feat: 优化编辑页模块和配置结构

This commit is contained in:
sudoooooo 2024-07-22 17:33:59 +08:00
parent ee9a1ea9c7
commit 4ac07ef938
15 changed files with 150 additions and 397 deletions

View File

@ -8,7 +8,6 @@ export const replacePxWithRem = (html) => {
const imgRegex = /<img[^>]*style=["'][^"']*\b(?:width|height):\s*\d+(\.\d+)?px[^"']*["'][^>]*>/gi
const styleRegex = /style="([^"]*)"/g
if (!imgRegex.test(html)) {
console.log('无需修改')
return html
}

View File

@ -1,35 +0,0 @@
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
}
}
]

View File

@ -1,16 +0,0 @@
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' }
}
]

View File

@ -1,48 +0,0 @@
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
}
]

View File

@ -1,62 +0,0 @@
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: '提交失败!'
}
]
}
]

View File

@ -18,8 +18,11 @@
</CooperationPanel>
<PreviewPanel></PreviewPanel>
<HistoryPanel></HistoryPanel>
<SavePanel></SavePanel>
<PublishPanel></PublishPanel>
<SavePanel :updateLogicConf="updateLogicConf" :updateWhiteConf="updateWhiteConf"></SavePanel>
<PublishPanel
:updateLogicConf="updateLogicConf"
:updateWhiteConf="updateWhiteConf"
></PublishPanel>
</div>
</div>
</template>
@ -27,6 +30,8 @@
import { computed } from 'vue'
import { useEditStore } from '@/management/stores/edit'
import { showLogicEngine } from '@/management/hooks/useShowLogicEngine'
import BackPanel from '../modules/generalModule/BackPanel.vue'
import TitlePanel from '../modules/generalModule/TitlePanel.vue'
import NavPanel from '../modules/generalModule/NavPanel.vue'
@ -38,6 +43,59 @@ import CooperationPanel from '../modules/contentModule/CooperationPanel.vue'
const editStore = useEditStore()
const title = computed(() => (editStore.schema?.metaData as any)?.title || '')
// -
const updateLogicConf = () => {
let res = {
validated: true,
message: ''
}
if (
showLogicEngine.value &&
showLogicEngine.value.rules &&
showLogicEngine.value.rules.length !== 0
) {
try {
showLogicEngine.value.validateSchema()
} catch (error) {
res = {
validated: false,
message: '逻辑配置不能为空'
}
return res
}
const showLogicConf = showLogicEngine.value.toJson()
//
store.dispatch('edit/changeSchema', { key: 'logicConf', value: { showLogicConf } })
return res
}
}
// -
const updateWhiteConf = () => {
let res = {
validated: true,
message: ''
}
const baseConf = store.state.edit.schema.baseConf || {}
if (baseConf.passwordSwitch && !baseConf.password) {
res = {
validated: false,
message: '访问密码不能为空'
}
return res
}
if (baseConf.whitelistType != 'ALL' && !baseConf.whitelist?.length) {
res = {
validated: false,
message: '白名单不能为空'
}
return res
}
return res
}
</script>
<style lang="scss" scoped>
@import url('@/management/styles/edit-btn.scss');

View File

@ -11,36 +11,38 @@ import { ElMessage } from 'element-plus'
import 'element-plus/theme-chalk/src/message.scss'
import { publishSurvey, saveSurvey } from '@/management/api/survey'
import { showLogicEngine } from '@/management/hooks/useShowLogicEngine'
import buildData from './buildData'
interface Props {
updateLogicConf: any
updateWhiteConf: any
}
const props = defineProps<Props>()
const isPublishing = ref<boolean>(false)
const editStore = useEditStore()
const { schema, changeSchema, getSchemaFromRemote } = editStore
const { schema, getSchemaFromRemote } = editStore
const router = useRouter()
const updateLogicConf = () => {
if (
showLogicEngine.value &&
showLogicEngine.value.rules &&
showLogicEngine.value.rules.length !== 0
) {
showLogicEngine.value.validateSchema()
const showLogicConf = showLogicEngine.value.toJson()
//
changeSchema({ key: 'logicConf', value: { showLogicConf } })
const validate = () => {
let checked = true
let msg = ''
const { validated, message } = props.updateLogicConf()
if (!validated) {
checked = validated
msg = `检查页面"问卷编辑>显示逻辑"${message}`
}
const { validated: whiteValidated, message: whiteMsg } = props.updateWhiteConf()
if (!whiteValidated) {
checked = whiteValidated
msg = `检查页面"问卷设置>作答限制"${whiteMsg}`
}
}
const updateWhiteConf = () => {
const baseConf = store.state.edit.schema.baseConf || {};
if (baseConf.passwordSwitch && !baseConf.password) {
return true;
return {
checked,
msg
}
if (baseConf.whitelistType!='ALL' && !baseConf.whitelist?.length) {
return true;
}
return false
}
const handlePublish = async () => {
@ -50,11 +52,11 @@ const handlePublish = async () => {
isPublishing.value = true
try {
updateLogicConf()
} catch (err) {
//
const { checked, msg } = validate()
if (!checked) {
isPublishing.value = false
ElMessage.error('请检查逻辑配置是否有误')
ElMessage.error(msg)
return
}
@ -65,7 +67,7 @@ const handlePublish = async () => {
return
}
if(updateWhiteConf()){
if (updateWhiteConf()) {
isPublishing.value = false
ElMessage.error('请检查问卷设置是否有误')
return

View File

@ -17,13 +17,23 @@
import { ref, computed, nextTick, watch } from 'vue'
import { storeToRefs } from 'pinia'
import { useEditStore } from '@/management/stores/edit'
import { useRoute } from 'vue-router'
import { get as _get } from 'lodash-es'
import { ElMessage } from 'element-plus'
import 'element-plus/theme-chalk/src/message.scss'
import { saveSurvey } from '@/management/api/survey'
import { showLogicEngine } from '@/management/hooks/useShowLogicEngine'
import buildData from './buildData'
interface Props {
updateLogicConf: any
updateWhiteConf: any
}
const route = useRoute()
const props = defineProps<Props>()
const isSaving = ref<boolean>(false)
const isShowAutoSave = ref<boolean>(false)
const autoSaveStatus = ref<'succeed' | 'saving' | 'failed'>('succeed')
@ -40,6 +50,27 @@ const editStore = useEditStore()
const { schemaUpdateTime } = storeToRefs(editStore)
const { schema, changeSchema } = editStore
const validate = () => {
let checked = true
let msg = ''
if (route.path.includes('edit/logic')) {
const { validated, message } = props.updateLogicConf()
checked = validated
msg = message
}
if (route.path.includes('edit/setting')) {
const { validated, message } = props.updateWhiteConf()
checked = validated
msg = message
}
return {
checked,
msg
}
}
const saveData = async () => {
const saveData = buildData(schema)
@ -52,30 +83,6 @@ const saveData = async () => {
return res
}
const updateLogicConf = () => {
if (
showLogicEngine.value &&
showLogicEngine.value.rules &&
showLogicEngine.value.rules.length !== 0
) {
showLogicEngine.value.validateSchema()
const showLogicConf = showLogicEngine.value.toJson()
//
changeSchema({ key: 'logicConf', value: { showLogicConf } })
}
}
const updateWhiteConf = () => {
const baseConf = store.state.edit.schema.baseConf || {};
if (baseConf.passwordSwitch && !baseConf.password) {
return true;
}
if (baseConf.whitelistType!='ALL' && !baseConf.whitelist?.length) {
return true;
}
return false
}
const timerHandle = ref<NodeJS.Timeout | number | null>(null)
const triggerAutoSave = () => {
if (autoSaveStatus.value === 'saving') {
@ -119,17 +126,12 @@ const handleSave = async () => {
isSaving.value = true
isShowAutoSave.value = false
try {
updateLogicConf()
} catch (error) {
isSaving.value = false
ElMessage.error('请检查逻辑配置是否有误')
return
}
if(updateWhiteConf()){
//
const { checked, msg } = validate()
if (!checked) {
isSaving.value = false
ElMessage.error('请检查问卷设置是否有误')
ElMessage.error(msg)
return
}

View File

@ -47,16 +47,24 @@ import {
isFunction as _isFunction
} from 'lodash-es'
import baseConfig from './config/baseConfig'
import baseFormConfig from './config/baseFormConfig'
import baseConfig from '@/management/pages/edit/setterConfig/baseConfig'
import baseFormConfig from '@/management/pages/edit/setterConfig/baseFormConfig'
import FormItem from '@/materials/setters/widgets/FormItem.vue'
import setterLoader from '@/materials/setters/setterLoader'
import WhiteList from './components/WhiteList.vue'
import TeamMemberList from './components/TeamMemberList.vue'
const formConfigList = ref<Array<any>>([])
const components = shallowRef<any>({})
const registerTypes = ref<any>({})
const editStore = useEditStore()
const { schema, changeSchema } = editStore
const components = shallowRef<any>({
['WhiteList']: WhiteList,
['TeamMemberList']: TeamMemberList
})
//
const registerTypes = ref<any>({
WhiteList: 'WhiteList',
TeamMemberList: 'TeamMemberList'
})
const store = useStore()
const schemaBaseConf = computed(() => store.state.edit?.schema?.baseConf || {})
@ -110,7 +118,9 @@ onMounted(async () => {
}))
const formList = formConfigList.value.map((item) => item.formList).flat()
const typeList = formList.map((item) => ({
const typeList = formList
.filter((item) => !item.custom)
.map((item) => ({
type: item.type,
path: item.path || item.type
}))

View File

@ -1,34 +0,0 @@
<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>

View File

@ -1,56 +0,0 @@
<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>

View File

@ -1,26 +0,0 @@
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'
}
}
]
}

View File

@ -16,9 +16,9 @@ import { onMounted } from 'vue'
import { useEditStore } from '@/management/stores/edit'
import CommonTemplate from '../../components/CommonTemplate.vue'
import CatalogPanel from '../../modules/settingModule/skin/CatalogPanel.vue'
import PreviewPanel from '../../modules/settingModule/skin/PreviewPanel.vue'
import SetterPanel from '../../modules/settingModule/skin/SetterPanel.vue'
import CatalogPanel from '../../modules/skinModule/CatalogPanel.vue'
import PreviewPanel from '../../modules/skinModule/PreviewPanel.vue'
import SetterPanel from '../../modules/skinModule/SetterPanel.vue'
const editStore = useEditStore()

View File

@ -13,7 +13,7 @@
</template>
<script setup lang="ts">
import CommonTemplate from '../../components/CommonTemplate.vue'
import ResultCatalog from '../../modules/settingModule/result/CatalogPanel.vue'
import ResultPreview from '../../modules/settingModule/result/PreviewPanel.vue'
import ResultSetter from '../../modules/settingModule/result/SetterPanel.vue'
import ResultCatalog from '../../modules/resultModule/CatalogPanel.vue'
import ResultPreview from '../../modules/resultModule/PreviewPanel.vue'
import ResultSetter from '../../modules/resultModule/SetterPanel.vue'
</script>

View File

@ -1,41 +0,0 @@
<template>
<div class="answer-radio-wrap">
<el-radio-group v-model="whitelistType" @change="handleRadioGroupChange">
<el-radio value="ALL">所有人</el-radio>
<el-radio value="MEMBER">空间成员</el-radio>
<el-radio value="CUSTOM">白名单</el-radio>
</el-radio-group>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { FORM_CHANGE_EVENT_KEY } from '@/materials/setters/constant'
const props = defineProps({
formConfig: Object,
})
const emit = defineEmits([FORM_CHANGE_EVENT_KEY])
const whitelistType = ref(props.formConfig?.value || 'ALL')
const handleRadioGroupChange = (value) => {
const key = props.formConfig.key
emit(FORM_CHANGE_EVENT_KEY, { key, value })
emit(FORM_CHANGE_EVENT_KEY, { key:'baseConf.whitelist', value: [] })
emit(FORM_CHANGE_EVENT_KEY, { key: 'baseConf.memberType', value: 'MOBILE' })
if (whitelistType.value == 'ALL') {
emit(FORM_CHANGE_EVENT_KEY, { key:'baseConf.whitelistTip', value:'' })
}
}
</script>
<style lang="scss" scoped>
.switch-input-wrap{
width: 100%;
.mt16{
margin-top: 16px;
}
}
</style>