feat: 优化编辑页结构
This commit is contained in:
parent
310fe0d325
commit
b494bd6174
@ -72,6 +72,8 @@ const updateLogicConf = () => {
|
|||||||
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
// 校验 - 白名单
|
// 校验 - 白名单
|
||||||
|
@ -66,12 +66,6 @@ const handlePublish = async () => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if(updateWhiteConf()){
|
|
||||||
isPublishing.value = false
|
|
||||||
ElMessage.error('请检查问卷设置是否有误')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const saveRes: any = await saveSurvey(saveData)
|
const saveRes: any = await saveSurvey(saveData)
|
||||||
if (saveRes.code !== 200) {
|
if (saveRes.code !== 200) {
|
||||||
|
@ -32,7 +32,6 @@ interface Props {
|
|||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const props = defineProps<Props>()
|
const props = defineProps<Props>()
|
||||||
|
|
||||||
const isSaving = ref<boolean>(false)
|
const isSaving = ref<boolean>(false)
|
||||||
const isShowAutoSave = ref<boolean>(false)
|
const isShowAutoSave = ref<boolean>(false)
|
||||||
const autoSaveStatus = ref<'succeed' | 'saving' | 'failed'>('succeed')
|
const autoSaveStatus = ref<'succeed' | 'saving' | 'failed'>('succeed')
|
||||||
@ -127,7 +126,6 @@ const handleSave = async () => {
|
|||||||
const { checked, msg } = validate()
|
const { checked, msg } = validate()
|
||||||
if (!checked) {
|
if (!checked) {
|
||||||
isSaving.value = false
|
isSaving.value = false
|
||||||
ElMessage.error('请检查问卷设置是否有误')
|
|
||||||
ElMessage.error(msg)
|
ElMessage.error(msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,98 @@
|
|||||||
|
<template>
|
||||||
|
<div class="tab-box">
|
||||||
|
<div class="title">结果页状态选择</div>
|
||||||
|
<div class="status-list-wrapper">
|
||||||
|
<div
|
||||||
|
v-for="(status, index) in statusList"
|
||||||
|
:key="index"
|
||||||
|
class="status-item"
|
||||||
|
@click="handleChangePreview({ type: status.type })"
|
||||||
|
>
|
||||||
|
<span>{{ status.title }}</span>
|
||||||
|
<div class="preview-item">
|
||||||
|
<img :src="status.previewImg" :alt="status.title" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useStore } from 'vuex'
|
||||||
|
import { EDIT_STATUS_MAP } from './enum'
|
||||||
|
|
||||||
|
const store = useStore()
|
||||||
|
const statusList = [
|
||||||
|
{
|
||||||
|
type: EDIT_STATUS_MAP.SUCCESS,
|
||||||
|
title: '提交成功',
|
||||||
|
previewImg: '/imgs/icons/success.webp'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: EDIT_STATUS_MAP.OVERTIME,
|
||||||
|
title: '问卷过期',
|
||||||
|
previewImg: '/imgs/icons/overtime.webp'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const handleChangePreview = (data: any) => {
|
||||||
|
const currentStatus = store.state?.edit?.currentEditStatus
|
||||||
|
|
||||||
|
if (currentStatus && currentStatus !== data.type) {
|
||||||
|
store.commit('edit/changeStatusPreview', data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.tab-box {
|
||||||
|
width: 300px;
|
||||||
|
height: 100%;
|
||||||
|
box-shadow: none;
|
||||||
|
border: none;
|
||||||
|
overflow-y: auto;
|
||||||
|
background-color: #fff;
|
||||||
|
.title {
|
||||||
|
height: 40px;
|
||||||
|
line-height: 40px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: $primary-color;
|
||||||
|
padding-left: 20px;
|
||||||
|
// background: #f9fafc;
|
||||||
|
border-bottom: 1px solid #edeffc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.status-list-wrapper {
|
||||||
|
padding: 19px 18px 100px 19px;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
|
||||||
|
label.title {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-item {
|
||||||
|
position: relative;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
|
||||||
|
span {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 17px;
|
||||||
|
color: $font-color-stress;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
.preview-item {
|
||||||
|
padding: 40px 80px;
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
&:hover {
|
||||||
|
-webkit-filter: brightness(90%);
|
||||||
|
filter: brightness(90%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,62 @@
|
|||||||
|
<template>
|
||||||
|
<div class="result-config-preview">
|
||||||
|
<div class="result-page-wrap">
|
||||||
|
<div class="result-page">
|
||||||
|
<component
|
||||||
|
:is="components[currentEditStatus]"
|
||||||
|
:key="currentEditStatus"
|
||||||
|
:module-config="moduleConfig"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue'
|
||||||
|
import { useStore } from 'vuex'
|
||||||
|
import { get as _get } from 'lodash-es'
|
||||||
|
|
||||||
|
import SuccessContent from './components/SuccessContent.vue'
|
||||||
|
import OverTime from './components/OverTime.vue'
|
||||||
|
import { EDIT_STATUS_MAP } from './enum'
|
||||||
|
|
||||||
|
const components = {
|
||||||
|
[EDIT_STATUS_MAP.SUCCESS]: SuccessContent,
|
||||||
|
[EDIT_STATUS_MAP.OVERTIME]: OverTime
|
||||||
|
}
|
||||||
|
|
||||||
|
const store = useStore()
|
||||||
|
const currentEditStatus = computed(() => store.state?.edit?.currentEditStatus)
|
||||||
|
const moduleConfig = computed(() => {
|
||||||
|
return _get(store.state, 'edit.schema.submitConf')
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.result-config-preview {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
min-width: 500px;
|
||||||
|
padding-bottom: 80px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
background-color: #f6f7f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-page-wrap {
|
||||||
|
width: 90%;
|
||||||
|
margin-top: 50px;
|
||||||
|
min-height: 812px;
|
||||||
|
max-height: 812px;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
background-color: var(--primary-background-color);
|
||||||
|
padding: 0 0.3rem;
|
||||||
|
.result-page {
|
||||||
|
background: rgba(255, 255, 255, var(--opacity));
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,120 @@
|
|||||||
|
<template>
|
||||||
|
<div class="question-edit-form">
|
||||||
|
<div class="setter-title">
|
||||||
|
{{ currentEditText }}
|
||||||
|
</div>
|
||||||
|
<el-form class="question-config-form" label-position="top" @submit.prevent>
|
||||||
|
<template v-for="(item, index) in formFields" :key="index">
|
||||||
|
<FormItem
|
||||||
|
v-if="item.type && !item.hidden && Boolean(registerTypes[item.type])"
|
||||||
|
:form-config="item"
|
||||||
|
:style="item.style"
|
||||||
|
>
|
||||||
|
<Component
|
||||||
|
v-if="Boolean(registerTypes[item.type])"
|
||||||
|
:is="components[item.type]"
|
||||||
|
:module-config="moduleConfig"
|
||||||
|
:form-config="item"
|
||||||
|
@form-change="handleFormChange"
|
||||||
|
/>
|
||||||
|
</FormItem>
|
||||||
|
</template>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, ref, shallowRef } from 'vue'
|
||||||
|
import { useStore } from 'vuex'
|
||||||
|
import { get as _get } from 'lodash-es'
|
||||||
|
|
||||||
|
import FormItem from '@/materials/setters/widgets/FormItem.vue'
|
||||||
|
import setterLoader from '@/materials/setters/setterLoader'
|
||||||
|
import statusConfig from '@/management/pages/edit/setterConfig/statusConfig'
|
||||||
|
|
||||||
|
const textMap = {
|
||||||
|
Success: '提交成功页面配置',
|
||||||
|
OverTime: '问卷过期页面配置'
|
||||||
|
}
|
||||||
|
|
||||||
|
const store = useStore()
|
||||||
|
|
||||||
|
const components = shallowRef<any>({})
|
||||||
|
const registerTypes = ref<any>({})
|
||||||
|
const moduleConfig = computed(() => _get(store.state, 'edit.schema.submitConf'))
|
||||||
|
const currentEditText = computed(() => (textMap as any)[store.state.edit.currentEditStatus])
|
||||||
|
const formFields = computed(() => {
|
||||||
|
const currentStatus = store.state.edit.currentEditStatus
|
||||||
|
const formList = (statusConfig as any)[currentStatus] || []
|
||||||
|
const list = formList.map((item: any) => {
|
||||||
|
const value = _get(moduleConfig.value, item.key, item.value)
|
||||||
|
|
||||||
|
return { ...item, value }
|
||||||
|
})
|
||||||
|
|
||||||
|
registerComponents(list)
|
||||||
|
|
||||||
|
return list
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleFormChange = ({ key, value }: any) => {
|
||||||
|
store.dispatch('edit/changeSchema', {
|
||||||
|
key: `submitConf.${key}`,
|
||||||
|
value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const registerComponents = async (formFieldData: any) => {
|
||||||
|
const setters = formFieldData.map((item: any) => item.type)
|
||||||
|
const settersSet = new Set(setters)
|
||||||
|
const settersArr = Array.from(settersSet)
|
||||||
|
const allSetters = settersArr.map((item) => {
|
||||||
|
return {
|
||||||
|
type: item,
|
||||||
|
path: item
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
try {
|
||||||
|
const comps = await setterLoader.loadComponents(allSetters)
|
||||||
|
|
||||||
|
for (const comp of comps) {
|
||||||
|
if (!comp) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const { type, component, err } = comp
|
||||||
|
|
||||||
|
if (!err) {
|
||||||
|
const componentName = component.name
|
||||||
|
|
||||||
|
components.value[type] = component
|
||||||
|
registerTypes.value[type] = componentName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.question-edit-form {
|
||||||
|
width: 360px;
|
||||||
|
height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setter-title {
|
||||||
|
height: 40px;
|
||||||
|
line-height: 40px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: $primary-color;
|
||||||
|
padding-left: 20px;
|
||||||
|
// background: #f9fafc;
|
||||||
|
border-bottom: 1px solid #edeffc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.question-config-form {
|
||||||
|
padding: 30px 20px 50px 20px;
|
||||||
|
}
|
||||||
|
</style>
|
34
web/src/management/pages/edit/modules/resultModule/components/OverTime.vue
Executable file
34
web/src/management/pages/edit/modules/resultModule/components/OverTime.vue
Executable file
@ -0,0 +1,34 @@
|
|||||||
|
<template>
|
||||||
|
<div class="over-time">
|
||||||
|
<img class="over-img" src="/imgs/icons/overtime.webp" />
|
||||||
|
<p class="title-msg" v-safe-html="resultText"></p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
moduleConfig: any
|
||||||
|
}
|
||||||
|
const props = defineProps<Props>()
|
||||||
|
const resultText = computed(() => props.moduleConfig?.msgContent?.msg_9001 || '问卷已过期')
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.over-time {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 5.5rem;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.title-msg {
|
||||||
|
width: 100%;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.over-time .over-img {
|
||||||
|
margin-top: 1.6rem;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,56 @@
|
|||||||
|
<template>
|
||||||
|
<div class="suc-page">
|
||||||
|
<div class="suc-content">
|
||||||
|
<div class="title-box">
|
||||||
|
<img src="/imgs/icons/success.webp" class="success-img" />
|
||||||
|
<div class="title-msg" v-safe-html="successText"></div>
|
||||||
|
</div>
|
||||||
|
<div class="bottom-btn"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
moduleConfig: any
|
||||||
|
}
|
||||||
|
const props = defineProps<Props>()
|
||||||
|
const successText = computed(() => props.moduleConfig?.msgContent?.msg_200 || '')
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
/*成功页面跳转全屏展示浮层*/
|
||||||
|
.suc-page {
|
||||||
|
padding: 0;
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
display: inline-block;
|
||||||
|
height: 100%;
|
||||||
|
.success-img {
|
||||||
|
margin-top: -0.2rem;
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.suc-content {
|
||||||
|
max-width: 920px;
|
||||||
|
margin: 0 auto;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
padding-top: 1.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-msg {
|
||||||
|
margin-top: 0.4rem;
|
||||||
|
margin-bottom: 0.4rem;
|
||||||
|
font-size: 0.36rem;
|
||||||
|
color: #666;
|
||||||
|
:deep(*) {
|
||||||
|
font-size: 0.36rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.bottom-btn {
|
||||||
|
height: 300px;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,4 @@
|
|||||||
|
export const EDIT_STATUS_MAP = {
|
||||||
|
SUCCESS: 'Success',
|
||||||
|
OVERTIME: 'OverTime'
|
||||||
|
}
|
@ -0,0 +1,101 @@
|
|||||||
|
<template>
|
||||||
|
<div class="team-member-wrap">
|
||||||
|
<div class="team-tree-wrap">
|
||||||
|
<el-tree
|
||||||
|
ref="treeRef"
|
||||||
|
:default-expanded-keys="defaultCheckedKeys"
|
||||||
|
:default-checked-keys="defaultCheckedKeys"
|
||||||
|
:data="treeData"
|
||||||
|
empty-text="暂无数据"
|
||||||
|
@check="handleChange"
|
||||||
|
style="height: 201px"
|
||||||
|
highlight-current
|
||||||
|
show-checkbox
|
||||||
|
node-key="id"
|
||||||
|
:props="defaultProps"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="member-count">
|
||||||
|
已选择 <span>{{ selectCount }}</span> 人
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed, defineProps, defineEmits, onMounted } from 'vue'
|
||||||
|
import { FORM_CHANGE_EVENT_KEY } from '@/materials/setters/constant'
|
||||||
|
import { getMemberList } from '@/management/api/space'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
formConfig: Object
|
||||||
|
})
|
||||||
|
const emit = defineEmits([FORM_CHANGE_EVENT_KEY])
|
||||||
|
|
||||||
|
const treeRef = ref(null)
|
||||||
|
const treeData = ref([])
|
||||||
|
const defaultCheckedKeys = ref([])
|
||||||
|
const defaultProps = {
|
||||||
|
children: 'children',
|
||||||
|
label: 'label'
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleChange = () => {
|
||||||
|
const key = props.formConfig.key
|
||||||
|
const userKeys = treeRef.value?.getCheckedKeys(true)
|
||||||
|
if (userKeys.length > 100) {
|
||||||
|
ElMessage.error('最多添加100个')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
emit(FORM_CHANGE_EVENT_KEY, { key: key, value: userKeys })
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectCount = computed(() => {
|
||||||
|
return treeRef.value?.getCheckedKeys(true).length || 0
|
||||||
|
})
|
||||||
|
|
||||||
|
const getSpaceMenus = async () => {
|
||||||
|
const res = await getMemberList()
|
||||||
|
if (res.code != 200) {
|
||||||
|
ElMessage.error('获取空间成员列表失败')
|
||||||
|
}
|
||||||
|
const data = res.data
|
||||||
|
data.map((v) => {
|
||||||
|
const members = v.members || []
|
||||||
|
treeData.value.push({
|
||||||
|
id: v.ownerId,
|
||||||
|
label: v.name,
|
||||||
|
children: members?.map((v) => ({
|
||||||
|
id: v.userId,
|
||||||
|
label: v.role
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
defaultCheckedKeys.value = props.formConfig.value
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getSpaceMenus()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.team-member-wrap {
|
||||||
|
width: 508px;
|
||||||
|
|
||||||
|
.team-tree-wrap {
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid rgba(227, 228, 232, 1);
|
||||||
|
border-radius: 2px;
|
||||||
|
min-height: 204px;
|
||||||
|
max-height: 204px;
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-count {
|
||||||
|
text-align: right;
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: $primary-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,155 @@
|
|||||||
|
<template>
|
||||||
|
<div class="white-list-wrap">
|
||||||
|
<el-button class="create-btn" type="primary" @click="whiteVisible = true"> 添加 </el-button>
|
||||||
|
<el-button v-if="whitelist.length > 0" class="create-btn" color="#4A4C5B" @click="delAllList">
|
||||||
|
全部删除
|
||||||
|
</el-button>
|
||||||
|
<el-table
|
||||||
|
class="table-wrap"
|
||||||
|
empty-text="暂无数据"
|
||||||
|
:data="whitelist"
|
||||||
|
height="240"
|
||||||
|
style="width: 426px"
|
||||||
|
>
|
||||||
|
<el-table-column label="名单" width="350">
|
||||||
|
<template #default="scope">
|
||||||
|
<div>{{ whitelist[scope.$index] }}</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="操作" width="74">
|
||||||
|
<template #default="scope">
|
||||||
|
<div @click="delRowItem(scope.$index)" class="flex cursor">
|
||||||
|
<i-ep-delete :size="16" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<el-dialog v-model="whiteVisible" title="添加白名单" width="600" @closed="handleClose">
|
||||||
|
<div>
|
||||||
|
<el-form-item label-position="top" label="类型选择" label-width="auto">
|
||||||
|
<el-radio-group v-model="memberType" @change="handleTypeChange">
|
||||||
|
<el-radio value="MOBILE">手机号</el-radio>
|
||||||
|
<el-radio value="EMAIL">邮箱</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label-position="top" class="flex-column" label="名单录入" label-width="auto">
|
||||||
|
<el-input
|
||||||
|
v-model="whiteTextarea"
|
||||||
|
placeholder="多个用逗号(半角)“,”隔开"
|
||||||
|
rows="7"
|
||||||
|
resize="none"
|
||||||
|
type="textarea"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button @click="whiteVisible = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="handleChange"> 确定 </el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { ref, nextTick } from 'vue'
|
||||||
|
import { FORM_CHANGE_EVENT_KEY } from '@/materials/setters/constant'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { regexpMap } from '@/common/regexpMap.ts'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
formConfig: Object
|
||||||
|
})
|
||||||
|
const emit = defineEmits([FORM_CHANGE_EVENT_KEY])
|
||||||
|
|
||||||
|
const whitelist = ref(props.formConfig.value[0] || [])
|
||||||
|
const memberType = ref(props.formConfig.value[1] || 'MOBILE')
|
||||||
|
const whiteVisible = ref(false)
|
||||||
|
const whiteTextarea = ref(whitelist.value.join(','))
|
||||||
|
|
||||||
|
const regularMap = {
|
||||||
|
MOBILE: regexpMap.m,
|
||||||
|
EMAIL: regexpMap.e
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkValRule = (list) => {
|
||||||
|
let status = false
|
||||||
|
if (list.length > 100) {
|
||||||
|
ElMessage.error('最多添加100个')
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
const pattern = regularMap[memberType.value]
|
||||||
|
if (!pattern) return false
|
||||||
|
|
||||||
|
for (let i = 0; i < list.length; i++) {
|
||||||
|
if (!pattern.test(list[i])) {
|
||||||
|
status = true
|
||||||
|
ElMessage.error('格式错误,请检查后重新输入~')
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return status
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleTypeChange = () => {
|
||||||
|
whiteTextarea.value = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleChange = () => {
|
||||||
|
const keys = props.formConfig.keys
|
||||||
|
const list = whiteTextarea.value ? whiteTextarea.value.split(',') : []
|
||||||
|
if (checkValRule(list)) return
|
||||||
|
|
||||||
|
emit(FORM_CHANGE_EVENT_KEY, { key: keys[0], value: list })
|
||||||
|
emit(FORM_CHANGE_EVENT_KEY, { key: keys[1], value: memberType.value })
|
||||||
|
whiteVisible.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
nextTick(() => {
|
||||||
|
whitelist.value = props.formConfig.value[0] || []
|
||||||
|
whiteTextarea.value = whitelist.value.join(',')
|
||||||
|
memberType.value = props.formConfig.value[1] || 'MOBILE'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const delRowItem = (index) => {
|
||||||
|
whitelist.value.splice(index, 1)
|
||||||
|
whiteTextarea.value = whitelist.value.join(',')
|
||||||
|
const keys = props.formConfig.keys
|
||||||
|
emit(FORM_CHANGE_EVENT_KEY, { key: keys[0], value: whitelist.value })
|
||||||
|
}
|
||||||
|
|
||||||
|
const delAllList = () => {
|
||||||
|
whitelist.value = []
|
||||||
|
whiteTextarea.value = ''
|
||||||
|
handleChange()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.white-list-wrap {
|
||||||
|
.flex-column {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
:deep(th) {
|
||||||
|
padding: 4px 0;
|
||||||
|
background: #f6f7f9;
|
||||||
|
}
|
||||||
|
:deep(td) {
|
||||||
|
padding: 6px 0;
|
||||||
|
}
|
||||||
|
.table-wrap {
|
||||||
|
margin-top: 16px;
|
||||||
|
border: 1px solid #ebeef5;
|
||||||
|
border-radius: 2px;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
.cursor {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.flex {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -92,10 +92,6 @@ const changePreset = (banner: any) => {
|
|||||||
border: none;
|
border: none;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
scrollbar-width: none;
|
|
||||||
&::-webkit-scrollbar {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.title {
|
.title {
|
||||||
height: 40px;
|
height: 40px;
|
||||||
line-height: 40px;
|
line-height: 40px;
|
||||||
@ -112,9 +108,8 @@ const changePreset = (banner: any) => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
.tag {
|
.tag {
|
||||||
|
margin: 5px 8px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
width: 51px;
|
|
||||||
margin: 5px 2px;
|
|
||||||
&.current {
|
&.current {
|
||||||
color: $primary-color;
|
color: $primary-color;
|
||||||
background-color: $primary-bg-color;
|
background-color: $primary-bg-color;
|
@ -13,12 +13,12 @@
|
|||||||
:readonly="false"
|
:readonly="false"
|
||||||
:is-selected="currentEditOne === 'submit'"
|
:is-selected="currentEditOne === 'submit'"
|
||||||
/>
|
/>
|
||||||
|
<LogoIcon
|
||||||
|
:logo-conf="bottomConf"
|
||||||
|
:readonly="false"
|
||||||
|
:is-selected="currentEditOne === 'logo'"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<LogoIcon
|
|
||||||
:logo-conf="bottomConf"
|
|
||||||
:readonly="false"
|
|
||||||
:is-selected="currentEditOne === 'logo'"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
@ -0,0 +1,85 @@
|
|||||||
|
<template>
|
||||||
|
<div class="setter-wrapper">
|
||||||
|
<div class="setter-title">样式设置</div>
|
||||||
|
<div class="setter-content">
|
||||||
|
<el-collapse v-model="collapse">
|
||||||
|
<el-collapse-item
|
||||||
|
v-for="(collapse, index) in skinConfig"
|
||||||
|
:key="index"
|
||||||
|
:title="collapse.name"
|
||||||
|
:name="collapse.key"
|
||||||
|
>
|
||||||
|
<SetterField
|
||||||
|
:form-config-list="collapse.formConfigList"
|
||||||
|
:module-config="_get(schema, collapse.key, {})"
|
||||||
|
@form-change="
|
||||||
|
(key) => {
|
||||||
|
handleFormChange(key, collapse.key)
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</el-collapse-item>
|
||||||
|
</el-collapse>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, ref } from 'vue'
|
||||||
|
import { useStore } from 'vuex'
|
||||||
|
import { get as _get } from 'lodash-es'
|
||||||
|
|
||||||
|
import skinConfig from '@/management/pages/edit/setterConfig/skinConfig'
|
||||||
|
import SetterField from '@/management/pages/edit/components/SetterField.vue'
|
||||||
|
|
||||||
|
const store = useStore()
|
||||||
|
const collapse = ref<string>('')
|
||||||
|
const schema = computed(() => _get(store.state, 'edit.schema'))
|
||||||
|
|
||||||
|
const handleFormChange = (data: any, collapse: string) => {
|
||||||
|
const { key, value } = data
|
||||||
|
const currentEditKey = `${collapse}`
|
||||||
|
const resultKey = `${currentEditKey}.${key}`
|
||||||
|
|
||||||
|
store.dispatch('edit/changeSchema', { key: resultKey, value })
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.setter-wrapper {
|
||||||
|
width: 360px;
|
||||||
|
height: 100%;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setter-title {
|
||||||
|
height: 40px;
|
||||||
|
line-height: 40px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: $primary-color;
|
||||||
|
padding-left: 20px;
|
||||||
|
// background: #f9fafc;
|
||||||
|
border-bottom: 1px solid #edeffc;
|
||||||
|
}
|
||||||
|
.setter-content {
|
||||||
|
padding: 10px 20px;
|
||||||
|
.el-collapse {
|
||||||
|
border: none;
|
||||||
|
:deep(.el-collapse-item__header) {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
font-weight: bold;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
:deep(.el-collapse-item__wrap) {
|
||||||
|
border: none;
|
||||||
|
.el-collapse-item__content {
|
||||||
|
padding-bottom: 0px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.config-form {
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
35
web/src/management/pages/edit/setterConfig/bannerConfig.js
Normal file
35
web/src/management/pages/edit/setterConfig/bannerConfig.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
export default [
|
||||||
|
{
|
||||||
|
label: '顶部图片地址',
|
||||||
|
type: 'InputSetter',
|
||||||
|
key: 'bgImage',
|
||||||
|
labelStyle: { width: '120px' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '顶部视频地址',
|
||||||
|
type: 'InputSetter',
|
||||||
|
key: 'videoLink',
|
||||||
|
labelStyle: { width: '120px' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '视频海报地址',
|
||||||
|
type: 'InputSetter',
|
||||||
|
key: 'postImg',
|
||||||
|
labelStyle: { width: '120px' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '图片支持点击',
|
||||||
|
type: 'CustomedSwitch',
|
||||||
|
labelStyle: { width: '120px' },
|
||||||
|
key: 'bgImageAllowJump'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '跳转链接',
|
||||||
|
type: 'InputSetter',
|
||||||
|
labelStyle: { width: '120px' },
|
||||||
|
key: 'bgImageJumpLink',
|
||||||
|
relyFunc: (data) => {
|
||||||
|
return !!data?.bgImageAllowJump
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
@ -8,10 +8,11 @@ export default [
|
|||||||
title: '提交限制',
|
title: '提交限制',
|
||||||
key: 'limitConfig',
|
key: 'limitConfig',
|
||||||
formList: ['limit_tLimit']
|
formList: ['limit_tLimit']
|
||||||
},
|
}, {
|
||||||
{
|
|
||||||
title: '作答限制',
|
title: '作答限制',
|
||||||
key: 'respondConfig',
|
key: 'respondConfig',
|
||||||
formList: ['interview_pwd','answer_type','white_placeholder','white_list','team_list']
|
formList: ['interview_pwd','answer_type','white_placeholder','white_list','team_list']
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -27,36 +27,51 @@ export default {
|
|||||||
label: '访问密码',
|
label: '访问密码',
|
||||||
type: 'SwitchInput',
|
type: 'SwitchInput',
|
||||||
placeholder: '请输入6位字符串类型访问密码 ',
|
placeholder: '请输入6位字符串类型访问密码 ',
|
||||||
maxLength: 6,
|
maxLength: 6
|
||||||
},
|
},
|
||||||
answer_type: {
|
answer_type: {
|
||||||
key: 'baseConf.whitelistType',
|
key: 'baseConf.whitelistType',
|
||||||
label: '答题名单',
|
label: '答题名单',
|
||||||
type: 'AnswerRadio',
|
type: 'RadioGroup',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: '所有人',
|
||||||
|
value: 'ALL'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '空间成员',
|
||||||
|
value: 'MEMBER'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '白名单',
|
||||||
|
value: 'CUSTOM'
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
white_placeholder:{
|
white_placeholder: {
|
||||||
key: 'baseConf.whitelistTip',
|
key: 'baseConf.whitelistTip',
|
||||||
label: '名单登录提示语',
|
label: '名单登录提示语',
|
||||||
placeholder:'请输入名单提示语',
|
placeholder: '请输入名单提示语',
|
||||||
type: 'InputWordLimit',
|
type: 'InputWordLimit',
|
||||||
maxLength: 40,
|
maxLength: 40,
|
||||||
relyFunc: (data) => {
|
relyFunc: (data) => {
|
||||||
return ['CUSTOM','MEMBER'].includes(data.whitelistType)
|
return ['CUSTOM', 'MEMBER'].includes(data.whitelistType)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
white_list:{
|
white_list: {
|
||||||
keys: ['baseConf.whitelist','baseConf.memberType'],
|
keys: ['baseConf.whitelist', 'baseConf.memberType'],
|
||||||
label: '白名单列表',
|
label: '白名单列表',
|
||||||
type: 'whiteList',
|
type: 'WhiteList',
|
||||||
|
custom: true, // 自定义导入高级组件
|
||||||
relyFunc: (data) => {
|
relyFunc: (data) => {
|
||||||
|
|
||||||
return data.whitelistType == 'CUSTOM'
|
return data.whitelistType == 'CUSTOM'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
team_list:{
|
team_list: {
|
||||||
key: 'baseConf.whitelist',
|
key: 'baseConf.whitelist',
|
||||||
label: '团队空间成员选择',
|
label: '团队空间成员选择',
|
||||||
type: 'teamMemberList',
|
type: 'TeamMemberList',
|
||||||
|
custom: true, // 自定义导入高级组件
|
||||||
relyFunc: (data) => {
|
relyFunc: (data) => {
|
||||||
return data.whitelistType == 'MEMBER'
|
return data.whitelistType == 'MEMBER'
|
||||||
}
|
}
|
16
web/src/management/pages/edit/setterConfig/logoConfig.js
Normal file
16
web/src/management/pages/edit/setterConfig/logoConfig.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
export default [
|
||||||
|
{
|
||||||
|
label: '自定义Logo',
|
||||||
|
type: 'InputSetter',
|
||||||
|
key: 'logoImage',
|
||||||
|
tip: '默认尺寸200px*50px',
|
||||||
|
labelStyle: { width: '120px' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Logo大小',
|
||||||
|
type: 'InputPercent',
|
||||||
|
key: 'logoImageWidth',
|
||||||
|
tip: '填写宽度百分比,例如30%',
|
||||||
|
labelStyle: { width: '120px' }
|
||||||
|
}
|
||||||
|
]
|
48
web/src/management/pages/edit/setterConfig/skinConfig.js
Normal file
48
web/src/management/pages/edit/setterConfig/skinConfig.js
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import bannerConfig from './bannerConfig'
|
||||||
|
import logoConfig from './logoConfig'
|
||||||
|
|
||||||
|
export default [
|
||||||
|
{
|
||||||
|
name: '头图',
|
||||||
|
key: 'bannerConf.bannerConfig',
|
||||||
|
formConfigList: bannerConfig
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '背景',
|
||||||
|
key: 'skinConf.backgroundConf',
|
||||||
|
formConfigList: [
|
||||||
|
{
|
||||||
|
label: '背景颜色',
|
||||||
|
type: 'ColorPicker',
|
||||||
|
key: 'color'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '主题色',
|
||||||
|
key: 'skinConf.themeConf',
|
||||||
|
formConfigList: [
|
||||||
|
{
|
||||||
|
label: '全局应用',
|
||||||
|
type: 'ColorPicker',
|
||||||
|
key: 'color'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'skinConf.contentConf',
|
||||||
|
name: '内容区域',
|
||||||
|
formConfigList: [
|
||||||
|
{
|
||||||
|
label: '内容透明度',
|
||||||
|
type: 'SliderSetter',
|
||||||
|
key: 'opacity'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '品牌logo',
|
||||||
|
key: 'bottomConf',
|
||||||
|
formConfigList: logoConfig
|
||||||
|
}
|
||||||
|
]
|
26
web/src/management/pages/edit/setterConfig/statusConfig.js
Normal file
26
web/src/management/pages/edit/setterConfig/statusConfig.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
export default {
|
||||||
|
Success: [
|
||||||
|
{
|
||||||
|
label: '提示文案',
|
||||||
|
type: 'RichText',
|
||||||
|
key: 'msgContent.msg_200',
|
||||||
|
placeholder: '提交成功',
|
||||||
|
value: '提交成功',
|
||||||
|
labelStyle: {
|
||||||
|
'font-weight': 'bold'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
OverTime: [
|
||||||
|
{
|
||||||
|
label: '提示文案',
|
||||||
|
type: 'RichText',
|
||||||
|
key: 'msgContent.msg_9001',
|
||||||
|
placeholder: '问卷已过期',
|
||||||
|
value: '问卷已过期',
|
||||||
|
labelStyle: {
|
||||||
|
'font-weight': 'bold'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
62
web/src/management/pages/edit/setterConfig/submitConfig.js
Normal file
62
web/src/management/pages/edit/setterConfig/submitConfig.js
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
export default [
|
||||||
|
{
|
||||||
|
title: '提交按钮文案',
|
||||||
|
type: 'InputSetter',
|
||||||
|
key: 'submitTitle',
|
||||||
|
placeholder: '提交',
|
||||||
|
value: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '提交确认弹窗',
|
||||||
|
type: 'Customed',
|
||||||
|
key: 'confirmAgain',
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
label: '是否配置该项',
|
||||||
|
labelStyle: { width: '120px' },
|
||||||
|
type: 'CustomedSwitch',
|
||||||
|
key: 'confirmAgain.is_again',
|
||||||
|
value: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '二次确认文案',
|
||||||
|
labelStyle: { width: '120px' },
|
||||||
|
type: 'InputSetter',
|
||||||
|
key: 'confirmAgain.again_text',
|
||||||
|
placeholder: '确认要提交吗?',
|
||||||
|
value: '确认要提交吗?'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '提交文案配置',
|
||||||
|
type: 'Customed',
|
||||||
|
key: 'msgContent',
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
label: '已提交',
|
||||||
|
labelStyle: { width: '120px' },
|
||||||
|
type: 'InputSetter',
|
||||||
|
key: 'msgContent.msg_9002',
|
||||||
|
placeholder: '请勿多次提交!',
|
||||||
|
value: '请勿多次提交!'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '提交结束',
|
||||||
|
labelStyle: { width: '120px' },
|
||||||
|
type: 'InputSetter',
|
||||||
|
key: 'msgContent.msg_9003',
|
||||||
|
placeholder: '您来晚了,已经满额!',
|
||||||
|
value: '您来晚了,已经满额!'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '其他提交失败',
|
||||||
|
labelStyle: { width: '120px' },
|
||||||
|
type: 'InputSetter',
|
||||||
|
key: 'msgContent.msg_9004',
|
||||||
|
placeholder: '提交失败!',
|
||||||
|
value: '提交失败!'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
@ -1,4 +1,4 @@
|
|||||||
import submitFormConfig from '@/management/config/setterConfig/submitConfig'
|
import submitFormConfig from '@/management/pages/edit/setterConfig/submitConfig'
|
||||||
import questionLoader from '@/materials/questions/questionLoader'
|
import questionLoader from '@/materials/questions/questionLoader'
|
||||||
|
|
||||||
const innerMetaConfig = {
|
const innerMetaConfig = {
|
||||||
|
Loading…
Reference in New Issue
Block a user