mirror of
https://gitee.com/fit2cloud-feizhiyun/MeterSphere.git
synced 2024-12-01 03:28:59 +08:00
feat(功能用例): 脑图保存
This commit is contained in:
parent
14dc8d1d56
commit
06d3a96ef5
@ -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 });
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
@ -13,14 +13,18 @@
|
||||
single-tag
|
||||
tag-enable
|
||||
sequence-enable
|
||||
@content-change="handleContentChange"
|
||||
@node-select="handleNodeSelect"
|
||||
@action="handleAction"
|
||||
@save="handleMinderSave"
|
||||
>
|
||||
<template #extractTabContent>
|
||||
<baseInfo
|
||||
v-if="activeExtraKey === 'baseInfo'"
|
||||
ref="baseInfoRef"
|
||||
:loading="baseInfoLoading"
|
||||
:active-case="activeCase"
|
||||
@init-template="(id) => (templateId = id)"
|
||||
@cancel="handleBaseInfoCancel"
|
||||
/>
|
||||
<attachment
|
||||
@ -54,9 +58,16 @@
|
||||
} from '@/api/modules/case-management/featureCase';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
import { getGenerateId, mapTree } from '@/utils';
|
||||
import { MinderEvent } from '@/store/modules/components/minder-editor/types';
|
||||
import { filterTree, getGenerateId, mapTree } from '@/utils';
|
||||
|
||||
import {
|
||||
FeatureCaseMinderEditType,
|
||||
FeatureCaseMinderStepItem,
|
||||
FeatureCaseMinderUpdateParams,
|
||||
} from '@/models/caseManagement/featureCase';
|
||||
import { TableQueryParams } from '@/models/common';
|
||||
import { MinderEventName } from '@/enums/minderEnum';
|
||||
|
||||
import { convertToFile, initFormCreate } from '@/views/case-management/caseManagementFeature/components/utils';
|
||||
|
||||
@ -72,7 +83,12 @@
|
||||
const caseTag = t('common.case');
|
||||
const moduleTag = t('common.module');
|
||||
const topTags = [moduleTag, caseTag];
|
||||
const descTags = [t('ms.minders.stepDesc'), t('ms.minders.textDesc')];
|
||||
const stepTag = t('ms.minders.stepDesc');
|
||||
const textTag = t('ms.minders.textDesc');
|
||||
const prerequisiteTag = t('ms.minders.precondition');
|
||||
const remarkTag = t('common.remark');
|
||||
const descTags = [stepTag, textTag];
|
||||
const caseChildTags = [prerequisiteTag, stepTag, textTag, remarkTag];
|
||||
const importJson = ref<MinderJson>({
|
||||
root: {} as MinderJsonNode,
|
||||
template: 'default',
|
||||
@ -80,6 +96,14 @@
|
||||
});
|
||||
const caseTree = ref<MinderJsonNode[]>([]);
|
||||
const loading = ref(false);
|
||||
const tempMinderParams = ref<FeatureCaseMinderUpdateParams>({
|
||||
projectId: appStore.currentProjectId,
|
||||
versionId: '',
|
||||
updateCaseList: [],
|
||||
updateModuleList: [],
|
||||
deleteResourceList: [],
|
||||
});
|
||||
const templateId = ref('');
|
||||
|
||||
/**
|
||||
* 初始化用例模块树
|
||||
@ -99,6 +123,7 @@
|
||||
resource: e.data?.id === 'fakeNode' ? [] : [moduleTag],
|
||||
expandState: e.level === 1 ? 'expand' : 'collapse',
|
||||
count: props.modulesCount[e.id],
|
||||
isNew: false,
|
||||
},
|
||||
children:
|
||||
props.modulesCount[e.id] > 0 && !e.children?.length
|
||||
@ -108,6 +133,7 @@
|
||||
id: 'fakeNode',
|
||||
text: 'fakeNode',
|
||||
resource: ['fakeNode'],
|
||||
isNew: false,
|
||||
},
|
||||
},
|
||||
]
|
||||
@ -140,11 +166,19 @@
|
||||
projectId: appStore.currentProjectId,
|
||||
moduleId: props.moduleId === 'all' ? '' : props.moduleId,
|
||||
});
|
||||
importJson.value.root.children = res;
|
||||
importJson.value.root.children = mapTree(res, (node) => {
|
||||
return {
|
||||
...node,
|
||||
data: {
|
||||
...node.data,
|
||||
isNew: false,
|
||||
},
|
||||
};
|
||||
});
|
||||
importJson.value.root.data = {
|
||||
id: props.moduleId === 'all' ? '' : props.moduleId,
|
||||
text: props.moduleName,
|
||||
resource: [t('common.module')],
|
||||
resource: [moduleTag],
|
||||
};
|
||||
window.minder.importJson(importJson.value);
|
||||
} catch (error) {
|
||||
@ -163,15 +197,83 @@
|
||||
}
|
||||
});
|
||||
|
||||
async function handleMinderSave(data: any) {
|
||||
const baseInfoRef = ref<InstanceType<typeof baseInfo>>();
|
||||
|
||||
/**
|
||||
* 解析用例节点信息
|
||||
* @param node 用例节点
|
||||
*/
|
||||
function getCaseNodeInfo(node: MinderJsonNode) {
|
||||
let textStep: MinderJsonNode | undefined;
|
||||
let prerequisiteNode: MinderJsonNode | undefined;
|
||||
let remarkNode: MinderJsonNode | undefined;
|
||||
const stepNodes: MinderJsonNode[] = [];
|
||||
node.children?.forEach((item) => {
|
||||
if (item.data.resource?.includes(textTag)) {
|
||||
textStep = item;
|
||||
} else if (item.data.resource?.includes(stepTag)) {
|
||||
stepNodes.push(item);
|
||||
} else if (item.data.resource?.includes(prerequisiteTag)) {
|
||||
prerequisiteNode = item;
|
||||
} else if (item.data.resource?.includes(remarkTag)) {
|
||||
remarkNode = item;
|
||||
}
|
||||
});
|
||||
const steps: FeatureCaseMinderStepItem[] = stepNodes.map((child, i) => {
|
||||
return {
|
||||
id: child.data.id,
|
||||
num: i,
|
||||
desc: child.data.text,
|
||||
result: child.children?.[0].data.text || '',
|
||||
};
|
||||
});
|
||||
return {
|
||||
prerequisite: prerequisiteNode?.data.text || '',
|
||||
caseEditType: steps.length > 0 ? 'STEP' : ('TEXT' as FeatureCaseMinderEditType),
|
||||
steps,
|
||||
textDescription: textStep?.data.text || '',
|
||||
expectedResult: textStep?.children?.[0]?.data.text || '',
|
||||
description: remarkNode?.data.text || '',
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成脑图保存的入参
|
||||
*/
|
||||
function makeMinderParams(): FeatureCaseMinderUpdateParams {
|
||||
const fullJson: MinderJson = window.minder.exportJson();
|
||||
filterTree(fullJson.root.children, (node) => {
|
||||
if (node.data.isNew !== false || node.data.changed === true) {
|
||||
if (node.data.resource?.includes(moduleTag)) {
|
||||
tempMinderParams.value.updateModuleList.push({
|
||||
id: node.data.id,
|
||||
name: node.data.text,
|
||||
parentId: node.parent?.data.id || '',
|
||||
type: node.data.isNew ? 'ADD' : 'UPDATE',
|
||||
});
|
||||
} else if (node.data.resource?.includes(caseTag)) {
|
||||
const caseNodeInfo = getCaseNodeInfo(node as MinderJsonNode);
|
||||
tempMinderParams.value.updateCaseList.push({
|
||||
id: node.data.id,
|
||||
name: node.data.text,
|
||||
moduleId: node.parent?.data.id || '',
|
||||
type: node.data.isNew ? 'ADD' : 'UPDATE',
|
||||
templateId: templateId.value,
|
||||
tags: node.data.resource || [],
|
||||
customFields: baseInfoRef.value?.makeParams().customFields || [],
|
||||
...caseNodeInfo,
|
||||
});
|
||||
return false; // 用例的子孙节点已经处理过,跳过
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return tempMinderParams.value;
|
||||
}
|
||||
|
||||
async function handleMinderSave() {
|
||||
try {
|
||||
await saveCaseMinder({
|
||||
projectId: appStore.currentProjectId,
|
||||
versionId: '',
|
||||
updateCaseList: data,
|
||||
updateModuleList: [],
|
||||
deleteResourceList: [],
|
||||
});
|
||||
await saveCaseMinder(makeMinderParams());
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
@ -196,21 +298,24 @@
|
||||
if (node.data?.resource?.some((e) => descTags.includes(e))) {
|
||||
// 选中节点属于描述节点,可替换为除自身外的描述标签
|
||||
if (
|
||||
node.data.resource.includes(t('ms.minders.stepDesc')) &&
|
||||
(node.parent?.children?.filter((e) => e.data?.resource?.includes(t('ms.minders.stepDesc'))) || []).length > 1
|
||||
node.data.resource.includes(stepTag) &&
|
||||
(node.parent?.children?.filter((e) => e.data?.resource?.includes(stepTag)) || []).length > 1
|
||||
) {
|
||||
// 如果当前节点是步骤描述,则需要判断是否有其他步骤描述节点,如果有,则不可替换为文本描述
|
||||
return [];
|
||||
}
|
||||
return descTags.filter((tag) => !node.data?.resource?.includes(tag));
|
||||
}
|
||||
if ((!node.data?.resource || node.data.resource.length === 0) && node.parent?.data?.resource?.includes(caseTag)) {
|
||||
// 选中节点无标签,且父节点为用例节点,可替换用例下级标签
|
||||
return caseChildTags;
|
||||
}
|
||||
if (
|
||||
(!node.data?.resource || node.data.resource.length === 0) &&
|
||||
(!node.parent?.data?.resource ||
|
||||
node.parent?.data?.resource.length === 0 ||
|
||||
node.parent?.data?.resource?.some((e) => topTags.includes(e)))
|
||||
) {
|
||||
// 选中节点无标签,且父节点为顶级节点,可替换为顶级标签
|
||||
// 如果选中节点子级含有用例节点或模块节点,则不可将选中节点标记为用例
|
||||
return node.children &&
|
||||
(node.children.some((e) => e.data?.resource?.includes(caseTag)) ||
|
||||
@ -242,24 +347,14 @@
|
||||
parent: node,
|
||||
data: {
|
||||
id: getGenerateId(),
|
||||
text: t('ms.minders.precondition'),
|
||||
resource: [t('ms.minders.precondition')],
|
||||
text: prerequisiteTag,
|
||||
resource: [prerequisiteTag],
|
||||
expandState: 'expand',
|
||||
isNew: true,
|
||||
},
|
||||
children: [],
|
||||
};
|
||||
const sibling = {
|
||||
parent: child,
|
||||
data: {
|
||||
id: getGenerateId(),
|
||||
text: '',
|
||||
resource: [],
|
||||
},
|
||||
};
|
||||
execInert(type, child.data);
|
||||
nextTick(() => {
|
||||
execInert('AppendChildNode', sibling.data);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -272,38 +367,15 @@
|
||||
parent: node,
|
||||
data: {
|
||||
id: getGenerateId(),
|
||||
text: t('common.remark'),
|
||||
resource: [t('common.remark')],
|
||||
text: remarkTag,
|
||||
resource: [remarkTag],
|
||||
isNew: true,
|
||||
},
|
||||
children: [],
|
||||
};
|
||||
execInert(type, child.data);
|
||||
}
|
||||
|
||||
// function insertTextDesc(node: MinderJsonNode, type: string) {
|
||||
// const child = {
|
||||
// parent: node,
|
||||
// data: {
|
||||
// id: getGenerateId(),
|
||||
// text: t('ms.minders.textDesc'),
|
||||
// resource: [t('ms.minders.textDesc')],
|
||||
// },
|
||||
// children: [],
|
||||
// };
|
||||
// const sibling = {
|
||||
// parent: child,
|
||||
// data: {
|
||||
// id: getGenerateId(),
|
||||
// text: t('ms.minders.stepExpect'),
|
||||
// resource: [t('ms.minders.stepExpect')],
|
||||
// },
|
||||
// };
|
||||
// execInert(type, {
|
||||
// ...child,
|
||||
// children: [sibling],
|
||||
// });
|
||||
// }
|
||||
|
||||
/**
|
||||
* 插入步骤描述
|
||||
* @param node 目标节点
|
||||
@ -316,6 +388,7 @@
|
||||
id: getGenerateId(),
|
||||
text: t('ms.minders.stepDesc'),
|
||||
resource: [t('ms.minders.stepDesc')],
|
||||
isNew: true,
|
||||
},
|
||||
children: [],
|
||||
};
|
||||
@ -325,6 +398,7 @@
|
||||
id: getGenerateId(),
|
||||
text: t('ms.minders.stepExpect'),
|
||||
resource: [t('ms.minders.stepExpect')],
|
||||
isNew: true,
|
||||
},
|
||||
};
|
||||
execInert(type, child.data);
|
||||
@ -345,6 +419,7 @@
|
||||
id: getGenerateId(),
|
||||
text: t('ms.minders.stepExpect'),
|
||||
resource: [t('ms.minders.stepExpect')],
|
||||
isNew: true,
|
||||
},
|
||||
children: [],
|
||||
};
|
||||
@ -373,11 +448,11 @@
|
||||
let hasRemark = false;
|
||||
for (let i = 0; i < node.children.length; i++) {
|
||||
const child = node.children[i];
|
||||
if (child.data?.resource?.includes(t('ms.minders.precondition'))) {
|
||||
if (child.data?.resource?.includes(prerequisiteTag)) {
|
||||
hasPreCondition = true;
|
||||
} else if (child.data?.resource?.includes(t('ms.minders.textDesc'))) {
|
||||
} else if (child.data?.resource?.includes(textTag)) {
|
||||
hasTextDesc = true;
|
||||
} else if (child.data?.resource?.includes(t('common.remark'))) {
|
||||
} else if (child.data?.resource?.includes(remarkTag)) {
|
||||
hasRemark = true;
|
||||
}
|
||||
}
|
||||
@ -393,20 +468,16 @@
|
||||
}
|
||||
}
|
||||
} else if (
|
||||
(node.data?.resource?.includes(t('ms.minders.stepDesc')) ||
|
||||
node.data?.resource?.includes(t('ms.minders.textDesc'))) &&
|
||||
(node.data?.resource?.includes(stepTag) || node.data?.resource?.includes(textTag)) &&
|
||||
(!node.children || node.children.length === 0)
|
||||
) {
|
||||
// 当前节点是步骤描述或文本描述,且没有子节点,则默认添加一个预期结果
|
||||
insertExpect(node, 'AppendChildNode');
|
||||
} else if (node.data?.resource?.includes(t('ms.minders.precondition'))) {
|
||||
} else if (node.data?.resource?.includes(prerequisiteTag) && (!node.children || node.children.length === 0)) {
|
||||
// 当前节点是前置条件,则默认添加一个文本节点
|
||||
execInert('AppendChildNode');
|
||||
}
|
||||
break;
|
||||
case 'AppendParentNode':
|
||||
execInert('AppendParentNode');
|
||||
break;
|
||||
case 'AppendSiblingNode':
|
||||
if (node.parent?.data?.resource?.includes(caseTag) && node.parent?.children) {
|
||||
// 当前节点的父节点是用例
|
||||
@ -415,11 +486,11 @@
|
||||
let hasRemark = false;
|
||||
for (let i = 0; i < node.parent.children.length; i++) {
|
||||
const sibling = node.parent.children[i];
|
||||
if (sibling.data?.resource?.includes(t('ms.minders.precondition'))) {
|
||||
if (sibling.data?.resource?.includes(prerequisiteTag)) {
|
||||
hasPreCondition = true;
|
||||
} else if (sibling.data?.resource?.includes(t('common.remark'))) {
|
||||
} else if (sibling.data?.resource?.includes(remarkTag)) {
|
||||
hasRemark = true;
|
||||
} else if (sibling.data?.resource?.includes(t('ms.minders.textDesc'))) {
|
||||
} else if (sibling.data?.resource?.includes(textTag)) {
|
||||
hasTextDesc = true;
|
||||
}
|
||||
}
|
||||
@ -460,10 +531,39 @@
|
||||
*/
|
||||
function afterTagEdit(node: MinderJsonNode, tag: string) {
|
||||
if (tag === moduleTag && node.data) {
|
||||
// 排除是从用例节点切换到模块节点的数据
|
||||
tempMinderParams.value.updateCaseList = tempMinderParams.value.updateCaseList.filter(
|
||||
(e) => e.id !== node.data.id
|
||||
);
|
||||
// tempMinderParams.value.updateModuleList.push({
|
||||
// id: node.data.id,
|
||||
// name: node.data.text,
|
||||
// type: 'ADD',
|
||||
// parentId: node.parent?.data.id || '',
|
||||
// });
|
||||
window.minder.execCommand('priority');
|
||||
} else if (node.data.resource?.includes(caseTag)) {
|
||||
// 排除是从模块节点切换到用例节点的数据
|
||||
tempMinderParams.value.updateModuleList = tempMinderParams.value.updateModuleList.filter(
|
||||
(e) => e.id !== node.data.id
|
||||
);
|
||||
// tempMinderParams.value.updateCaseList.push({
|
||||
// id: node.data.id,
|
||||
// name: node.data.text,
|
||||
// moduleId: node.parent?.data.id || '',
|
||||
// type: 'ADD',
|
||||
// templateId: templateId.value,
|
||||
// prerequisite: '',
|
||||
// caseEditType: 'STEP',
|
||||
// steps: [],
|
||||
// textDescription: '',
|
||||
// expectedResult: '',
|
||||
// description: '',
|
||||
// tags: [],
|
||||
// customFields: [],
|
||||
// });
|
||||
}
|
||||
}
|
||||
|
||||
const baseInfoLoading = ref(false);
|
||||
|
||||
const formRules = ref<FormItem[]>([]);
|
||||
@ -562,6 +662,24 @@
|
||||
resetExtractInfo();
|
||||
}
|
||||
|
||||
function handleContentChange(node: MinderJsonNode) {
|
||||
const { resource } = node.data;
|
||||
// 用例下的子节点更改,触发用例更改
|
||||
if (
|
||||
resource?.includes(prerequisiteTag) ||
|
||||
resource?.includes(stepTag) ||
|
||||
resource?.includes(textTag) ||
|
||||
resource?.includes(remarkTag)
|
||||
) {
|
||||
if (node.parent) {
|
||||
node.parent.data.changed = true;
|
||||
}
|
||||
} else if (node.parent?.parent?.data.resource?.includes(caseTag)) {
|
||||
// 用例下子节点的子节点更改,触发用例更改
|
||||
node.parent.parent.data.changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理脑图节点激活/点击
|
||||
* @param node 被激活/点击的节点
|
||||
@ -594,15 +712,33 @@
|
||||
// TODO:递归渲染存在的子节点
|
||||
res.forEach((e) => {
|
||||
// 用例节点
|
||||
const child = window.minder.createNode(e.data, node);
|
||||
const child = window.minder.createNode(
|
||||
{
|
||||
...e.data,
|
||||
isNew: false,
|
||||
},
|
||||
node
|
||||
);
|
||||
child.render();
|
||||
e.children?.forEach((item) => {
|
||||
// 前置/步骤/备注节点
|
||||
const grandChild = window.minder.createNode(item.data, child);
|
||||
const grandChild = window.minder.createNode(
|
||||
{
|
||||
...item.data,
|
||||
isNew: false,
|
||||
},
|
||||
child
|
||||
);
|
||||
grandChild.render();
|
||||
item.children?.forEach((subItem) => {
|
||||
// 预期结果节点
|
||||
const greatGrandChild = window.minder.createNode(subItem.data, grandChild);
|
||||
const greatGrandChild = window.minder.createNode(
|
||||
{
|
||||
...subItem.data,
|
||||
isNew: false,
|
||||
},
|
||||
grandChild
|
||||
);
|
||||
greatGrandChild.render();
|
||||
});
|
||||
});
|
||||
@ -626,6 +762,37 @@
|
||||
resetExtractInfo();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理脑图节点操作
|
||||
* @param event 脑图事件对象
|
||||
*/
|
||||
function handleAction(event: MinderEvent) {
|
||||
const { node, name } = event;
|
||||
if (node) {
|
||||
switch (name) {
|
||||
case MinderEventName.DELETE_NODE:
|
||||
tempMinderParams.value.deleteResourceList.push({
|
||||
id: node.data.id,
|
||||
type: node.data?.resource?.[0] || moduleTag,
|
||||
});
|
||||
if (node.data?.resource?.includes(caseTag)) {
|
||||
// 删除用例节点
|
||||
tempMinderParams.value.updateCaseList = tempMinderParams.value.updateCaseList.filter(
|
||||
(e) => e.id !== node.data.id
|
||||
);
|
||||
} else if (node.data?.resource?.includes(moduleTag)) {
|
||||
// 删除模块节点
|
||||
tempMinderParams.value.updateModuleList = tempMinderParams.value.updateModuleList.filter(
|
||||
(e) => e.id !== node.data.id
|
||||
);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
@ -0,0 +1 @@
|
||||
export default function useShortCut() {}
|
@ -19,12 +19,6 @@
|
||||
<div class="ml-[4px] text-[var(--color-text-4)]">( / )</div>
|
||||
</div>
|
||||
</a-doption>
|
||||
<a-doption value="insetParent">
|
||||
<div class="flex items-center">
|
||||
<div>{{ t('minder.hotboxMenu.insetParent') }}</div>
|
||||
<div class="ml-[4px] text-[var(--color-text-4)]">(Shift + Tab)</div>
|
||||
</div>
|
||||
</a-doption>
|
||||
<a-doption value="insetSon">
|
||||
<div class="flex items-center">
|
||||
<div>{{ t('minder.hotboxMenu.insetSon') }}</div>
|
||||
@ -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<HTMLDivElement | null> = 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);
|
||||
|
@ -15,10 +15,15 @@
|
||||
<script lang="ts" name="TagBox" setup>
|
||||
import { nextTick, onMounted, reactive, ref } from 'vue';
|
||||
|
||||
import useMinderStore from '@/store/modules/components/minder-editor';
|
||||
|
||||
import { MinderEventName } from '@/enums/minderEnum';
|
||||
|
||||
import { MinderJsonNode, tagProps } from '../../props';
|
||||
import { isDisableNode, isTagEnable } from '../../script/tool/utils';
|
||||
|
||||
const props = defineProps(tagProps);
|
||||
const minderStore = useMinderStore();
|
||||
|
||||
let minder = reactive<any>({});
|
||||
const commandDisabled = ref(true);
|
||||
@ -94,6 +99,7 @@
|
||||
}
|
||||
window.minder.execCommand('resource', origin);
|
||||
const node: MinderJsonNode = minder.getSelectedNode();
|
||||
minderStore.dispatchEvent(MinderEventName.SET_TAG, undefined, undefined, node);
|
||||
if (props.replaceableTags) {
|
||||
tagList.value = props.replaceableTags(node);
|
||||
}
|
||||
|
@ -63,14 +63,14 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" name="minderEditor" setup>
|
||||
import { debounce } from 'lodash-es';
|
||||
|
||||
import MsTab from '@/components/pure/ms-tab/index.vue';
|
||||
import minderHeader from './main/header.vue';
|
||||
import mainEditor from './main/mainEditor.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { MinderEvent } from '@/store/modules/components/minder-editor/types';
|
||||
|
||||
import useEventListener from './hooks/useEventListener';
|
||||
import {
|
||||
delProps,
|
||||
editMenuProps,
|
||||
@ -88,8 +88,10 @@
|
||||
(e: 'moldChange', data: number): void;
|
||||
(e: 'save', data: Record<string, any>): void;
|
||||
(e: 'afterMount'): void;
|
||||
(e: 'enterNode', data: any): void;
|
||||
(e: 'nodeSelect', data: any): void;
|
||||
(e: 'enterNode', data: MinderJsonNode): void;
|
||||
(e: 'nodeSelect', data: MinderJsonNode): void;
|
||||
(e: 'contentChange', data: MinderJsonNode): void;
|
||||
(e: 'action', event: MinderEvent): void;
|
||||
}>();
|
||||
|
||||
const props = defineProps({
|
||||
@ -133,18 +135,19 @@
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
if (window.minder.on) {
|
||||
window.minder.on(
|
||||
'selectionchange',
|
||||
debounce(() => {
|
||||
const selectedNode: MinderJsonNode = window.minder.getSelectedNode();
|
||||
if (Object.keys(window.minder).length > 0 && selectedNode) {
|
||||
emit('nodeSelect', selectedNode);
|
||||
}
|
||||
}, 300)
|
||||
);
|
||||
}
|
||||
useEventListener({
|
||||
handleSelectionChange: () => {
|
||||
const selectedNode: MinderJsonNode = window.minder.getSelectedNode();
|
||||
if (Object.keys(window.minder).length > 0 && selectedNode) {
|
||||
emit('nodeSelect', selectedNode);
|
||||
}
|
||||
},
|
||||
handleContentChange: (node: MinderJsonNode) => {
|
||||
emit('contentChange', node);
|
||||
},
|
||||
handleMinderEvent: (event) => {
|
||||
emit('action', event);
|
||||
},
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
@ -16,6 +16,8 @@ export interface MinderJsonNodeData {
|
||||
expandState?: 'collapse' | 'expand';
|
||||
priority?: number;
|
||||
// 前端渲染字段
|
||||
isNew?: boolean; // 是否脑图新增节点,需要在初始化脑图数据时标记已存在节点为 false 以区分是否新增节点
|
||||
changed?: boolean; // 脑图节点是否发生过变化
|
||||
[key: string]: any;
|
||||
}
|
||||
export interface MinderJsonNode {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 {};
|
||||
|
@ -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[];
|
||||
}
|
||||
|
@ -16,14 +16,14 @@
|
||||
@refresh="fetchData()"
|
||||
>
|
||||
<template #right>
|
||||
<!-- <a-radio-group v-model:model-value="showType" type="button" size="small" class="list-show-type">
|
||||
<a-radio-group v-model:model-value="showType" type="button" size="small" class="list-show-type">
|
||||
<a-radio value="list" class="show-type-icon !m-[2px]">
|
||||
<MsIcon :size="14" type="icon-icon_view-list_outlined" />
|
||||
</a-radio>
|
||||
<a-radio value="xMind" class="show-type-icon !m-[2px]">
|
||||
<MsIcon :size="14" type="icon-icon_mindnote_outlined" />
|
||||
</a-radio>
|
||||
</a-radio-group> -->
|
||||
</a-radio-group>
|
||||
</template>
|
||||
</MsAdvanceFilter>
|
||||
<ms-base-table
|
||||
|
@ -64,31 +64,29 @@
|
||||
width: 400px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.login-qrcode {
|
||||
min-width: 480px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
margin-top: 24px;
|
||||
min-width: 480px;
|
||||
flex-direction: column;
|
||||
.qrcode {
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 0px 0 16px 0;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
margin: 0 0 16px;
|
||||
font-size: 18px;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
line-height: 26px;
|
||||
.ed-icon {
|
||||
margin-right: 8px;
|
||||
|
@ -39,10 +39,10 @@
|
||||
state: 'fit2cloud-wecom-qr',
|
||||
redirect_type: WWLoginRedirectType.callback,
|
||||
},
|
||||
onCheckWeComLogin({ isWeComLogin }) {
|
||||
onCheckWeComLogin({ isWeComLogin }: any) {
|
||||
console.log(isWeComLogin);
|
||||
},
|
||||
async onLoginSuccess({ code }) {
|
||||
async onLoginSuccess({ code }: any) {
|
||||
const weComCallback = getWeComCallback(code);
|
||||
userStore.qrCodeLogin(await weComCallback);
|
||||
Message.success(t('login.form.login.success'));
|
||||
@ -71,7 +71,7 @@
|
||||
},
|
||||
});
|
||||
},
|
||||
onLoginFail(err) {
|
||||
onLoginFail(err: any) {
|
||||
console.log(err);
|
||||
},
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user