refactor: 重构 management/pages/edit 目录下组件, 使用 Vue3 组合式 API 写法 (#251)

This commit is contained in:
alwayrun 2024-06-04 21:01:26 +08:00 committed by sudoooooo
parent d9255db8a9
commit cffe037269
28 changed files with 806 additions and 1020 deletions

View File

@ -14,22 +14,21 @@
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { useStore } from 'vuex'
import { get as _get } from 'lodash-es'
import BackPanel from '../modules/generalModule/BackPanel.vue'
import TitlePanel from '../modules/generalModule/TitlePanel.vue'
import NavPanel from '../modules/generalModule/NavPanel.vue'
import HistoryPanel from '../modules/contentModule/HistoryPanel.vue'
import SavePanel from '../modules/contentModule/SavePanel.vue'
import PublishPanel from '../modules/contentModule/PublishPanel.vue'
import { useStore } from 'vuex'
import { get as _get } from 'lodash-es'
import { computed } from 'vue'
const store = useStore()
const title = computed(() => _get(store.state, 'edit.schema.metaData.title'))
</script>
<style lang="scss" scoped>
.nav {
width: 100%;

View File

@ -16,28 +16,28 @@
:form-config="content"
>
<Component
:is="content.type"
:is="components[content.type]"
:form-config="content"
:module-config="moduleConfig"
@form-change="onFormChange($event, content)"
@form-change="handleFormChange($event, content)"
:class="content.contentClass"
/>
</FormItem>
</template>
<FormItem v-else :form-config="item">
<Component
:is="item.type"
:is="components[item.type]"
:form-config="item"
:module-config="moduleConfig"
@form-change="onFormChange($event, item)"
@form-change="handleFormChange($event, item)"
:class="item.contentClass"
/>
</FormItem>
</div>
</el-form>
</template>
<script>
<script setup lang="ts">
import { watch, ref, shallowRef } from 'vue'
import { get as _get, pick as _pick, isFunction as _isFunction } from 'lodash-es'
import FormItem from '@/materials/setters/widgets/FormItem.vue'
@ -45,8 +45,20 @@ import setterLoader from '@/materials/setters/setterLoader'
import { FORM_CHANGE_EVENT_KEY } from '@/materials/setters/constant'
interface Props {
formConfigList: Array<any>
moduleConfig: any
}
interface Emit {
(ev: typeof FORM_CHANGE_EVENT_KEY, arg: { key: string; value: any }): void
}
const props = defineProps<Props>()
const emit = defineEmits<Emit>()
//
const formatValue = ({ item, moduleConfig }) => {
const formatValue = ({ item, moduleConfig }: any) => {
if (_isFunction(item.valueAdapter)) {
const value = item.valueAdapter({ moduleConfig })
@ -65,89 +77,64 @@ const formatValue = ({ item, moduleConfig }) => {
}
}
export default {
name: 'SettersField',
props: {
formConfigList: Array, // meta.js
moduleConfig: Object
},
data() {
return {
register: {},
formFieldData: [],
init: true
}
},
components: {
FormItem
},
watch: {
formConfigList: {
deep: true,
immediate: true,
async handler(newVal) {
this.init = true
if (!newVal || !newVal.length) {
return
}
const formFieldData = ref<Array<any>>([])
const init = ref<boolean>(true)
const components = shallowRef<any>({})
//
await this.handleComponentRegister(newVal)
const handleFormChange = (data: any, formConfig: any) => {
if (_isFunction(formConfig?.setterAdapter)) {
const resultData = formConfig.setterAdapter(data)
this.init = false
this.formFieldData = this.setValues(this.formConfigList)
if (Array.isArray(resultData)) {
resultData.forEach((item) => {
emit(FORM_CHANGE_EVENT_KEY, item)
})
} else {
emit(FORM_CHANGE_EVENT_KEY, resultData)
}
},
// schema
moduleConfig: {
deep: true,
async handler() {
// value
if (this.init) {
return
} else {
emit(FORM_CHANGE_EVENT_KEY, data)
}
}
// TODO: schema
this.formFieldData = this.setValues(this.formConfigList)
}
}
},
methods: {
setValues(configList = []) {
const normalizationValues = (configList: Array<any> = []) => {
return configList
.filter((item) => {
.filter((item: any) => {
//
if (item.type === 'Customed') {
item.content = this.setValues(item.content)
item.content = normalizationValues(item.content)
return true
}
if (!item.type) {
return false
}
if (item.hidden) {
return false
}
//
if (_isFunction(item.relyFunc)) {
return item.relyFunc(this.moduleConfig)
return item.relyFunc(props.moduleConfig)
}
return true
})
.map((item) => {
.map((item: any) => {
return {
...item,
value: formatValue({ item, moduleConfig: this.moduleConfig }) //
value: formatValue({ item, moduleConfig: props.moduleConfig }) //
}
})
},
async handleComponentRegister(formFieldData) {
let innerSetters = []
const setters = formFieldData.map((item) => {
}
const registerComponents = async (formFieldData: any) => {
let innerSetters: Array<any> = []
const setters = formFieldData.map((item: any) => {
if (item.type === 'Customed') {
innerSetters.push(...(item.content || []).map((content) => content.type))
innerSetters.push(...(item.content || []).map((content: any) => content.type))
}
return item.type
@ -155,51 +142,65 @@ export default {
const settersSet = new Set([...setters, ...innerSetters])
const settersArr = Array.from(settersSet)
const allSetters = settersArr.map((item) => {
return {
const allSetters = settersArr.map((item) => ({
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
if (!this.$options.components) {
this.$options.components = {}
}
this.$options.components[componentName] = component
this.register[type] = componentName
components.value[type] = component
}
}
} catch (err) {
console.error(err)
}
},
onFormChange(data, formConfig) {
if (_isFunction(formConfig?.setterAdapter)) {
const resultData = formConfig.setterAdapter(data)
if (Array.isArray(resultData)) {
resultData.forEach((item) => {
this.$emit(FORM_CHANGE_EVENT_KEY, item)
})
} else {
this.$emit(FORM_CHANGE_EVENT_KEY, resultData)
}
} else {
this.$emit(FORM_CHANGE_EVENT_KEY, data)
}
}
}
}
</script>
watch(
() => props.formConfigList,
async (newVal: Array<any>) => {
init.value = true
if (!newVal || !newVal.length) {
return
}
await registerComponents(newVal)
init.value = false
formFieldData.value = normalizationValues(newVal)
},
{
deep: true,
immediate: true
}
)
watch(
() => props.moduleConfig,
() => {
// value
if (init.value) {
return
}
// TODO: schema
formFieldData.value = normalizationValues(props.formConfigList)
},
{
deep: true
}
)
</script>
<style lang="scss" scoped>
.config-form {
padding: 15px 0;

View File

@ -13,42 +13,38 @@
</div>
</div>
</template>
<script>
<script setup lang="ts">
import { onMounted } from 'vue'
import { useStore } from 'vuex'
import { useRouter, useRoute } from 'vue-router'
import { ElMessage } from 'element-plus'
import 'element-plus/theme-chalk/src/message.scss'
import LeftMenu from '@/management/components/LeftMenu.vue'
import CommonTemplate from './components/CommonTemplate.vue'
import Navbar from './components/ModuleNavbar.vue'
import { initShowLogicEngine } from '@/management/hooks/useShowLogicEngine'
export default {
name: 'questionEditPage',
components: {
CommonTemplate,
Navbar,
LeftMenu
},
async created() {
this.$store.commit('edit/setSurveyId', this.$route.params.id)
const store = useStore()
const router = useRouter()
const route = useRoute()
onMounted(async () => {
store.commit('edit/setSurveyId', route.params.id)
try {
await this.$store.dispatch('edit/init')
// await this.$store.dispatch('logic/initShowLogic', this.$store.state.edit.schema.logicConf.showLogicConf || {})
await initShowLogicEngine(this.$store.state.edit.schema.logicConf.showLogicConf || {})
} catch (error) {
ElMessage.error(error.message)
//
await store.dispatch('edit/init')
await initShowLogicEngine(store.state.edit.schema.logicConf.showLogicConf || {})
} catch (err: any) {
ElMessage.error(err.message)
setTimeout(() => {
this.$router.replace({
name: 'survey'
})
router.replace({ name: 'survey' })
}, 1000)
}
}
}
})
</script>
<style lang="scss" scoped>
.edit-index {
height: 100%;

View File

@ -1,6 +1,6 @@
<template>
<el-popover placement="top" trigger="click" @show="onShow" :width="320">
<el-tabs v-model="currentTab" class="custom-tab" v-if="visible" v-loading="paneLoading">
<el-popover placement="top" trigger="click" @show="handlePopoverShow" :width="320">
<el-tabs v-model="currentTab" class="custom-tab" v-if="visible" v-loading="loading">
<el-tab-pane label="修改历史" name="daily" class="custom-tab-pane">
<div class="line" v-for="(his, index) in dailyList" :key="index">
<span class="operator">{{ his.operator }}</span>
@ -24,100 +24,77 @@
</template>
</el-popover>
</template>
<script>
import { getSurveyHistory } from '@/management/api/survey'
<script setup lang="ts">
import { ref, computed, watch } from 'vue'
import { useStore } from 'vuex'
import { get as _get } from 'lodash-es'
import moment from 'moment'
//
import 'moment/locale/zh-cn'
//
moment.locale('zh-cn')
import { mapState } from 'vuex'
import { get as _get } from 'lodash-es'
import { getSurveyHistory } from '@/management/api/survey'
const getItemData = (item) => ({
const getItemData = (item: any) => ({
operator: item?.operator?.username || '未知用户',
time: moment(item.createDate).format('YYYY-MM-DD HH:mm:ss')
})
export default {
name: 'HistoryPanel',
computed: {
...mapState({
surveyId: (state) => _get(state, 'edit.surveyId')
}),
dailyList() {
return this.dailyHis.map(getItemData)
},
publishList() {
return this.publishHis.map(getItemData)
}
},
data() {
return {
dailyHis: [],
publishHis: [],
currentTab: 'daily',
visible: false,
paneLoading: false
}
},
watch: {
visible: {
async handler(newVal) {
if (this.visible && newVal) {
this.fetchHis()
}
}
},
currentTab: {
immediate: true,
async handler(newVal) {
if (this.visible && newVal) {
this.fetchHis()
}
}
}
},
methods: {
onShow() {
this.visible = true
},
fetchHis() {
this.paneLoading = true
switch (this.currentTab) {
case 'daily':
getSurveyHistory({
surveyId: this.surveyId,
historyType: 'dailyHis'
})
.then((dailyHis) => {
this.dailyHis = dailyHis.data || []
})
.finally(() => {
this.paneLoading = false
})
break
const dailyList = ref<Array<any>>([])
const publishList = ref<Array<any>>([])
const currentTab = ref<'daily' | 'publish'>('daily')
const visible = ref<boolean>(false)
case 'publish':
const store = useStore()
const queryHistories = async () => {
if (dirtyMonitor.value) {
loading.value = true
dirtyMonitor.value = false
const surveyId = _get(store.state, 'edit.surveyId')
const [dHis, pHis] = await Promise.all([
getSurveyHistory({
surveyId: this.surveyId,
surveyId,
historyType: 'dailyHis'
}),
getSurveyHistory({
surveyId,
historyType: 'publishHis'
})
.then((publishHis) => {
this.publishHis = publishHis.data || []
]).finally(() => {
loading.value = false
})
.finally(() => {
this.paneLoading = false
})
break
if ((dHis.data || []).length !== dailyList.value.length) {
dailyList.value = (dHis.data || []).map(getItemData)
}
if ((pHis.data || []).length !== publishList.value.length) {
publishList.value = (pHis.data || []).map(getItemData)
}
}
}
</script>
const handlePopoverShow = async () => {
visible.value = true
queryHistories()
}
const loading = ref<boolean>(false)
const dirtyMonitor = ref<boolean>(true)
const schemaUpdateTime = computed(() => _get(store.state, 'edit.schemaUpdateTime'))
watch(
schemaUpdateTime,
() => {
if (!dirtyMonitor.value) {
dirtyMonitor.value = true
}
},
{
immediate: true
}
)
</script>
<style lang="scss" scoped>
@import url('@/management/styles/edit-btn.scss');

View File

@ -1,80 +1,81 @@
<template>
<el-button type="primary" :loading="isPublishing" class="publish-btn" @click="onPublish">
<el-button type="primary" :loading="isPublishing" class="publish-btn" @click="handlePublish">
发布
</el-button>
</template>
<script>
import { get as _get } from 'lodash-es'
import { mapState } from 'vuex'
<script setup lang="ts">
import { ref } from 'vue'
import { useStore } from 'vuex'
import { useRouter } from 'vue-router'
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'
export default {
name: 'PublishPanel',
data() {
return {
isPublishing: false
}
},
computed: {
...mapState({
surveyId: (state) => _get(state, 'edit.surveyId')
})
},
methods: {
async onPublish() {
try {
this.updateLogicConf()
} catch (error) {
ElMessage.error('请检查逻辑配置是否有误')
return
}
const saveData = buildData(this.$store.state.edit.schema)
if (!saveData.surveyId) {
ElMessage.error('未获取到问卷id')
return
}
if (this.isPublishing) {
return
}
const isPublishing = ref<boolean>(false)
const store = useStore()
const router = useRouter()
try {
this.isPublishing = true
const saveRes = await saveSurvey(saveData)
if (saveRes.code !== 200) {
ElMessage.error(saveRes.errmsg || '问卷保存失败')
return
}
const publishRes = await publishSurvey({ surveyId: this.surveyId })
if (publishRes.code === 200) {
ElMessage.success('发布成功')
this.$store.dispatch('edit/getSchemaFromRemote')
this.$router.push({ name: 'publish' })
} else {
ElMessage.error(`发布失败 ${publishRes.errmsg}`)
}
} catch (error) {
ElMessage.error(`发布失败`)
} finally {
this.isPublishing = false
}
},
updateLogicConf() {
if (showLogicEngine.value) {
const updateLogicConf = () => {
if (
showLogicEngine.value &&
showLogicEngine.value.rules &&
showLogicEngine.value.rules.length !== 0
) {
showLogicEngine.value.validateSchema()
const showLogicConf = showLogicEngine.value.toJson()
//
this.$store.dispatch('edit/changeSchema', { key: 'logicConf', value: { showLogicConf } })
store.dispatch('edit/changeSchema', { key: 'logicConf', value: { showLogicConf } })
}
}
const handlePublish = async () => {
if (isPublishing.value) {
return
}
isPublishing.value = true
try {
updateLogicConf()
} catch (err) {
isPublishing.value = false
ElMessage.error('请检查逻辑配置是否有误')
return
}
const saveData = buildData(store.state.edit.schema)
if (!saveData.surveyId) {
isPublishing.value = false
ElMessage.error('未获取到问卷id')
return
}
try {
const saveRes: any = await saveSurvey(saveData)
if (saveRes.code !== 200) {
isPublishing.value = false
ElMessage.error(saveRes.errmsg || '问卷保存失败')
return
}
const publishRes: any = await publishSurvey({ surveyId: saveData.surveyId })
if (publishRes.code === 200) {
ElMessage.success('发布成功')
store.dispatch('edit/getSchemaFromRemote')
router.push({ name: 'publish' })
} else {
ElMessage.error(`发布失败 ${publishRes.errmsg}`)
}
} catch (err) {
ElMessage.error(`发布失败`)
} finally {
isPublishing.value = false
}
}
</script>
<style lang="scss" scoped>
.publish-btn {
width: 100px;

View File

@ -1,5 +1,5 @@
<template>
<div class="btn" @click="onSave" v-loading="isSaving">
<div class="btn" @click="handleSave" v-loading="isSaving">
<i class="iconfont icon-baocun"></i>
<span class="btn-txt">保存</span>
<transition name="fade">
@ -13,115 +13,109 @@
</transition>
</div>
</template>
<script>
import { mapState } from 'vuex'
<script setup lang="ts">
import { ref, computed, nextTick, watch } from 'vue'
import { useStore } from 'vuex'
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 buildData from './buildData'
import { showLogicEngine } from '@/management/hooks/useShowLogicEngine'
import buildData from './buildData'
export default {
components: {},
name: 'SavePanel',
data() {
return {
isSaving: false,
isShowAutoSave: false,
autoSaveStatus: 'succeed'
}
},
computed: {
...mapState({
schemaUpdateTime: (state) => _get(state, 'edit.schemaUpdateTime')
}),
saveText() {
const statusMap = {
const isSaving = ref<boolean>(false)
const isShowAutoSave = ref<boolean>(false)
const autoSaveStatus = ref<'succeed' | 'saving' | 'failed'>('succeed')
const saveText = computed(
() =>
({
saving: '保存中',
succeed: '保存成功',
failed: '保存失败'
}
return statusMap[this.autoSaveStatus]
}
},
watch: {
schemaUpdateTime() {
this.triggerAutoSave()
}
},
methods: {
triggerAutoSave() {
if (this.autoSaveStatus === 'saving') {
//
setTimeout(() => {
this.triggerAutoSave()
}, 1000)
} else {
if (this.timer) {
clearTimeout(this.timer)
}
this.timer = setTimeout(() => {
this.autoSaveStatus = 'saving'
this.isShowAutoSave = true
this.$nextTick(() => {
this.saveData()
.then((res) => {
if (res.code === 200) {
this.autoSaveStatus = 'succeed'
} else {
this.autoSaveStatus = 'failed'
}
setTimeout(() => {
this.isShowAutoSave = false
this.timer = null
}, 300)
})
.catch(() => {
this.timer = null
this.autoSaveStatus = 'failed'
this.isShowAutoSave = true
})
})
}, 2000)
}
},
updateLogicConf() {
if (showLogicEngine.value) {
showLogicEngine.value.validateSchema()
const showLogicConf = showLogicEngine.value.toJson()
//
this.$store.dispatch('edit/changeSchema', { key: 'logicConf', value: { showLogicConf } })
}
},
async saveData() {
const saveData = buildData(this.$store.state.edit.schema)
})[autoSaveStatus.value]
)
const store = useStore()
const saveData = async () => {
const saveData = buildData(store.state.edit.schema)
if (!saveData.surveyId) {
ElMessage.error('未获取到问卷id')
return null
}
const res = await saveSurvey(saveData)
return res
},
async onSave() {
if (this.isSaving) {
}
const updateLogicConf = () => {
if (
showLogicEngine.value &&
showLogicEngine.value.rules &&
showLogicEngine.value.rules.length !== 0
) {
showLogicEngine.value.validateSchema()
const showLogicConf = showLogicEngine.value.toJson()
//
store.dispatch('edit/changeSchema', { key: 'logicConf', value: { showLogicConf } })
}
}
const timerHandle = ref<NodeJS.Timeout | number | null>(null)
const triggerAutoSave = () => {
if (autoSaveStatus.value === 'saving') {
setTimeout(() => triggerAutoSave(), 1000)
} else {
if (timerHandle.value) {
clearTimeout(timerHandle.value)
timerHandle.value = null
}
timerHandle.value = setTimeout(() => {
autoSaveStatus.value = 'saving'
isShowAutoSave.value = true
nextTick(async () => {
try {
const res: any = await saveData()
if (res.code === 200) {
autoSaveStatus.value = 'succeed'
} else {
autoSaveStatus.value = 'failed'
}
setTimeout(() => {
isShowAutoSave.value = false
timerHandle.value = null
}, 300)
} catch (err) {
autoSaveStatus.value = 'failed'
isShowAutoSave.value = true
}
})
}, 2000)
}
}
const handleSave = async () => {
if (isSaving.value) {
return
}
this.isShowAutoSave = false
isSaving.value = true
isShowAutoSave.value = false
try {
this.updateLogicConf()
updateLogicConf()
} catch (error) {
// console.error(error)
isSaving.value = false
ElMessage.error('请检查逻辑配置是否有误')
return
}
try {
this.isSaving = true
const res = await this.saveData()
const res: any = await saveData()
if (res.code === 200) {
ElMessage.success('保存成功')
} else {
@ -130,13 +124,15 @@ export default {
} catch (error) {
ElMessage.error('保存问卷失败')
} finally {
this.isSaving = false
}
}
isSaving.value = false
}
}
</script>
const schemaUpdateTime = computed(() => _get(store.state, 'edit.schemaUpdateTime'))
watch(schemaUpdateTime, () => {
triggerAutoSave()
})
</script>
<style lang="scss" scoped>
@import url('@/management/styles/edit-btn.scss');

View File

@ -1,16 +1,12 @@
<template>
<div class="back-btn" @click="onBack">
<div class="back-btn" @click="handleNavigateHome">
<i class="iconfont icon-fanhui"></i>
<span>返回</span>
</div>
</template>
<script setup lang="ts">
const onBack = () => {
window.open('/survey', '_self')
}
const handleNavigateHome = () => window.open('/survey', '_self')
</script>
<style lang="scss" scoped>
.back-btn {
height: 100%;

View File

@ -1,8 +1,8 @@
<template>
<div class="content">
<template v-for="btnItem in btnList" :key="btnItem.key">
<template v-for="route in routes" :key="route.key">
<router-link
:to="{ name: btnItem.router }"
:to="{ name: route.router }"
replace
v-slot="{ href, navigate, isActive, isExactActive }"
custom
@ -10,25 +10,22 @@
<div
:class="[
'navbar-btn',
(isActive && ['skinsettings', 'edit'].includes(btnItem.key)) || isExactActive
(isActive && ['skinsettings', 'edit'].includes(route.key)) || isExactActive
? 'router-link-exact-active'
: ''
]"
>
<i class="iconfont" :class="[btnItem.icon]"></i>
<i class="iconfont" :class="[route.icon]"></i>
<a :href="href" @click="navigate"
><span>{{ btnItem.text }}</span></a
><span>{{ route.text }}</span></a
>
</div>
</router-link>
</template>
</div>
</template>
<script setup lang="ts">
import { reactive } from 'vue'
const btnList = reactive([
const routes = [
{
icon: 'icon-wenjuanbianji',
text: '问卷编辑',
@ -50,9 +47,8 @@ const btnList = reactive([
key: 'skinsettings',
next: true
}
])
]
</script>
<style lang="scss" scoped>
.content {
display: flex;

View File

@ -46,7 +46,6 @@ const hideFullTitle = () => {
tooltipVisible.value = false
}
</script>
<style lang="scss" scoped>
.title-container {
position: relative;

View File

@ -8,26 +8,14 @@
</el-tab-pane>
</el-tabs>
</template>
<script setup lang="ts">
import { ref } from 'vue'
<script>
import TypeList from './components/TypeList.vue'
import QuestionCatalog from './components/QuestionCatalog.vue'
export default {
name: 'CatalogPanel',
data() {
return {
tabSelected: '0'
}
},
components: {
TypeList,
QuestionCatalog
},
methods: {}
}
const tabSelected = ref<string>('0')
</script>
<style lang="scss" scoped>
.tab-box {
width: 300px;

View File

@ -11,47 +11,31 @@
class="question-config-form"
:form-config-list="formConfigList"
:module-config="moduleConfig"
@form-change="onFormChange"
@form-change="handleFormChange"
/>
</template>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { useStore } from 'vuex'
<script>
import SetterField from '@/management/pages/edit/components/SetterField.vue'
import { mapGetters } from 'vuex'
export default {
name: 'SetterPanel',
data() {
return {
tabSelected: '0'
}
},
computed: {
currentEditOne() {
return this.$store.state?.edit?.currentEditOne
},
...mapGetters({
formConfigList: 'edit/formConfigList',
moduleConfig: 'edit/moduleConfig',
currentEditKey: 'edit/currentEditKey',
currentEditMeta: 'edit/currentEditMeta'
})
},
components: {
SetterField
},
methods: {
onFormChange(data) {
const store = useStore()
const currentEditOne = computed(() => store.state?.edit?.currentEditOne)
const formConfigList = computed(() => store.getters['edit/formConfigList'])
const moduleConfig = computed(() => store.getters['edit/moduleConfig'])
const currentEditKey = computed(() => store.getters['edit/currentEditKey'])
const currentEditMeta = computed(() => store.getters['edit/currentEditMeta'])
const handleFormChange = (data: any) => {
const { key, value } = data
const resultKey = `${this.currentEditKey}.${key}`
this.$store.dispatch('edit/changeSchema', { key: resultKey, value })
}
}
const resultKey = `${currentEditKey.value}.${key}`
store.dispatch('edit/changeSchema', { key: resultKey, value })
}
</script>
<style lang="scss" scoped>
.setter-wrapper {
width: 360px;

View File

@ -1,5 +1,5 @@
<template>
<div class="question-catalog-item" @click="onSelect()">
<div class="question-catalog-item" @click="handleSelect()">
<div class="iconfont icon-tuodong draggHandle"></div>
<div class="catalog-item-body">
<div class="catalog-item-index" v-if="showIndex">{{ indexNumber }}.</div>
@ -7,37 +7,29 @@
</div>
</div>
</template>
<script setup lang="ts">
interface Props {
title: string
indexNumber: string | number
showIndex: boolean
}
<script>
export default {
name: 'CatalogItem',
data() {
return {}
},
computed: {},
props: {
title: {
type: String,
default: ''
},
indexNumber: {
type: [String, Number],
default: ''
},
showIndex: {
type: Boolean,
default: false
}
},
components: {},
methods: {
onSelect() {
this.$emit('select')
}
}
interface Emit {
(ev: 'select'): void
}
withDefaults(defineProps<Props>(), {
title: '',
indexNumber: '',
showIndex: false
})
const emit = defineEmits<Emit>()
const handleSelect = () => {
emit('select')
}
</script>
<style lang="scss" scoped>
.question-catalog-item {
position: relative;

View File

@ -2,7 +2,7 @@
<div class="question-catalog-wrapper">
<draggable
:list="renderData"
@end="onDragEnd"
@end="handleDragEnd"
itemKey="field"
handle=".draggHandle"
host-class="catalog-item-ghost"
@ -12,50 +12,43 @@
:title="element.title"
:indexNumber="element.indexNumber"
:showIndex="element.showIndex"
@select="onSelect(index)"
@select="handleSelect(index)"
/>
</template>
</draggable>
</div>
</template>
<script>
<script setup lang="ts">
import { computed } from 'vue'
import { useStore } from 'vuex'
import draggable from 'vuedraggable'
import CatalogItem from './CatalogItem.vue'
import { filterQuestionPreviewData } from '@/management/utils/index'
export default {
name: 'QuestionCatalog',
data() {
return {}
},
computed: {
questionDataList() {
return this.$store.state.edit.schema.questionDataList
},
renderData() {
return filterQuestionPreviewData(this.questionDataList) || []
const store = useStore()
const renderData = computed(() => {
const questions = store.state.edit.schema.questionDataList
return filterQuestionPreviewData(questions) || []
})
const handleDragEnd = ({ newIndex, oldIndex }: any) => {
const currentActivityKey = store.state.edit.currentEditOne
if (currentActivityKey === oldIndex) {
handleSelect(newIndex)
}
},
components: {
draggable,
CatalogItem
},
methods: {
onDragEnd(data) {
const { newIndex, oldIndex } = data
this.$store.dispatch('edit/moveQuestion', {
store.dispatch('edit/moveQuestion', {
index: oldIndex,
range: newIndex - oldIndex
})
},
onSelect(index) {
this.$store.commit('edit/setCurrentEditOne', index)
}
}
}
const handleSelect = (idx: number) => {
store.commit('edit/setCurrentEditOne', idx)
}
</script>
<style lang="scss" scoped>
.question-catalog-wrapper {
padding-bottom: 400px; //

View File

@ -2,7 +2,7 @@
<div class="question-config">
<div class="question-config-wrapper">
<div class="question-config-main">
<div v-for="form of renderData" :key="form.key" class="config-item">
<div v-for="form of setterList" :key="form.key" class="config-item">
<div class="config-title">
<span>
{{ form.title }}
@ -16,17 +16,17 @@
>
<template v-for="(item, index) in form.formList">
<FormItem
v-if="item.type && !item.hidden && Boolean(register[item.type])"
v-if="item.type && !item.hidden && Boolean(registerTypes[item.type])"
:key="index"
:form-config="item"
:style="item.style"
>
<Component
v-if="Boolean(register[item.type])"
:is="item.type"
v-if="Boolean(registerTypes[item.type])"
:is="components[item.type]"
:module-config="form.dataConfig"
:form-config="item"
@form-change="onFormChange"
@form-change="handleFormChange"
/>
</FormItem>
</template>
@ -36,92 +36,83 @@
</div>
</div>
</template>
<script setup lang="ts">
import { computed, ref, onMounted, shallowRef } from 'vue'
import { useStore } from 'vuex'
import { cloneDeep as _cloneDeep, isArray as _isArray, get as _get } from 'lodash-es'
<script>
import baseConfig from './config/baseConfig'
import baseFormConfig from './config/baseFormConfig'
import FormItem from '@/materials/setters/widgets/FormItem.vue'
import setterLoader from '@/materials/setters/setterLoader'
import { cloneDeep as _cloneDeep, isArray as _isArray, get as _get } from 'lodash-es'
export default {
name: 'SettingPanel',
components: {
FormItem
},
data() {
return {
formConfigList: [],
register: {}
}
},
methods: {
onFormChange(data) {
this.$store.dispatch('edit/changeSchema', {
key: data.key,
value: data.value
})
}
},
computed: {
allSetters() {
const formList = this.formConfigList.map((item) => item.formList).flat()
const typeList = formList.map((item) => ({
type: item.type,
path: item.path || item.type
}))
const formConfigList = ref<Array<any>>([])
const components = shallowRef<any>({})
const registerTypes = ref<any>({})
const setterList = computed(() => {
const list = _cloneDeep(formConfigList.value)
return typeList
},
renderData() {
// todo: 1formConfigvalue2dataConfig
const formConfigList = _cloneDeep(this.formConfigList)
return list.map((form) => {
const dataConfig: any = {}
return formConfigList.map((form) => {
const dataConfig = {}
for (const formItem of form.formList) {
const formKey = formItem.key ? formItem.key : formItem.keys
let formValue
if (_isArray(formKey)) {
formValue = []
for (const key of formKey) {
const val = _get(this.$store.state.edit.schema, key, formItem.value)
const val = _get(store.state.edit.schema, key, formItem.value)
formValue.push(val)
dataConfig[key] = val
}
} else {
formValue = _get(this.$store.state.edit.schema, formKey, formItem.value)
formValue = _get(store.state.edit.schema, formKey, formItem.value)
dataConfig[formKey] = formValue
}
formItem.value = formValue
}
form.dataConfig = dataConfig
return form
})
}
},
async created() {
this.formConfigList = baseConfig.map((item) => {
return {
...item,
formList: item.formList.map((key) => baseFormConfig[key]).filter((config) => !!config)
}
})
})
const comps = await setterLoader.loadComponents(this.allSetters)
const store = useStore()
const handleFormChange = (data: any) => {
store.dispatch('edit/changeSchema', {
key: data.key,
value: data.value
})
}
onMounted(async () => {
formConfigList.value = baseConfig.map((item) => ({
...item,
formList: item.formList.map((key) => (baseFormConfig as any)[key]).filter((config) => !!config)
}))
const formList = formConfigList.value.map((item) => item.formList).flat()
const typeList = formList.map((item) => ({
type: item.type,
path: item.path || item.type
}))
const comps = await setterLoader.loadComponents(typeList)
for (const comp of comps) {
if (!comp) {
continue
}
const { type, component, err } = comp
if (!err) {
const componentName = component.name
this.$options.components[componentName] = component
this.register[type] = componentName
components.value[type] = component
registerTypes.value[type] = componentName
}
}
}
}
})
</script>
<style lang="scss" scoped>

View File

@ -4,24 +4,15 @@
<p class="title-msg" v-safe-html="resultText"></p>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
<script>
export default {
name: 'OverTime',
props: {
moduleConfig: {
type: Object,
required: true
}
},
computed: {
resultText() {
return this.moduleConfig?.submitConf?.msgContent?.msg_9001 || '问卷已过期'
}
}
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;

View File

@ -9,24 +9,15 @@
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
<script>
export default {
name: 'SuccessContent',
props: {
moduleConfig: {
type: Object,
required: true
}
},
computed: {
successText() {
return this.moduleConfig?.submitConf?.msgContent?.msg_200 || ''
}
}
interface Props {
moduleConfig: any
}
const props = defineProps<Props>()
const successText = computed(() => props.moduleConfig?.msgContent?.msg_200 || '')
</script>
<style lang="scss" scoped>
/*成功页面跳转全屏展示浮层*/
.suc-page {

View File

@ -6,7 +6,7 @@
v-for="(status, index) in statusList"
:key="index"
class="status-item"
@click="filterDisabledStatus({ type: status.type })"
@click="handleChangePreview({ type: status.type })"
>
<span>{{ status.title }}</span>
<div class="preview-item">
@ -16,16 +16,12 @@
</div>
</div>
</template>
<script>
import { mapMutations } from 'vuex'
<script setup lang="ts">
import { useStore } from 'vuex'
import { EDIT_STATUS_MAP } from '../enum'
export default {
name: 'CatalogPanel',
data() {
return {
statusList: [
const store = useStore()
const statusList = [
{
type: EDIT_STATUS_MAP.SUCCESS,
title: '提交成功',
@ -36,21 +32,16 @@ export default {
title: '问卷过期',
previewImg: '/imgs/icons/overtime.webp'
}
]
}
},
computed: {},
methods: {
...mapMutations({
changeStatusPreview: 'edit/changeStatusPreview'
}),
filterDisabledStatus(data) {
this.changeStatusPreview(data)
}
]
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;

View File

@ -2,43 +2,35 @@
<div class="result-config-preview">
<div class="result-page-wrap">
<div class="result-page">
<component :is="currentEditStatus" :key="currentEditStatus" :module-config="moduleConfig" />
<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'
<script>
import { mapState } from 'vuex'
import SuccessContent from '../components/SuccessContent.vue'
import OverTime from '../components/OverTime.vue'
import { EDIT_STATUS_MAP } from '../enum'
import { get as _get } from 'lodash-es'
export default {
name: 'PreviewPanel',
props: {},
data() {
return {}
},
computed: {
...mapState({
currentEditStatus: (state) => state.edit.currentEditStatus,
submitConf: (state) => _get(state, 'edit.schema.submitConf')
}),
moduleConfig() {
return {
submitConf: this.submitConf
}
}
},
components: {
const components = {
[EDIT_STATUS_MAP.SUCCESS]: SuccessContent,
[EDIT_STATUS_MAP.OVERTIME]: OverTime
}
}
</script>
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%;

View File

@ -4,82 +4,67 @@
{{ currentEditText }}
</div>
<el-form class="question-config-form" label-position="top" @submit.prevent>
<template v-for="(item, index) in formFieldData" :key="index">
<template v-for="(item, index) in formFields" :key="index">
<FormItem
v-if="item.type && !item.hidden && Boolean(register[item.type])"
v-if="item.type && !item.hidden && Boolean(registerTypes[item.type])"
:form-config="item"
:style="item.style"
>
<Component
v-if="Boolean(register[item.type])"
:is="item.type"
v-if="Boolean(registerTypes[item.type])"
:is="components[item.type]"
:module-config="moduleConfig"
:form-config="item"
@form-change="onFormChange"
@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'
<script>
import FormItem from '@/materials/setters/widgets/FormItem.vue'
import setterLoader from '@/materials/setters/setterLoader'
import statusConfig from '../config/statusConfig'
import { mapState } from 'vuex'
import { get as _get, pick as _pick } from 'lodash-es'
const textMap = {
Success: '提交成功页面配置',
OverTime: '问卷过期页面配置'
}
export default {
name: 'SetterPanel',
components: {
FormItem
},
data() {
return {
register: {}
}
},
computed: {
formFieldData() {
const formList = statusConfig[this.currentEditStatus] || []
return formList.map((item) => {
const value = _get(this.moduleConfig, item.key, item.value)
return {
...item,
value
}
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 }
})
},
currentEditText() {
return textMap[this.currentEditStatus] || ''
},
...mapState({
currentEditStatus: (state) => state.edit.currentEditStatus,
submitConf: (state) => _get(state, 'edit.schema.submitConf')
}),
moduleConfig() {
return this.submitConf
}
},
watch: {
formFieldData: {
immediate: true,
handler(newVal) {
if (Array.isArray(newVal)) {
this.handleComponentRegister(newVal)
}
}
}
},
methods: {
async handleComponentRegister(formFieldData) {
const setters = formFieldData.map((item) => item.type)
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) => {
@ -88,50 +73,29 @@ export default {
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
this.$options.components[componentName] = component
this.register[type] = componentName
components.value[type] = component
registerTypes.value[type] = componentName
}
}
} catch (err) {
console.error(err)
}
},
getValueFromModuleConfig(item) {
const { key, keys } = item
const moduleConfig = this.moduleConfig
let result = item
if (key) {
result = {
...item,
value: _get(moduleConfig, key, item.value)
}
}
if (keys) {
result = {
...item,
value: _pick(moduleConfig, keys)
}
}
return result
},
onFormChange(data) {
const { key, value } = data
const resultKey = `submitConf.${key}`
this.$store.dispatch('edit/changeSchema', { key: resultKey, value })
}
}
}
</script>
<style lang="scss" scoped>
.question-edit-form {
width: 360px;

View File

@ -8,7 +8,7 @@
:class="[groupName === item.value ? 'current' : '', 'tag']"
type="info"
:key="item.value"
@click="() => changeGroup(item.value)"
@click="() => handleChangeGroup(item.value)"
>
{{ item.label }}
</el-tag>
@ -25,75 +25,63 @@
</div>
</div>
</template>
<script>
import { mapActions } from 'vuex'
<script setup lang="ts">
import { computed, ref } from 'vue'
import { useStore } from 'vuex'
import skinPresets from '@/management/config/skinPresets.js'
export default {
name: 'CatalogPanel',
data() {
return {
skinPresets: [],
groupName: 'temp'
}
},
computed: {
bannerList() {
return this.$store?.state?.bannerList || []
},
groupList() {
return Object.keys(this.bannerList).map((key) => {
return {
label: this.bannerList[key].name,
const store = useStore()
const groupName = ref<string>('temp')
const bannerList = computed(() => store?.state?.bannerList || [])
const groupList = computed(() =>
Object.keys(bannerList.value).map((key) => ({
label: bannerList.value[key].name,
value: key
}
})
},
currentBannerList() {
const arr = Object.keys(this.bannerList)
}))
)
const currentBannerList = computed(() => {
const arr = Object.keys(bannerList.value)
.map((key) => {
return this.bannerList[key]
return bannerList.value[key]
})
.map((data) => {
return data.list.map((item) => {
return data.list.map((item: any) => {
item.group = data.key
return item
})
})
const allbanner = arr.reduce((acc, curr) => {
return acc.concat(curr)
}, [])
return allbanner.filter((item) => {
if (this.groupName === 'temp') {
return allbanner.filter((item: any) => {
if (groupName.value === 'temp') {
return true
} else {
return item.group === this.groupName
return item.group === groupName.value
}
})
}
},
mounted() {},
methods: {
...mapActions({
changeThemePreset: 'edit/changeThemePreset'
}),
changeGroup(value) {
this.groupName = value
},
changePreset(banner) {
})
const handleChangeGroup = (value: string) => {
groupName.value = value
}
const changePreset = (banner: any) => {
const name = banner.group + '-' + banner.title
let presets = {
'bannerConf.bannerConfig.bgImage': banner.src,
'skinConf.themeConf.color': '#FAA600',
'skinConf.backgroundConf.color': '#fff'
}
if (skinPresets[name]) {
presets = Object.assign(presets, skinPresets[name])
if ((skinPresets as any)[name]) {
presets = Object.assign(presets, (skinPresets as any)[name])
}
this.changeThemePreset(presets)
}
}
store.dispatch('edit/changeThemePreset', presets)
}
</script>
<style lang="scss" scoped>

View File

@ -14,7 +14,7 @@
:module-config="_get(schema, collapse.key, {})"
@form-change="
(key) => {
onFormChange(key, collapse.key)
handleFormChange(key, collapse.key)
}
"
/>
@ -23,37 +23,24 @@
</div>
</div>
</template>
<script>
<script setup lang="ts">
import { computed, ref } from 'vue'
import { useStore } from 'vuex'
import { get as _get } from 'lodash-es'
import skinConfig from '@/management/config/setterConfig/skinConfig'
import SetterField from '@/management/pages/edit/components/SetterField.vue'
import { mapState } from 'vuex'
import { get as _get } from 'lodash-es'
export default {
name: 'SetterPanel',
components: {
SetterField
},
data() {
return {
collapse: '',
skinConfig
}
},
computed: {
...mapState({
skinConf: (state) => _get(state, 'edit.schema.skinConf'),
schema: (state) => _get(state, 'edit.schema')
})
},
methods: {
_get,
onFormChange(data, collapse) {
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}`
this.$store.dispatch('edit/changeSchema', { key: resultKey, value })
}
}
store.dispatch('edit/changeSchema', { key: resultKey, value })
}
</script>
<style lang="scss" scoped>

View File

@ -5,15 +5,18 @@
</template>
<script setup lang="ts">
import { computed, provide } from 'vue'
import RulePanel from '../../modules/logicModule/RulePanel.vue'
import { filterQuestionPreviewData } from '@/management/utils/index'
import { useStore } from 'vuex'
import { cloneDeep } from 'lodash-es'
import RulePanel from '../../modules/logicModule/RulePanel.vue'
import { filterQuestionPreviewData } from '@/management/utils/index'
const store = useStore()
const questionDataList = computed(() => {
return store.state.edit.schema.questionDataList
})
const renderData = computed(() => {
return filterQuestionPreviewData(cloneDeep(questionDataList.value))
})

View File

@ -11,20 +11,11 @@
</template>
</CommonTemplate>
</template>
<script>
<script setup lang="ts">
import CommonTemplate from '../../components/CommonTemplate.vue'
import CatalogPanel from '../../modules/questionModule/CatalogPanel.vue'
import PreviewPanel from '../../modules/questionModule/PreviewPanel.vue'
import SetterPanel from '../../modules/questionModule/SetterPanel.vue'
export default {
name: 'editIndex',
components: {
CommonTemplate,
CatalogPanel,
PreviewPanel,
SetterPanel
}
}
</script>
<style lang="scss" scoped>
.navbar {

View File

@ -3,24 +3,21 @@
<div class="navbar-tab">
<el-radio-group v-model="activeRouter">
<el-radio-button
v-for="btnItem in btnList"
:key="btnItem.router"
:label="btnItem.text"
:value="btnItem.router"
v-for="item in routes"
:key="item.router"
:label="item.text"
:value="item.router"
/>
</el-radio-group>
</div>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'QuestionPage',
props: {},
data() {
return {
activeRouter: this.$route.name,
btnList: [
<script setup lang="ts">
import { watch, ref } from 'vue'
import { useRouter, useRoute } from 'vue-router'
const routes = [
{
text: '内容设置',
router: 'QuestionEditIndex',
@ -31,17 +28,21 @@ export default {
router: 'LogicIndex',
key: 'logicEdit'
}
]
}
]
const router = useRouter()
const route = useRoute()
const activeRouter = ref(route.name)
watch(
activeRouter,
(val: any) => {
router.push({ name: val })
},
watch: {
activeRouter: {
handler(val) {
this.$router.push({ name: val })
{
immediate: true
}
}
}
}
)
</script>
<style lang="scss" scoped>
.question-content {

View File

@ -3,17 +3,9 @@
<SettingPanel></SettingPanel>
</div>
</template>
<script>
<script setup lang="ts">
import SettingPanel from '../../modules/settingModule/SettingPanel.vue'
export default {
name: 'SettingPage',
components: {
SettingPanel
}
}
</script>
<style lang="scss" scoped>
.setting-page {
width: 100%;

View File

@ -11,24 +11,20 @@
</template>
</CommonTemplate>
</template>
<script>
<script setup lang="ts">
import { onMounted } from 'vue'
import { useStore } from 'vuex'
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'
export default {
name: 'ContentPage',
components: {
CommonTemplate,
CatalogPanel,
PreviewPanel,
SetterPanel
},
created() {
this.$store.dispatch('getBannerData')
}
}
const store = useStore()
onMounted(() => {
store.dispatch('getBannerData')
})
</script>
<style lang="scss" scoped>
.navbar {

View File

@ -11,20 +11,9 @@
</template>
</CommonTemplate>
</template>
<script>
<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'
export default {
name: 'ResultPage',
components: {
CommonTemplate,
ResultCatalog,
ResultPreview,
ResultSetter
}
}
</script>

View File

@ -3,24 +3,21 @@
<div class="navbar-tab">
<el-radio-group v-model="activeRouter">
<el-radio-button
v-for="btnItem in btnList"
:key="btnItem.router"
:label="btnItem.text"
:value="btnItem.router"
v-for="item in routes"
:key="item.router"
:label="item.text"
:value="item.router"
/>
</el-radio-group>
</div>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'skinPage',
props: {},
data() {
return {
activeRouter: this.$route.name,
btnList: [
<script setup lang="ts">
import { watch, ref } from 'vue'
import { useRouter, useRoute } from 'vue-router'
const routes = [
{
text: '内容页',
router: 'QuestionSkinSetting',
@ -32,17 +29,21 @@ export default {
router: 'QuestionEditResultConfig',
key: 'status'
}
]
}
]
const router = useRouter()
const route = useRoute()
const activeRouter = ref(route.name)
watch(
activeRouter,
(val: any) => {
router.push({ name: val })
},
watch: {
activeRouter: {
handler(val) {
this.$router.push({ name: val })
{
immediate: true
}
}
}
}
)
</script>
<style lang="scss" scoped>
.skin-content {