feat(功能用例): 脑图保存

This commit is contained in:
baiqi 2024-05-31 16:57:05 +08:00 committed by 刘瑞斌
parent 14dc8d1d56
commit 06d3a96ef5
15 changed files with 396 additions and 149 deletions

View File

@ -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 });
}

View File

@ -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>

View File

@ -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>

View File

@ -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);
}
}
);
}

View File

@ -0,0 +1 @@
export default function useShortCut() {}

View File

@ -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);

View File

@ -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);
}

View File

@ -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>

View File

@ -16,6 +16,8 @@ export interface MinderJsonNodeData {
expandState?: 'collapse' | 'expand';
priority?: number;
// 前端渲染字段
isNew?: boolean; // 是否脑图新增节点,需要在初始化脑图数据时标记已存在节点为 false 以区分是否新增节点
changed?: boolean; // 脑图节点是否发生过变化
[key: string]: any;
}
export interface MinderJsonNode {

View File

@ -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;
}

View File

@ -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 {};

View File

@ -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[];
}

View File

@ -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

View File

@ -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;

View File

@ -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);
},
});