feat: 整卷增加基础配置:必填、显示类型、显示序号、显示分割线 (#391)
* feat: 增加整卷配置功能 * fix: 限制单题修改配置时只对基础配置进行更新全局基础配置操作 --------- Co-authored-by: jiangchunfu <jiangchunfu@kaike.la>
This commit is contained in:
parent
28591f00a3
commit
624308bae8
@ -1,37 +1,51 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="setter-wrapper">
|
<div class="setter-wrapper">
|
||||||
<div class="no-select-question" v-if="currentEditOne === null">
|
<div class="no-select-question" v-if="editStore.currentEditOne === null">
|
||||||
<img src="/imgs/icons/unselected.webp" />
|
<img src="/imgs/icons/unselected.webp" />
|
||||||
<h4 class="tipFont">选中题型可以编辑</h4>
|
<h4 class="tipFont">选中题型可以编辑</h4>
|
||||||
<span class="tip">来!试试看~</span>
|
<span class="tip">来!试试看~</span>
|
||||||
</div>
|
</div>
|
||||||
<template v-else>
|
<el-tabs v-else v-model="confType" type="border-card" stretch>
|
||||||
<div class="setter-title">{{ currentEditMeta?.title || '' }}</div>
|
<el-tab-pane name="baseConf" label="单题设置">
|
||||||
<SetterField
|
<div class="setter-title">{{ currentEditMeta?.title || '' }}</div>
|
||||||
class="question-config-form"
|
<SetterField
|
||||||
:form-config-list="formConfigList"
|
:form-config-list="formConfigList"
|
||||||
:module-config="moduleConfig"
|
:module-config="moduleConfig"
|
||||||
@form-change="handleFormChange"
|
@form-change="handleFormChange"
|
||||||
/>
|
/>
|
||||||
</template>
|
</el-tab-pane>
|
||||||
|
<el-tab-pane name="globalBaseConf" label="整卷设置">
|
||||||
|
<SetterField
|
||||||
|
:form-config-list="[basicConfig]"
|
||||||
|
:module-config="editStore.editGlobalBaseConf.globalBaseConfig"
|
||||||
|
@form-change="editStore.editGlobalBaseConf.updateGlobalConfOption"
|
||||||
|
/>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
|
import { ref } from 'vue'
|
||||||
import { useEditStore } from '@/management/stores/edit'
|
import { useEditStore } from '@/management/stores/edit'
|
||||||
|
import basicConfig from '@/materials/questions/common/config/basicConfig'
|
||||||
import SetterField from '@/management/pages/edit/components/SetterField.vue'
|
import SetterField from '@/management/pages/edit/components/SetterField.vue'
|
||||||
|
|
||||||
|
const confType = ref('baseConf')
|
||||||
const editStore = useEditStore()
|
const editStore = useEditStore()
|
||||||
const { currentEditOne, currentEditKey, currentEditMeta, formConfigList, moduleConfig } =
|
|
||||||
storeToRefs(editStore)
|
const { currentEditKey, currentEditMeta, formConfigList, moduleConfig } = storeToRefs(editStore)
|
||||||
const { changeSchema } = editStore
|
const { changeSchema } = editStore
|
||||||
const handleFormChange = (data: any) => {
|
const handleFormChange = (data: any) => {
|
||||||
const { key, value } = data
|
const { key, value } = data
|
||||||
const resultKey = `${currentEditKey.value}.${key}`
|
const resultKey = `${currentEditKey.value}.${key}`
|
||||||
changeSchema({ key: resultKey, value })
|
changeSchema({ key: resultKey, value })
|
||||||
|
if (key in editStore.editGlobalBaseConf.globalBaseConfig)
|
||||||
|
editStore.editGlobalBaseConf.updateCounts('MODIFY', { key, value })
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.setter-wrapper {
|
.setter-wrapper {
|
||||||
width: 360px;
|
width: 360px;
|
||||||
@ -39,36 +53,53 @@ const handleFormChange = (data: any) => {
|
|||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
}
|
.no-select-question {
|
||||||
|
padding-top: 125px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
.setter-title {
|
img {
|
||||||
height: 40px;
|
width: 160px;
|
||||||
line-height: 40px;
|
padding: 25px;
|
||||||
font-size: 14px;
|
}
|
||||||
color: $primary-color;
|
|
||||||
padding-left: 20px;
|
|
||||||
border-bottom: 1px solid #edeffc;
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-select-question {
|
.tip {
|
||||||
padding-top: 125px;
|
font-size: 14px;
|
||||||
display: flex;
|
color: $normal-color;
|
||||||
flex-direction: column;
|
letter-spacing: 0;
|
||||||
align-items: center;
|
}
|
||||||
|
|
||||||
img {
|
|
||||||
width: 160px;
|
|
||||||
padding: 25px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tip {
|
.setter-title {
|
||||||
|
height: 40px;
|
||||||
|
line-height: 40px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: $normal-color;
|
color: $primary-color;
|
||||||
letter-spacing: 0;
|
padding-left: 20px;
|
||||||
|
border-bottom: 1px solid #edeffc;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.question-config-form {
|
:deep(.el-tabs) {
|
||||||
padding: 30px 20px 50px 20px;
|
width: 360px;
|
||||||
|
height: 100%;
|
||||||
|
border: none;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.el-tabs__nav {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-tabs__content {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
.config-form {
|
||||||
|
padding: 30px 20px 50px 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -0,0 +1,91 @@
|
|||||||
|
import { reactive, type Ref } from 'vue'
|
||||||
|
|
||||||
|
export type TypeMethod = 'INIT' | 'MODIFY' | 'REMOVE' | 'ADD'
|
||||||
|
|
||||||
|
export default function useEditGlobalBaseConf(
|
||||||
|
questionDetailList: Ref<any[]>,
|
||||||
|
updateTime: () => void
|
||||||
|
) {
|
||||||
|
// 整卷配置数据
|
||||||
|
const globalBaseConfig = reactive({
|
||||||
|
isRequired: true,
|
||||||
|
showIndex: true,
|
||||||
|
showType: true,
|
||||||
|
showSpliter: true
|
||||||
|
})
|
||||||
|
|
||||||
|
// 整卷配置各项选项选中个数统计
|
||||||
|
const optionCheckedCounts = {
|
||||||
|
isRequiredCount: 0,
|
||||||
|
showIndexCount: 0,
|
||||||
|
showTypeCount: 0,
|
||||||
|
showSpliterCount: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化统计
|
||||||
|
function initCounts() {
|
||||||
|
questionDetailList.value.forEach((question: any) => {
|
||||||
|
calculateCountsForQuestion('INIT', { question })
|
||||||
|
})
|
||||||
|
updateGlobalBaseConf()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新统计
|
||||||
|
function updateCounts(type: TypeMethod, data: any) {
|
||||||
|
if (type === 'MODIFY') {
|
||||||
|
calculateOptionCounts(type, data)
|
||||||
|
} else {
|
||||||
|
calculateCountsForQuestion(type, data)
|
||||||
|
}
|
||||||
|
updateGlobalBaseConf()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算整卷配置各项选项选中个数
|
||||||
|
function calculateCountsForQuestion(type: TypeMethod, { question }: any) {
|
||||||
|
Object.keys(globalBaseConfig).forEach((key) => {
|
||||||
|
calculateOptionCounts(type, { key, value: question[key] })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算单个选项选中个数
|
||||||
|
function calculateOptionCounts(type: TypeMethod, { key, value }: any) {
|
||||||
|
const _key = `${key}Count` as keyof typeof optionCheckedCounts
|
||||||
|
if (value) {
|
||||||
|
if (type === 'REMOVE') optionCheckedCounts[_key]--
|
||||||
|
else optionCheckedCounts[_key]++
|
||||||
|
} else {
|
||||||
|
if (type === 'MODIFY') optionCheckedCounts[_key]--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新整卷配置状态
|
||||||
|
function updateGlobalBaseConf() {
|
||||||
|
const len = questionDetailList.value.length
|
||||||
|
const { isRequiredCount, showIndexCount, showSpliterCount, showTypeCount } = optionCheckedCounts
|
||||||
|
Object.assign(globalBaseConfig, {
|
||||||
|
isRequired: isRequiredCount === len,
|
||||||
|
showIndex: showIndexCount === len,
|
||||||
|
showSpliter: showSpliterCount === len,
|
||||||
|
showType: showTypeCount === len
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 整卷配置修改
|
||||||
|
function updateGlobalConfOption({ key, value }: { key: string; value: boolean }) {
|
||||||
|
const len = questionDetailList.value.length
|
||||||
|
const _key = `${key}Count` as keyof typeof optionCheckedCounts
|
||||||
|
if (value) optionCheckedCounts[_key] = len
|
||||||
|
else optionCheckedCounts[_key] = 0
|
||||||
|
questionDetailList.value.forEach((question: any) => {
|
||||||
|
question[key] = value
|
||||||
|
})
|
||||||
|
updateTime()
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
globalBaseConfig,
|
||||||
|
initCounts,
|
||||||
|
updateCounts,
|
||||||
|
updateGlobalConfOption
|
||||||
|
}
|
||||||
|
}
|
@ -19,6 +19,7 @@ import questionLoader from '@/materials/questions/questionLoader'
|
|||||||
import { SurveyPermissions } from '@/management/utils/types/workSpace'
|
import { SurveyPermissions } from '@/management/utils/types/workSpace'
|
||||||
import { getBannerData } from '@/management/api/skin.js'
|
import { getBannerData } from '@/management/api/skin.js'
|
||||||
import { getCollaboratorPermissions } from '@/management/api/space'
|
import { getCollaboratorPermissions } from '@/management/api/space'
|
||||||
|
import useEditGlobalBaseConf, { type TypeMethod } from './composables/useEditGlobalBaseConf'
|
||||||
import { CODE_MAP } from '../api/base'
|
import { CODE_MAP } from '../api/base'
|
||||||
|
|
||||||
const innerMetaConfig = {
|
const innerMetaConfig = {
|
||||||
@ -28,7 +29,7 @@ const innerMetaConfig = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function useInitializeSchema(surveyId: Ref<string>) {
|
function useInitializeSchema(surveyId: Ref<string>, initializeSchemaCallBack: () => void) {
|
||||||
const schema = reactive({
|
const schema = reactive({
|
||||||
metaData: null,
|
metaData: null,
|
||||||
bannerConf: {
|
bannerConf: {
|
||||||
@ -130,6 +131,7 @@ function useInitializeSchema(surveyId: Ref<string>) {
|
|||||||
logicConf
|
logicConf
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
initializeSchemaCallBack()
|
||||||
} else {
|
} else {
|
||||||
throw new Error(res.errmsg || '问卷不存在')
|
throw new Error(res.errmsg || '问卷不存在')
|
||||||
}
|
}
|
||||||
@ -142,11 +144,17 @@ function useInitializeSchema(surveyId: Ref<string>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function useQuestionDataListOperations(
|
function useQuestionDataListOperations({
|
||||||
questionDataList: Ref<any[]>,
|
questionDataList,
|
||||||
updateTime: () => void,
|
updateTime,
|
||||||
|
pageOperations,
|
||||||
|
updateCounts
|
||||||
|
}: {
|
||||||
|
questionDataList: Ref<any[]>
|
||||||
|
updateTime: () => void
|
||||||
pageOperations: (type: string) => void
|
pageOperations: (type: string) => void
|
||||||
) {
|
updateCounts: (type: TypeMethod, data: any) => void
|
||||||
|
}) {
|
||||||
function copyQuestion({ index }: { index: number }) {
|
function copyQuestion({ index }: { index: number }) {
|
||||||
const newQuestion = _cloneDeep(questionDataList.value[index])
|
const newQuestion = _cloneDeep(questionDataList.value[index])
|
||||||
newQuestion.field = getNewField(questionDataList.value.map((item) => item.field))
|
newQuestion.field = getNewField(questionDataList.value.map((item) => item.field))
|
||||||
@ -157,12 +165,14 @@ function useQuestionDataListOperations(
|
|||||||
questionDataList.value.splice(index, 0, question)
|
questionDataList.value.splice(index, 0, question)
|
||||||
pageOperations('add')
|
pageOperations('add')
|
||||||
updateTime()
|
updateTime()
|
||||||
|
updateCounts('ADD', { question })
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteQuestion({ index }: { index: number }) {
|
function deleteQuestion({ index }: { index: number }) {
|
||||||
pageOperations('remove')
|
pageOperations('remove')
|
||||||
questionDataList.value.splice(index, 1)
|
const [question] = questionDataList.value.splice(index, 1)
|
||||||
updateTime()
|
updateTime()
|
||||||
|
updateCounts('REMOVE', { question })
|
||||||
}
|
}
|
||||||
|
|
||||||
function moveQuestion({ index, range }: { index: number; range: number }) {
|
function moveQuestion({ index, range }: { index: number; range: number }) {
|
||||||
@ -432,9 +442,13 @@ export const useEditStore = defineStore('edit', () => {
|
|||||||
const bannerList: Ref<IBannerList> = ref({})
|
const bannerList: Ref<IBannerList> = ref({})
|
||||||
const cooperPermissions = ref(Object.values(SurveyPermissions))
|
const cooperPermissions = ref(Object.values(SurveyPermissions))
|
||||||
const schemaUpdateTime = ref(Date.now())
|
const schemaUpdateTime = ref(Date.now())
|
||||||
const { schema, initSchema, getSchemaFromRemote } = useInitializeSchema(surveyId)
|
const { schema, initSchema, getSchemaFromRemote } = useInitializeSchema(surveyId, () => {
|
||||||
|
editGlobalBaseConf.initCounts()
|
||||||
|
})
|
||||||
const questionDataList = toRef(schema, 'questionDataList')
|
const questionDataList = toRef(schema, 'questionDataList')
|
||||||
|
|
||||||
|
const editGlobalBaseConf = useEditGlobalBaseConf(questionDataList, updateTime)
|
||||||
|
|
||||||
function setQuestionDataList(data: any) {
|
function setQuestionDataList(data: any) {
|
||||||
schema.questionDataList = data
|
schema.questionDataList = data
|
||||||
}
|
}
|
||||||
@ -497,9 +511,12 @@ export const useEditStore = defineStore('edit', () => {
|
|||||||
} = usePageEdit({ schema, questionDataList }, updateTime)
|
} = usePageEdit({ schema, questionDataList }, updateTime)
|
||||||
|
|
||||||
const { copyQuestion, addQuestion, deleteQuestion, moveQuestion } = useQuestionDataListOperations(
|
const { copyQuestion, addQuestion, deleteQuestion, moveQuestion } = useQuestionDataListOperations(
|
||||||
questionDataList,
|
{
|
||||||
updateTime,
|
questionDataList,
|
||||||
pageOperations
|
updateTime,
|
||||||
|
pageOperations,
|
||||||
|
updateCounts: editGlobalBaseConf.updateCounts
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
function moveQuestionDataList(data: any) {
|
function moveQuestionDataList(data: any) {
|
||||||
@ -575,6 +592,7 @@ export const useEditStore = defineStore('edit', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
editGlobalBaseConf,
|
||||||
surveyId,
|
surveyId,
|
||||||
setSurveyId,
|
setSurveyId,
|
||||||
bannerList,
|
bannerList,
|
||||||
|
Loading…
Reference in New Issue
Block a user