From 06d3a96ef5f08ee0ceabf2c808fffe3037521e06 Mon Sep 17 00:00:00 2001 From: baiqi Date: Fri, 31 May 2024 16:57:05 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E5=8A=9F=E8=83=BD=E7=94=A8=E4=BE=8B):=20?= =?UTF-8?q?=E8=84=91=E5=9B=BE=E4=BF=9D=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modules/case-management/featureCase.ts | 4 +- .../ms-minders/featureCaseMinder/basInfo.vue | 36 +- .../ms-minders/featureCaseMinder/index.vue | 307 ++++++++++++++---- .../hooks/useEventListener.ts | 46 +++ .../ms-minder-editor/hooks/useShortCut.ts | 1 + .../pure/ms-minder-editor/main/mainEditor.vue | 36 +- .../ms-minder-editor/menu/edit/tagBox.vue | 6 + .../pure/ms-minder-editor/minderEditor.vue | 35 +- .../components/pure/ms-minder-editor/props.ts | 2 + .../ms-minder-editor/script/tool/utils.ts | 22 +- frontend/src/enums/minderEnum.ts | 8 + .../src/models/caseManagement/featureCase.ts | 16 +- .../components/caseTable.vue | 4 +- .../src/views/login/components/tabQrCode.vue | 16 +- .../views/login/components/weComQrCode.vue | 6 +- 15 files changed, 396 insertions(+), 149 deletions(-) create mode 100644 frontend/src/components/pure/ms-minder-editor/hooks/useEventListener.ts create mode 100644 frontend/src/components/pure/ms-minder-editor/hooks/useShortCut.ts diff --git a/frontend/src/api/modules/case-management/featureCase.ts b/frontend/src/api/modules/case-management/featureCase.ts index 1f2930d591..56992bc400 100644 --- a/frontend/src/api/modules/case-management/featureCase.ts +++ b/frontend/src/api/modules/case-management/featureCase.ts @@ -90,7 +90,7 @@ import type { DeleteDependencyParams, DemandItem, DragCase, - FeatureCaseMinder, + FeatureCaseMinderUpdateParams, ImportExcelType, ModulesTreeType, OperationFile, @@ -182,7 +182,7 @@ export function batchCopyToModules(data: BatchMoveOrCopyType) { } // 保存脑图 -export function saveCaseMinder(data: FeatureCaseMinder) { +export function saveCaseMinder(data: FeatureCaseMinderUpdateParams) { return MSR.post({ url: `${SaveCaseMinderUrl}`, data }); } diff --git a/frontend/src/components/business/ms-minders/featureCaseMinder/basInfo.vue b/frontend/src/components/business/ms-minders/featureCaseMinder/basInfo.vue index 55edf3fc23..e37409b049 100644 --- a/frontend/src/components/business/ms-minders/featureCaseMinder/basInfo.vue +++ b/frontend/src/components/business/ms-minders/featureCaseMinder/basInfo.vue @@ -63,6 +63,7 @@ loading: boolean; }>(); const emit = defineEmits<{ + (e: 'initTemplate', id: string): void; (e: 'cancel'): void; }>(); @@ -118,6 +119,7 @@ }); formRules.value = result.filter((e: any) => e); baseInfoLoading.value = false; + emit('initTemplate', id); } catch (error) { // eslint-disable-next-line no-console console.log(error); @@ -129,6 +131,22 @@ }); const saveLoading = ref(false); + + function makeParams() { + return { + ...baseInfoForm.value, + id: props.activeCase.id, + projectId: appStore.currentProjectId, + caseEditType: props.activeCase.caseEditType, + customFields: formItem.value.map((item: any) => { + return { + fieldId: item.field, + value: Array.isArray(item.value) ? JSON.stringify(item.value) : item.value, + }; + }), + }; + } + function handleSave() { baseInfoFormRef.value?.validate((errors) => { if (!errors) { @@ -136,20 +154,8 @@ if (valid === true) { try { saveLoading.value = true; - const data = { - ...baseInfoForm.value, - id: props.activeCase.id, - projectId: appStore.currentProjectId, - caseEditType: props.activeCase.caseEditType, - customFields: formItem.value.map((item: any) => { - return { - fieldId: item.field, - value: Array.isArray(item.value) ? JSON.stringify(item.value) : item.value, - }; - }), - }; await updateCaseRequest({ - request: data, + request: makeParams(), fileList: [], }); const selectedNode: MinderJsonNode = window.minder.getSelectedNode(); @@ -181,6 +187,10 @@ immediate: true, } ); + + defineExpose({ + makeParams, + }); diff --git a/frontend/src/components/pure/ms-minder-editor/hooks/useEventListener.ts b/frontend/src/components/pure/ms-minder-editor/hooks/useEventListener.ts new file mode 100644 index 0000000000..49d9f2420b --- /dev/null +++ b/frontend/src/components/pure/ms-minder-editor/hooks/useEventListener.ts @@ -0,0 +1,46 @@ +import { debounce } from 'lodash-es'; + +import useMinderStore from '@/store/modules/components/minder-editor/index'; +import type { MinderEvent } from '@/store/modules/components/minder-editor/types'; + +import type { MinderJsonNode } from '../props'; + +export interface UseEventListenerProps { + handleContentChange?: (node: MinderJsonNode) => void; + handleSelectionChange?: (node: MinderJsonNode) => void; + handleMinderEvent?: (event: MinderEvent) => void; +} + +export default function useEventListener(listener: UseEventListenerProps) { + const { minder } = window; + const minderStore = useMinderStore(); + + // 监听脑图节点内容变化 + minder.on('contentchange', () => { + const node: MinderJsonNode = minder.getSelectedNode(); + if (listener.handleContentChange) { + listener.handleContentChange(node); + } + }); + + // 监听脑图选中节点变化 + minder.on( + 'selectionchange', + debounce(() => { + const node: MinderJsonNode = minder.getSelectedNode(); + if (listener.handleSelectionChange) { + listener.handleSelectionChange(node); + } + }, 300) + ); + + // 监听脑图自定义事件 + watch( + () => minderStore.event.timestamp, + () => { + if (listener.handleMinderEvent) { + listener.handleMinderEvent(minderStore.event); + } + } + ); +} diff --git a/frontend/src/components/pure/ms-minder-editor/hooks/useShortCut.ts b/frontend/src/components/pure/ms-minder-editor/hooks/useShortCut.ts new file mode 100644 index 0000000000..a6e8008326 --- /dev/null +++ b/frontend/src/components/pure/ms-minder-editor/hooks/useShortCut.ts @@ -0,0 +1 @@ +export default function useShortCut() {} diff --git a/frontend/src/components/pure/ms-minder-editor/main/mainEditor.vue b/frontend/src/components/pure/ms-minder-editor/main/mainEditor.vue index 8b0b5d5e26..2b1c07ee2c 100644 --- a/frontend/src/components/pure/ms-minder-editor/main/mainEditor.vue +++ b/frontend/src/components/pure/ms-minder-editor/main/mainEditor.vue @@ -19,12 +19,6 @@
( / )
- -
-
{{ t('minder.hotboxMenu.insetParent') }}
-
(Shift + Tab)
-
-
{{ t('minder.hotboxMenu.insetSon') }}
@@ -94,7 +88,15 @@ import { MinderEventName } from '@/enums/minderEnum'; - import { editMenuProps, insertProps, mainEditorProps, MinderJsonNode, priorityProps, tagProps } from '../props'; + import { + editMenuProps, + insertProps, + mainEditorProps, + MinderJson, + MinderJsonNode, + priorityProps, + tagProps, + } from '../props'; import Editor from '../script/editor'; import { markChangeNode, markDeleteNode } from '../script/tool/utils'; import type { Ref } from 'vue'; @@ -102,11 +104,10 @@ const { t } = useI18n(); const props = defineProps({ ...editMenuProps, ...insertProps, ...mainEditorProps, ...tagProps, ...priorityProps }); - const emit = defineEmits({ - afterMount: () => ({}), - save: (json) => json, - enterNode: (data) => data, - }); + const emit = defineEmits<{ + (e: 'afterMount'): void; + (e: 'save', json: MinderJson): void; + }>(); const minderStore = useMinderStore(); const mec: Ref = ref(null); @@ -192,7 +193,7 @@ 'appendsiblingnode', ]); if (selectNodes && !notChangeCommands.has(env.commandName.toLocaleLowerCase())) { - selectNodes.forEach((node: any) => { + selectNodes.forEach((node: MinderJsonNode) => { markChangeNode(node); }); } @@ -233,6 +234,7 @@ innerImportJson.value.data.expandState = 'expand'; window.minder.importJson(innerImportJson.value); window.minder.execCommand('template', Object.keys(window.kityminder.Minder.getTemplateList())[minderStore.mold]); + minderStore.dispatchEvent(MinderEventName.ENTER_NODE, undefined, undefined, node); } watch( @@ -280,27 +282,35 @@ } else { window.minder.execCommand('Collapse'); } + minderStore.dispatchEvent(MinderEventName.EXPAND, undefined, undefined, selectedNode); break; case 'insetParent': execInsertCommand('AppendParentNode'); + minderStore.dispatchEvent(MinderEventName.INSERT_PARENT, undefined, undefined, selectedNode); break; case 'insetSon': execInsertCommand('AppendChildNode'); + minderStore.dispatchEvent(MinderEventName.INSERT_CHILD, undefined, undefined, selectedNode); break; case 'insetBrother': execInsertCommand('AppendSiblingNode'); + minderStore.dispatchEvent(MinderEventName.INSERT_SIBLING, undefined, undefined, selectedNode); break; case 'copy': window.minder.execCommand('Copy'); + minderStore.dispatchEvent(MinderEventName.COPY_NODE, undefined, undefined, selectedNode); break; case 'cut': window.minder.execCommand('Cut'); + minderStore.dispatchEvent(MinderEventName.CUT_NODE, undefined, undefined, selectedNode); break; case 'paste': window.minder.execCommand('Paste'); + minderStore.dispatchEvent(MinderEventName.PASTE_NODE, undefined, undefined, selectedNode); break; case 'delete': window.minder.execCommand('RemoveNode'); + minderStore.dispatchEvent(MinderEventName.DELETE_NODE, undefined, undefined, selectedNode); break; case 'enterNode': switchNode(selectedNode.data); diff --git a/frontend/src/components/pure/ms-minder-editor/menu/edit/tagBox.vue b/frontend/src/components/pure/ms-minder-editor/menu/edit/tagBox.vue index 936422865e..24b37702a9 100644 --- a/frontend/src/components/pure/ms-minder-editor/menu/edit/tagBox.vue +++ b/frontend/src/components/pure/ms-minder-editor/menu/edit/tagBox.vue @@ -15,10 +15,15 @@ diff --git a/frontend/src/components/pure/ms-minder-editor/props.ts b/frontend/src/components/pure/ms-minder-editor/props.ts index a231e16c6c..0b9f3edc20 100644 --- a/frontend/src/components/pure/ms-minder-editor/props.ts +++ b/frontend/src/components/pure/ms-minder-editor/props.ts @@ -16,6 +16,8 @@ export interface MinderJsonNodeData { expandState?: 'collapse' | 'expand'; priority?: number; // 前端渲染字段 + isNew?: boolean; // 是否脑图新增节点,需要在初始化脑图数据时标记已存在节点为 false 以区分是否新增节点 + changed?: boolean; // 脑图节点是否发生过变化 [key: string]: any; } export interface MinderJsonNode { diff --git a/frontend/src/components/pure/ms-minder-editor/script/tool/utils.ts b/frontend/src/components/pure/ms-minder-editor/script/tool/utils.ts index 9877c3708c..6b225bc057 100644 --- a/frontend/src/components/pure/ms-minder-editor/script/tool/utils.ts +++ b/frontend/src/components/pure/ms-minder-editor/script/tool/utils.ts @@ -1,3 +1,5 @@ +import type { MinderJsonNode } from '../../props'; + export function isDisableNode(minder: any) { let node; if (minder && minder.getSelectedNode) { @@ -20,7 +22,7 @@ export function isDeleteDisableNode(minder: any) { return false; } -export function isTagEnableNode(node: any) { +export function isTagEnableNode(node: MinderJsonNode) { if (node && (node.data.tagEnable === true || node.data.allowDisabledTag === true)) { return true; } @@ -38,19 +40,13 @@ export function isTagEnable(minder: any) { return false; } -export function markChangeNode(node: any) { - if (node && node.data) { - // 修改的该节点标记为 contextChanged - node.data.contextChanged = true; - while (node) { - // 该路径上的节点都标记为 changed - node.data.changed = true; - node = node.parent; - } +export function markChangeNode(node: MinderJsonNode) { + if (node.data) { + node.data.changed = true; } } -function markDelNode(node: any, deleteChild: any) { +function markDelNode(node: MinderJsonNode, deleteChild: any) { deleteChild.push(node.data); if (node.children) { node.children.forEach((child: any) => { @@ -63,7 +59,7 @@ function markDelNode(node: any, deleteChild: any) { export function markDeleteNode(minder: any) { if (minder) { const nodes = minder.getSelectedNodes(); - nodes.forEach((node: any) => { + nodes.forEach((node: MinderJsonNode) => { if (node && node.parent) { const pData = node.parent.data; if (!pData.deleteChild) { @@ -118,7 +114,7 @@ export function resetNodes(nodes: any) { } } -export function isDisableForNode(node: any) { +export function isDisableForNode(node: MinderJsonNode) { if (node && node.data.disable === true) { return true; } diff --git a/frontend/src/enums/minderEnum.ts b/frontend/src/enums/minderEnum.ts index d7b955f318..4cfbeeab4b 100644 --- a/frontend/src/enums/minderEnum.ts +++ b/frontend/src/enums/minderEnum.ts @@ -2,6 +2,14 @@ export enum MinderEventName { 'DELETE_NODE' = 'DELETE_NODE', // 删除节点 'HOTBOX' = 'HOTBOX', // 热键菜单 'ENTER_NODE' = 'ENTER_NODE', // 进入节点 + 'EXPAND' = 'EXPAND', // 展开节点 + 'INSERT_PARENT' = 'INSERT_PARENT', // 插入父节点 + 'INSERT_CHILD' = 'INSERT_CHILD', // 插入子节点 + 'INSERT_SIBLING' = 'INSERT_SIBLING', // 插入同级节点 + 'COPY_NODE' = 'COPY_NODE', // 复制节点 + 'PASTE_NODE' = 'PASTE_NODE', // 粘贴节点 + 'CUT_NODE' = 'CUT_NODE', // 剪切节点 + 'SET_TAG' = 'SET_TAG', // 设置节点标签 } export default {}; diff --git a/frontend/src/models/caseManagement/featureCase.ts b/frontend/src/models/caseManagement/featureCase.ts index 427b0349e6..0b8d674015 100644 --- a/frontend/src/models/caseManagement/featureCase.ts +++ b/frontend/src/models/caseManagement/featureCase.ts @@ -365,7 +365,7 @@ export interface ContentTabsMap { backupTabList: TabItemType[]; } // 脑图删除的模块/用例的集合 -export interface FeatureCaseMinderDeleteResourceList { +export interface FeatureCaseMinderDeleteResourceItem { id: string; type: string; } @@ -374,7 +374,7 @@ export type FeatureCaseMinderActionType = 'ADD' | 'UPDATE'; // 脑图用例编辑模式 export type FeatureCaseMinderEditType = 'STEP' | 'TEXT'; // 脑图新增/修改的模块集合(只记录操作的节点,节点下的子节点不需要记录) -export interface FeatureCaseMinderUpdateModuleList { +export interface FeatureCaseMinderUpdateModuleItem { id: string; name: string; parentId: string; @@ -395,7 +395,7 @@ export interface FeatureCaseMinderStepItem { result?: string; } // 脑图新增/修改的用例对象集合 -export interface FeatureCaseMinderUpdateCaseList { +export interface FeatureCaseMinderUpdateCaseItem { id: string; // 用例id(新增的时候前端传UUid,更新的时候必填) templateId: string; // 模板id type: FeatureCaseMinderActionType; @@ -403,7 +403,7 @@ export interface FeatureCaseMinderUpdateCaseList { moduleId: string; moveMode?: MoveMode; // 移动方式(节点移动或新增时需要) targetId?: string; - prerequisite: string; + prerequisite: string; // 前置条件 caseEditType: FeatureCaseMinderEditType; steps: FeatureCaseMinderStepItem[]; textDescription: string; // 文本描述 @@ -413,10 +413,10 @@ export interface FeatureCaseMinderUpdateCaseList { customFields: CustomField[]; } // 脑图 -export interface FeatureCaseMinder { +export interface FeatureCaseMinderUpdateParams { projectId: string; versionId?: string; - updateCaseList: FeatureCaseMinderUpdateCaseList[]; - updateModuleList: FeatureCaseMinderUpdateModuleList[]; - deleteResourceList: FeatureCaseMinderDeleteResourceList[]; + updateCaseList: FeatureCaseMinderUpdateCaseItem[]; + updateModuleList: FeatureCaseMinderUpdateModuleItem[]; + deleteResourceList: FeatureCaseMinderDeleteResourceItem[]; } diff --git a/frontend/src/views/case-management/caseManagementFeature/components/caseTable.vue b/frontend/src/views/case-management/caseManagementFeature/components/caseTable.vue index aa1109fe63..0bebb317ae 100644 --- a/frontend/src/views/case-management/caseManagementFeature/components/caseTable.vue +++ b/frontend/src/views/case-management/caseManagementFeature/components/caseTable.vue @@ -16,14 +16,14 @@ @refresh="fetchData()" >