From 11d9c8c58c146c7db7c168bf1026a78451cbf302 Mon Sep 17 00:00:00 2001 From: dayou <853094838@qq.com> Date: Mon, 9 Dec 2024 20:48:27 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=A4=9A=E7=BA=A7=E8=81=94=E5=8A=A8?= =?UTF-8?q?=E9=A2=98=E9=87=8D=E5=91=BD=E5=90=8D=E4=B8=BAcascader?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/enums/question.ts | 2 +- server/src/interfaces/survey.ts | 10 +- .../controllers/dataStatistic.controller.ts | 2 +- .../survey/services/dataStatistic.service.ts | 6 +- server/src/modules/survey/utils/index.ts | 4 +- .../imgs/question-type-snapshot/cascader.webp | Bin 0 -> 4858 bytes web/src/common/typeEnum.ts | 6 +- .../management/config/questionMenuConfig.js | 12 +- web/src/management/hooks/useCascaderPull.ts | 138 +++++++++++++ web/src/management/hooks/useMultilevelPull.ts | 58 +++--- .../AdvancedConfig/CascaderConfig.vue | 194 ++++++++++++++++++ .../components/AdvancedConfig/index.vue | 4 +- web/src/management/styles/icon.scss | 2 +- .../questions/common/config/moduleList.js | 2 +- .../CascaderModule/BaseCascader/index.vue | 192 +++++++++++++++++ .../widgets/CascaderModule/index.jsx | 45 ++++ .../questions/widgets/CascaderModule/meta.js | 94 +++++++++ 17 files changed, 717 insertions(+), 54 deletions(-) create mode 100644 web/public/imgs/question-type-snapshot/cascader.webp create mode 100644 web/src/management/hooks/useCascaderPull.ts create mode 100644 web/src/management/pages/edit/modules/questionModule/components/AdvancedConfig/CascaderConfig.vue create mode 100644 web/src/materials/questions/widgets/CascaderModule/BaseCascader/index.vue create mode 100644 web/src/materials/questions/widgets/CascaderModule/index.jsx create mode 100644 web/src/materials/questions/widgets/CascaderModule/meta.js diff --git a/server/src/enums/question.ts b/server/src/enums/question.ts index 6dacd512..09959099 100644 --- a/server/src/enums/question.ts +++ b/server/src/enums/question.ts @@ -37,5 +37,5 @@ export enum QUESTION_TYPE { /** * 多级联动 */ - MULTILEVEL = 'multilevel', + CASCADER = 'cascader', } diff --git a/server/src/interfaces/survey.ts b/server/src/interfaces/survey.ts index bf8330f0..290540ab 100644 --- a/server/src/interfaces/survey.ts +++ b/server/src/interfaces/survey.ts @@ -22,18 +22,18 @@ export interface NPS { rightText: string; } -export interface MultilevelItem { +export interface CascaderItem { hash: string; text: string; - children?: MultilevelItem[]; + children?: CascaderItem[]; } -export interface MultilevelData { +export interface CascaderDate { placeholder: Array<{ hash: string; text: string; }>; - children: Array; + children: Array; } export interface TextRange { @@ -74,7 +74,7 @@ export interface DataItem { rangeConfig?: any; starStyle?: string; innerType?: string; - multilevelData: MultilevelData; + cascaderData: CascaderDate; } export interface Option { diff --git a/server/src/modules/survey/controllers/dataStatistic.controller.ts b/server/src/modules/survey/controllers/dataStatistic.controller.ts index 56ce27f6..cbcee75f 100644 --- a/server/src/modules/survey/controllers/dataStatistic.controller.ts +++ b/server/src/modules/survey/controllers/dataStatistic.controller.ts @@ -108,7 +108,7 @@ export class DataStatisticController { QUESTION_TYPE.RADIO_STAR, QUESTION_TYPE.RADIO_NPS, QUESTION_TYPE.VOTE, - QUESTION_TYPE.MULTILEVEL, + QUESTION_TYPE.CASCADER, ]; const fieldList = responseSchema.code.dataConf.dataList .filter((item) => allowQuestionType.includes(item.type as QUESTION_TYPE)) diff --git a/server/src/modules/survey/services/dataStatistic.service.ts b/server/src/modules/survey/services/dataStatistic.service.ts index 50457448..8026a3b5 100644 --- a/server/src/modules/survey/services/dataStatistic.service.ts +++ b/server/src/modules/survey/services/dataStatistic.service.ts @@ -89,10 +89,10 @@ export class DataStatisticService { } // 将多级联动id还原成选项文案 if ( - itemConfig.multilevelData && - itemConfig.type === QUESTION_TYPE.MULTILEVEL + itemConfig.cascaderData && + itemConfig.type === QUESTION_TYPE.CASCADER ) { - let optionTextMap = keyBy(itemConfig.multilevelData.children, 'hash'); + let optionTextMap = keyBy(itemConfig.cascaderData.children, 'hash'); data[itemKey] = data[itemKey] ?.split(',') .map((v) => { diff --git a/server/src/modules/survey/utils/index.ts b/server/src/modules/survey/utils/index.ts index dee07eee..eb270d87 100644 --- a/server/src/modules/survey/utils/index.ts +++ b/server/src/modules/survey/utils/index.ts @@ -174,9 +174,9 @@ export function handleAggretionData({ dataMap, item }) { summary, }, }; - } else if (type == QUESTION_TYPE.MULTILEVEL) { + } else if (type == QUESTION_TYPE.CASCADER) { const aggregation = getTextPaths( - dataMap[item.field].multilevelData.children, + dataMap[item.field].cascaderData.children, ); return { ...item, diff --git a/web/public/imgs/question-type-snapshot/cascader.webp b/web/public/imgs/question-type-snapshot/cascader.webp new file mode 100644 index 0000000000000000000000000000000000000000..ab849863277f5e3bf0ce723482a2060c6fc70472 GIT binary patch literal 4858 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 literal 0 HcmV?d00001 diff --git a/web/src/common/typeEnum.ts b/web/src/common/typeEnum.ts index 53270ce2..65ca3c06 100644 --- a/web/src/common/typeEnum.ts +++ b/web/src/common/typeEnum.ts @@ -8,7 +8,7 @@ export enum QUESTION_TYPE { RADIO_STAR = 'radio-star', RADIO_NPS = 'radio-nps', VOTE = 'vote', - MULTILEVEL = 'multilevel', + CASCADER = 'cascader', } // 题目类型标签映射对象 @@ -21,7 +21,7 @@ export const typeTagLabels: Record = { [QUESTION_TYPE.RADIO_STAR]: '评分', [QUESTION_TYPE.RADIO_NPS]: 'NPS评分', [QUESTION_TYPE.VOTE]: '投票', - [QUESTION_TYPE.MULTILEVEL]: '多级联动' + [QUESTION_TYPE.CASCADER]: '多级联动' } // 输入类题型 @@ -42,4 +42,4 @@ export const CHOICES = [ export const RATES = [QUESTION_TYPE.RADIO_STAR, QUESTION_TYPE.RADIO_NPS] // 高级题型分类 -export const ADVANCED = [QUESTION_TYPE.MULTILEVEL] \ No newline at end of file +export const ADVANCED = [QUESTION_TYPE.CASCADER] \ No newline at end of file diff --git a/web/src/management/config/questionMenuConfig.js b/web/src/management/config/questionMenuConfig.js index f988d8f0..0e363f94 100644 --- a/web/src/management/config/questionMenuConfig.js +++ b/web/src/management/config/questionMenuConfig.js @@ -55,11 +55,11 @@ export const menuItems = { icon: 'tixing-toupiao', title: '投票' }, - multilevel: { - type: 'multilevel', - path: 'MultilevelModule', - snapshot: '/imgs/question-type-snapshot/multilevel.webp', - icon: 'multilevel-select', + cascader: { + type: 'cascader', + path: 'CascaderModule', + snapshot: '/imgs/question-type-snapshot/cascader.webp', + icon: 'cascader-select', title: '多级联动' } } @@ -74,7 +74,7 @@ const menuGroup = [ questionList: ['radio', 'checkbox', 'binary-choice', 'radio-star', 'radio-nps', 'vote'] }, { title: '高级题型', - questionList: ['multilevel'] + questionList: ['cascader'] } ] diff --git a/web/src/management/hooks/useCascaderPull.ts b/web/src/management/hooks/useCascaderPull.ts new file mode 100644 index 00000000..e4ee8c56 --- /dev/null +++ b/web/src/management/hooks/useCascaderPull.ts @@ -0,0 +1,138 @@ +import { ElMessageBox } from 'element-plus' +import { ref } from 'vue' +import { cloneDeep } from 'lodash-es' + +interface NodeItem { + hash: string, + text: string, + children?: NodeItem[], +} + +type CascaderDate = { + placeholder: Array<{ + hash: string, + text: string, + }>, + children: Array, +} + +export const useCascaderPull = () => { + const maxCount = 3; + const optionsCount = 50; + const cascaderVal = ref>([]); + const cascaderData = ref(null) + let hashArr: Array = []; + + + const extractHash = (obj: CascaderDate): Array => { + const hashes: Array = []; + + function recurse(currentObj: any) { + if (Array.isArray(currentObj)) { + currentObj.forEach(item => recurse(item)); + } else if (typeof currentObj === 'object' && currentObj !== null) { + if (currentObj.hash) { + hashes.push(currentObj.hash); + } + for (const key in currentObj) { + // eslint-disable-next-line no-prototype-builtins + if (currentObj.hasOwnProperty(key as any)) { + recurse(currentObj[key]); + } + } + } + } + + recurse(obj); + return hashes; + } + + const getRandom = () => { + return Math.random().toString().slice(-6) + } + + const getNewHash = () => { + let random = getRandom() + while (random in hashArr) { + random = getRandom() + } + hashArr.push(random) + return random + } + + const addCascaderNode = (key: number) => { + const nodeItem: NodeItem = (key == 0 ? cascaderData.value : cascaderVal.value[key - 1]) as NodeItem + if (nodeItem.children && nodeItem.children.length > optionsCount) { + ElMessageBox.alert(`当前最多添加${optionsCount}个选项`, '提示', { + confirmButtonText: '确定', + type: 'warning' + }) + return + } + const optionStr = `选项${nodeItem?.children ? nodeItem?.children?.length + 1 : 1}` + nodeItem.children?.push({ + hash: getNewHash(), + text: optionStr, + children: [] + }) + } + + const resetCascaderVal = (index: number) => { + for (let i = cascaderVal.value.length; index < i; i--) { + cascaderVal.value[i - 1] = null; + } + } + + const removeCascaderNode = (nodeItem: NodeItem, index: number, key: number) => { + try { + if (key == 0 && cascaderData.value?.children && cascaderData.value?.children?.length<=1) { + ElMessageBox.alert('至少保留一个选项', '提示', { + confirmButtonText: '确定', + type: 'warning' + }) + return + } + if (nodeItem.children) { + nodeItem.children[index].children = []; + } + nodeItem.children?.splice(index, 1) + resetCascaderVal(key) + } catch (error) { + console.log(error) + } + } + + const editCascaderNode = (nodeItem: NodeItem, index: number, text: string) => { + nodeItem.children && (nodeItem.children[index].text = text) + } + + + const setCascaderVal = (data: NodeItem, index: number) => { + if (cascaderVal.value[index]?.hash == data.hash) return + resetCascaderVal(index) + cascaderVal.value[index] = data + } + + + const loadInitData = (data: CascaderDate) => { + cascaderData.value = cloneDeep(data); + cascaderVal.value = []; + for (let index = 0; index < maxCount; index++) { + cascaderVal.value.push(null) + } + hashArr = extractHash(cascaderData.value); + } + + + + return { + addCascaderNode, + removeCascaderNode, + editCascaderNode, + loadInitData, + setCascaderVal, + + cascaderVal, + cascaderData + } +} \ No newline at end of file diff --git a/web/src/management/hooks/useMultilevelPull.ts b/web/src/management/hooks/useMultilevelPull.ts index 8d5382fc..e4ee8c56 100644 --- a/web/src/management/hooks/useMultilevelPull.ts +++ b/web/src/management/hooks/useMultilevelPull.ts @@ -8,7 +8,7 @@ interface NodeItem { children?: NodeItem[], } -type MultilevelDat = { +type CascaderDate = { placeholder: Array<{ hash: string, text: string, @@ -16,15 +16,15 @@ type MultilevelDat = { children: Array, } -export const useMultilevelPull = () => { +export const useCascaderPull = () => { const maxCount = 3; const optionsCount = 50; - const multilevelVal = ref>([]); - const multilevelData = ref(null) + const cascaderVal = ref>([]); + const cascaderData = ref(null) let hashArr: Array = []; - const extractHash = (obj: MultilevelDat): Array => { + const extractHash = (obj: CascaderDate): Array => { const hashes: Array = []; function recurse(currentObj: any) { @@ -60,8 +60,8 @@ export const useMultilevelPull = () => { return random } - const addMultilevelNode = (key: number) => { - const nodeItem: NodeItem = (key == 0 ? multilevelData.value : multilevelVal.value[key - 1]) as NodeItem + const addCascaderNode = (key: number) => { + const nodeItem: NodeItem = (key == 0 ? cascaderData.value : cascaderVal.value[key - 1]) as NodeItem if (nodeItem.children && nodeItem.children.length > optionsCount) { ElMessageBox.alert(`当前最多添加${optionsCount}个选项`, '提示', { confirmButtonText: '确定', @@ -77,15 +77,15 @@ export const useMultilevelPull = () => { }) } - const resetMultilevelVal = (index: number) => { - for (let i = multilevelVal.value.length; index < i; i--) { - multilevelVal.value[i - 1] = null; + const resetCascaderVal = (index: number) => { + for (let i = cascaderVal.value.length; index < i; i--) { + cascaderVal.value[i - 1] = null; } } - const removeMultilevelNode = (nodeItem: NodeItem, index: number, key: number) => { + const removeCascaderNode = (nodeItem: NodeItem, index: number, key: number) => { try { - if (key == 0 && multilevelData.value?.children && multilevelData.value?.children?.length<=1) { + if (key == 0 && cascaderData.value?.children && cascaderData.value?.children?.length<=1) { ElMessageBox.alert('至少保留一个选项', '提示', { confirmButtonText: '确定', type: 'warning' @@ -96,43 +96,43 @@ export const useMultilevelPull = () => { nodeItem.children[index].children = []; } nodeItem.children?.splice(index, 1) - resetMultilevelVal(key) + resetCascaderVal(key) } catch (error) { console.log(error) } } - const editMultilevelNode = (nodeItem: NodeItem, index: number, text: string) => { + const editCascaderNode = (nodeItem: NodeItem, index: number, text: string) => { nodeItem.children && (nodeItem.children[index].text = text) } - const setMultilevelVal = (data: NodeItem, index: number) => { - if (multilevelVal.value[index]?.hash == data.hash) return - resetMultilevelVal(index) - multilevelVal.value[index] = data + const setCascaderVal = (data: NodeItem, index: number) => { + if (cascaderVal.value[index]?.hash == data.hash) return + resetCascaderVal(index) + cascaderVal.value[index] = data } - const loadInitData = (data: MultilevelDat) => { - multilevelData.value = cloneDeep(data); - multilevelVal.value = []; + const loadInitData = (data: CascaderDate) => { + cascaderData.value = cloneDeep(data); + cascaderVal.value = []; for (let index = 0; index < maxCount; index++) { - multilevelVal.value.push(null) + cascaderVal.value.push(null) } - hashArr = extractHash(multilevelData.value); + hashArr = extractHash(cascaderData.value); } return { - addMultilevelNode, - removeMultilevelNode, - editMultilevelNode, + addCascaderNode, + removeCascaderNode, + editCascaderNode, loadInitData, - setMultilevelVal, + setCascaderVal, - multilevelVal, - multilevelData + cascaderVal, + cascaderData } } \ No newline at end of file diff --git a/web/src/management/pages/edit/modules/questionModule/components/AdvancedConfig/CascaderConfig.vue b/web/src/management/pages/edit/modules/questionModule/components/AdvancedConfig/CascaderConfig.vue new file mode 100644 index 00000000..98d5437f --- /dev/null +++ b/web/src/management/pages/edit/modules/questionModule/components/AdvancedConfig/CascaderConfig.vue @@ -0,0 +1,194 @@ + + + \ No newline at end of file diff --git a/web/src/management/pages/edit/modules/questionModule/components/AdvancedConfig/index.vue b/web/src/management/pages/edit/modules/questionModule/components/AdvancedConfig/index.vue index 30b88e96..aa243087 100644 --- a/web/src/management/pages/edit/modules/questionModule/components/AdvancedConfig/index.vue +++ b/web/src/management/pages/edit/modules/questionModule/components/AdvancedConfig/index.vue @@ -40,8 +40,8 @@ switch (props.moduleConfig.type) { case QUESTION_TYPE.RADIO_NPS: advancedComponent.value = defineAsyncComponent(() => import('./RateConfig.vue')) break - case QUESTION_TYPE.MULTILEVEL: - advancedComponent.value = defineAsyncComponent(() => import('./MultiLevelConfig.vue')) + case QUESTION_TYPE.CASCADER: + advancedComponent.value = defineAsyncComponent(() => import('./CascaderConfig.vue')) break default: break diff --git a/web/src/management/styles/icon.scss b/web/src/management/styles/icon.scss index dec4b2d1..a1d3a5aa 100644 --- a/web/src/management/styles/icon.scss +++ b/web/src/management/styles/icon.scss @@ -177,6 +177,6 @@ .icon-shiying:before { content: '\e6f6'; } -.icon-multilevel-select:before { +.icon-cascader-select:before { content: '\e6f9'; } \ No newline at end of file diff --git a/web/src/materials/questions/common/config/moduleList.js b/web/src/materials/questions/common/config/moduleList.js index 75de5b80..6d733ee7 100644 --- a/web/src/materials/questions/common/config/moduleList.js +++ b/web/src/materials/questions/common/config/moduleList.js @@ -11,5 +11,5 @@ export default { vote: 'VoteModule', 'matrix-checkbox': 'GroupModule', selectMoreModule: 'SelectMoreModule', - multilevel:'MultilevelModule', + cascader:'CascaderModule', } diff --git a/web/src/materials/questions/widgets/CascaderModule/BaseCascader/index.vue b/web/src/materials/questions/widgets/CascaderModule/BaseCascader/index.vue new file mode 100644 index 00000000..cdff8055 --- /dev/null +++ b/web/src/materials/questions/widgets/CascaderModule/BaseCascader/index.vue @@ -0,0 +1,192 @@ + + + \ No newline at end of file diff --git a/web/src/materials/questions/widgets/CascaderModule/index.jsx b/web/src/materials/questions/widgets/CascaderModule/index.jsx new file mode 100644 index 00000000..35a27ea2 --- /dev/null +++ b/web/src/materials/questions/widgets/CascaderModule/index.jsx @@ -0,0 +1,45 @@ +import { defineComponent} from 'vue' +import BaseCascader from './BaseCascader/index.vue' + +export default defineComponent({ + name: 'CascaderModule', + props: { + field: { + type: [String, Number], + default: '' + }, + value: { + type: String, + default: '' + }, + readonly: { + type: Boolean, + default: false + }, + cascaderData: { + type: Object, + default: () => {} + }, + }, + emits: ['change'], + setup(props, { emit }) { + const onChange = (value) => { + const key = props.field + emit('change', { + key, + value + }) + } + + return { + props, + onChange + } + }, + render() { + const { props } = this + return ( + + ) + } +}) \ No newline at end of file diff --git a/web/src/materials/questions/widgets/CascaderModule/meta.js b/web/src/materials/questions/widgets/CascaderModule/meta.js new file mode 100644 index 00000000..441ef7e7 --- /dev/null +++ b/web/src/materials/questions/widgets/CascaderModule/meta.js @@ -0,0 +1,94 @@ +import basicConfig from '@materials/questions/common/config/basicConfig' + + +const meta = { + title: '多级联动', + type: 'cascader', + componentName: 'CascaderModule', + attrs: [ + { + name: 'type', + propType: 'String', + description: '这是用于描述题目类型', + defaultValue: 'cascader' + }, + { + name: 'isRequired', + propType: Boolean, + description: '是否必填', + defaultValue: true + }, + { + name: 'showIndex', + propType: Boolean, + description: '显示序号', + defaultValue: true + }, + { + name: 'showType', + propType: Boolean, + description: '显示类型', + defaultValue: true + }, + { + name: 'showSpliter', + propType: Boolean, + description: '显示分割线', + defaultValue: true + }, + { + name: 'cascaderData', + propType: Array, + description: '这是用于描述选项', + defaultValue: + { + placeholder: [{ + text: '请选择', + hash: '115016' + }, { + text: '请选择', + hash: '115017' + }, { + text: '请选择', + hash: '115018' + }], + children: [ + { + text: '选项1', + children: [], + hash: '115019' + }, + { + text: '选项2', + children: [], + hash: '115020' + }, + { + text: '选项3', + children: [], + hash: '115011' + } + ] + }, + + + }, + ], + formConfig: [ + basicConfig + ], + editConfigure: { + optionEdit: { + show: false + }, + optionEditBar: { + show: true, + configure: { + showOthers: false, + showAdvancedConfig: true + } + } + } +} + +export default meta