fix(全局): 部分 bug 修复
This commit is contained in:
parent
1b26df9c2d
commit
33929d6978
|
@ -85,7 +85,6 @@
|
||||||
} from '@/api/modules/case-management/featureCase';
|
} from '@/api/modules/case-management/featureCase';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useAppStore from '@/store/modules/app';
|
import useAppStore from '@/store/modules/app';
|
||||||
import useFeatureCaseStore from '@/store/modules/case/featureCase';
|
|
||||||
import useMinderStore from '@/store/modules/components/minder-editor/index';
|
import useMinderStore from '@/store/modules/components/minder-editor/index';
|
||||||
import { MinderCustomEvent } from '@/store/modules/components/minder-editor/types';
|
import { MinderCustomEvent } from '@/store/modules/components/minder-editor/types';
|
||||||
import { filterTree, getGenerateId, mapTree, replaceNodeInTree } from '@/utils';
|
import { filterTree, getGenerateId, mapTree, replaceNodeInTree } from '@/utils';
|
||||||
|
@ -160,60 +159,66 @@
|
||||||
async function initCaseTree(notRemote = false) {
|
async function initCaseTree(notRemote = false) {
|
||||||
try {
|
try {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
let res: MinderJsonNode[];
|
if (!notRemote) {
|
||||||
if (notRemote) {
|
const res = await getCaseMinderTree({
|
||||||
res = caseTree.value;
|
|
||||||
} else {
|
|
||||||
res = await getCaseMinderTree({
|
|
||||||
projectId: appStore.currentProjectId,
|
projectId: appStore.currentProjectId,
|
||||||
moduleId: '', // 始终加载全部,然后再进入对应的模块节点
|
moduleId: '', // 始终加载全部,然后再进入对应的模块节点
|
||||||
});
|
});
|
||||||
}
|
caseTree.value = mapTree<MinderJsonNode>(res, (e) => ({
|
||||||
caseTree.value = mapTree<MinderJsonNode>(res, (e) => ({
|
...e,
|
||||||
...e,
|
data: {
|
||||||
data: {
|
...e.data,
|
||||||
id: e.id,
|
id: e.id || e.data?.id || '',
|
||||||
text: e.name,
|
text: e.name || e.data?.text || '',
|
||||||
resource: props.modulesCount[e.id] !== undefined ? [moduleTag] : e.data?.resource,
|
resource: props.modulesCount[e.id] !== undefined ? [moduleTag] : e.data?.resource,
|
||||||
expandState: e.level === 1 ? 'expand' : 'collapse',
|
expandState: e.level === 1 ? 'expand' : 'collapse',
|
||||||
count: props.modulesCount[e.id],
|
count: props.modulesCount[e.id],
|
||||||
isNew: false,
|
isNew: false,
|
||||||
changed: false,
|
changed: false,
|
||||||
},
|
},
|
||||||
children:
|
children:
|
||||||
props.modulesCount[e.id] > 0 && !e.children?.length
|
props.modulesCount[e.id] > 0 && !e.children?.length
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
data: {
|
data: {
|
||||||
id: 'fakeNode',
|
id: 'fakeNode',
|
||||||
text: 'fakeNode',
|
text: 'fakeNode',
|
||||||
resource: ['fakeNode'],
|
resource: ['fakeNode'],
|
||||||
isNew: false,
|
isNew: false,
|
||||||
changed: false,
|
changed: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
]
|
||||||
]
|
: e.children,
|
||||||
: e.children,
|
}));
|
||||||
}));
|
importJson.value.root = {
|
||||||
importJson.value.root = {
|
children: caseTree.value,
|
||||||
children: caseTree.value,
|
data: {
|
||||||
data: {
|
id: 'NONE',
|
||||||
id: 'NONE',
|
text: t('ms.minders.allModule'),
|
||||||
text: t('ms.minders.allModule'),
|
resource: [moduleTag],
|
||||||
resource: [moduleTag],
|
disabled: true,
|
||||||
disabled: true,
|
},
|
||||||
},
|
};
|
||||||
};
|
importJson.value.treePath = [];
|
||||||
importJson.value.treePath = [];
|
window.minder.importJson(importJson.value);
|
||||||
window.minder.importJson(importJson.value);
|
}
|
||||||
window.minder.execCommand('camera', window.minder.getRoot(), 100);
|
if (notRemote) {
|
||||||
if (props.moduleId !== 'all') {
|
if (props.moduleId !== 'all') {
|
||||||
// 携带具体的模块 ID 加载时,进入该模块内
|
// 携带具体的模块 ID 加载时,进入该模块内
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
minderStore.dispatchEvent(MinderEventName.ENTER_NODE, undefined, undefined, undefined, [
|
minderStore.dispatchEvent(MinderEventName.ENTER_NODE, undefined, undefined, undefined, [
|
||||||
window.minder.getNodeById(props.moduleId),
|
window.minder.getNodeById(props.moduleId),
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
// 携带具体的模块 ID 加载时,进入该模块内
|
||||||
|
nextTick(() => {
|
||||||
|
minderStore.dispatchEvent(MinderEventName.ENTER_NODE, undefined, undefined, undefined, [
|
||||||
|
importJson.value.root,
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
|
@ -391,12 +396,13 @@
|
||||||
if ((!res || res.length === 0) && node.children?.length) {
|
if ((!res || res.length === 0) && node.children?.length) {
|
||||||
// 如果模块下没有用例且有别的模块节点,正常展开
|
// 如果模块下没有用例且有别的模块节点,正常展开
|
||||||
node.expand();
|
node.expand();
|
||||||
node.renderTree();
|
window.minder.renderNodeBatch(node.children);
|
||||||
node.layout();
|
node.layout();
|
||||||
|
data.isLoaded = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// TODO:递归渲染存在的子节点
|
// TODO:递归渲染存在的子节点
|
||||||
const waitingRenderNodes: MinderJsonNode[] = [];
|
let waitingRenderNodes: MinderJsonNode[] = [];
|
||||||
res.forEach((e) => {
|
res.forEach((e) => {
|
||||||
// 用例节点
|
// 用例节点
|
||||||
const child = window.minder.createNode(
|
const child = window.minder.createNode(
|
||||||
|
@ -439,14 +445,14 @@
|
||||||
});
|
});
|
||||||
node.expand();
|
node.expand();
|
||||||
// node.renderTree();
|
// node.renderTree();
|
||||||
|
if (node.children && node.children.length > 0) {
|
||||||
|
waitingRenderNodes = waitingRenderNodes.concat(node.children);
|
||||||
|
}
|
||||||
window.minder.renderNodeBatch(waitingRenderNodes);
|
window.minder.renderNodeBatch(waitingRenderNodes);
|
||||||
node.layout();
|
node.layout();
|
||||||
window.minder.execCommand('camera', node, 100);
|
data.isLoaded = true;
|
||||||
if (node.data) {
|
|
||||||
node.data.isLoaded = true;
|
|
||||||
}
|
|
||||||
// 加载完用例数据后,更新当前importJson数据
|
// 加载完用例数据后,更新当前importJson数据
|
||||||
replaceNodeInTree([importJson.value.root], node.data?.id || '', node, 'data', 'id');
|
replaceNodeInTree([importJson.value.root], node.data?.id || '', window.minder.exportNode(node), 'data', 'id');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
@ -458,11 +464,6 @@
|
||||||
extraVisible.value = false;
|
extraVisible.value = false;
|
||||||
showDetailMenu.value = false;
|
showDetailMenu.value = false;
|
||||||
resetExtractInfo();
|
resetExtractInfo();
|
||||||
if (node.children && node.children.length > 0 && node.data?.expandState === 'collapse') {
|
|
||||||
node.expand();
|
|
||||||
node.renderTree();
|
|
||||||
node.layout();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
setPriorityView(true, 'P');
|
setPriorityView(true, 'P');
|
||||||
}
|
}
|
||||||
|
@ -524,7 +525,7 @@
|
||||||
if (!caseOffspringTags.some((e) => node.data?.resource?.includes(e))) {
|
if (!caseOffspringTags.some((e) => node.data?.resource?.includes(e))) {
|
||||||
// 非用例下的子孙节点的移除,才加入删除资源队列
|
// 非用例下的子孙节点的移除,才加入删除资源队列
|
||||||
tempMinderParams.value.deleteResourceList.push({
|
tempMinderParams.value.deleteResourceList.push({
|
||||||
id: node.data?.id || getGenerateId(),
|
id: node.data?.id || '',
|
||||||
type: node.data?.resource?.[0] || moduleTag,
|
type: node.data?.resource?.[0] || moduleTag,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -556,12 +557,12 @@
|
||||||
* 解析用例节点信息
|
* 解析用例节点信息
|
||||||
* @param node 用例节点
|
* @param node 用例节点
|
||||||
*/
|
*/
|
||||||
function getCaseNodeInfo(node: MinderJsonNode) {
|
function getCaseNodeInfo(node?: MinderJsonNode) {
|
||||||
let textStep: MinderJsonNode | undefined; // 文本描述
|
let textStep: MinderJsonNode | undefined; // 文本描述
|
||||||
let prerequisiteNode: MinderJsonNode | undefined; // 前置条件
|
let prerequisiteNode: MinderJsonNode | undefined; // 前置条件
|
||||||
let remarkNode: MinderJsonNode | undefined; // 备注
|
let remarkNode: MinderJsonNode | undefined; // 备注
|
||||||
const stepNodes: MinderJsonNode[] = []; // 步骤描述
|
const stepNodes: MinderJsonNode[] = []; // 步骤描述
|
||||||
node.children?.forEach((item) => {
|
node?.children?.forEach((item) => {
|
||||||
if (item.data?.resource?.includes(textDescTag)) {
|
if (item.data?.resource?.includes(textDescTag)) {
|
||||||
textStep = item;
|
textStep = item;
|
||||||
} else if (item.data?.resource?.includes(stepTag)) {
|
} else if (item.data?.resource?.includes(stepTag)) {
|
||||||
|
@ -577,7 +578,7 @@
|
||||||
id: child.data?.id || getGenerateId(),
|
id: child.data?.id || getGenerateId(),
|
||||||
num: i,
|
num: i,
|
||||||
desc: child.data?.text || '',
|
desc: child.data?.text || '',
|
||||||
result: child.children?.[0].data?.text || '',
|
result: child.children?.[0]?.data?.text || '',
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
|
@ -587,7 +588,7 @@
|
||||||
textDescription: textStep?.data?.text || '',
|
textDescription: textStep?.data?.text || '',
|
||||||
expectedResult: textStep?.children?.[0]?.data?.text || '',
|
expectedResult: textStep?.children?.[0]?.data?.text || '',
|
||||||
description: remarkNode?.data?.text || '',
|
description: remarkNode?.data?.text || '',
|
||||||
priority: node.data?.priority,
|
priority: node?.data?.priority,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -612,6 +613,17 @@
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resetMinderParams() {
|
||||||
|
tempMinderParams.value = {
|
||||||
|
projectId: appStore.currentProjectId,
|
||||||
|
versionId: '',
|
||||||
|
updateCaseList: [],
|
||||||
|
updateModuleList: [],
|
||||||
|
deleteResourceList: [],
|
||||||
|
additionalNodeList: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成脑图保存的入参
|
* 生成脑图保存的入参
|
||||||
*/
|
*/
|
||||||
|
@ -675,28 +687,20 @@
|
||||||
await saveCaseMinder(makeMinderParams(fullJson));
|
await saveCaseMinder(makeMinderParams(fullJson));
|
||||||
extraVisible.value = false;
|
extraVisible.value = false;
|
||||||
Message.success(t('common.saveSuccess'));
|
Message.success(t('common.saveSuccess'));
|
||||||
tempMinderParams.value = {
|
resetMinderParams();
|
||||||
projectId: appStore.currentProjectId,
|
|
||||||
versionId: '',
|
|
||||||
updateCaseList: [],
|
|
||||||
updateModuleList: [],
|
|
||||||
deleteResourceList: [],
|
|
||||||
additionalNodeList: [],
|
|
||||||
};
|
|
||||||
emit('save');
|
emit('save');
|
||||||
callback();
|
callback();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
resetMinderParams();
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const featureCaseStore = useFeatureCaseStore();
|
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => featureCaseStore.modulesCount,
|
() => props.moduleId,
|
||||||
() => {
|
() => {
|
||||||
initCaseTree(true);
|
initCaseTree(true);
|
||||||
},
|
},
|
||||||
|
|
|
@ -259,9 +259,10 @@ export default function useMinderBaseApi({ hasEditPermission }: { hasEditPermiss
|
||||||
if (
|
if (
|
||||||
Object.keys(node.data || {}).length === 0 ||
|
Object.keys(node.data || {}).length === 0 ||
|
||||||
node.data?.id === 'root' ||
|
node.data?.id === 'root' ||
|
||||||
(node.parent?.data?.resource || []).length === 0
|
(node.parent?.data?.resource || []).length === 0 ||
|
||||||
|
node.parent?.data?.id === 'NONE'
|
||||||
) {
|
) {
|
||||||
// 没有数据的节点、默认模块节点、父节点为文本节点的节点不可替换标签
|
// 没有数据的节点、默认模块节点、父节点为文本节点、父节点为NONE虚拟根节点的节点不可替换标签
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
if (node.data?.resource?.some((e) => topTags.includes(e))) {
|
if (node.data?.resource?.some((e) => topTags.includes(e))) {
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
:can-show-priority-menu="false"
|
:can-show-priority-menu="false"
|
||||||
:can-show-float-menu="canShowFloatMenu"
|
:can-show-float-menu="canShowFloatMenu"
|
||||||
:can-show-delete-menu="canShowDeleteMenu"
|
:can-show-delete-menu="canShowDeleteMenu"
|
||||||
:disable="!hasEditPermission"
|
:disabled="!hasEditPermission"
|
||||||
custom-priority
|
custom-priority
|
||||||
single-tag
|
single-tag
|
||||||
tag-enable
|
tag-enable
|
||||||
|
@ -86,7 +86,7 @@
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</div>
|
</div>
|
||||||
<a-form ref="configFormRef" :model="configForm" :disabled="!hasEditPermission" layout="vertical">
|
<a-form ref="configFormRef" :model="configForm" :disabled="!hasEditPermission" layout="vertical">
|
||||||
<a-form-item v-if="hasEditPermission">
|
<a-form-item v-if="hasEditPermission && configForm.level === 2">
|
||||||
<template #label>
|
<template #label>
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<div>{{ t('testPlan.planForm.pickCases') }}</div>
|
<div>{{ t('testPlan.planForm.pickCases') }}</div>
|
||||||
|
@ -127,27 +127,37 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<template
|
<template v-if="configForm.type !== PlanMinderCollectionType.FUNCTIONAL">
|
||||||
v-if="
|
|
||||||
configForm.type !== PlanMinderCollectionType.FUNCTIONAL &&
|
|
||||||
(configForm.level === 1 || !configForm.extended)
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<a-form-item :label="t('system.project.resourcePool')">
|
<a-form-item :label="t('system.project.resourcePool')">
|
||||||
<a-select v-model:model-value="configForm.testResourcePoolId" :options="resourcePoolOptions"></a-select>
|
<a-select
|
||||||
|
v-model:model-value="configForm.testResourcePoolId"
|
||||||
|
:options="resourcePoolOptions"
|
||||||
|
:disabled="configForm.level === 2 && configForm.extended"
|
||||||
|
></a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item :label="t('project.environmental.env')">
|
<a-form-item :label="t('project.environmental.env')">
|
||||||
<a-select v-model:model-value="configForm.environmentId" :options="environmentOptions"></a-select>
|
<a-select
|
||||||
|
v-model:model-value="configForm.environmentId"
|
||||||
|
:options="environmentOptions"
|
||||||
|
:disabled="configForm.level === 2 && configForm.extended"
|
||||||
|
></a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item class="hidden-item">
|
<a-form-item class="hidden-item">
|
||||||
<a-radio-group v-model:model-value="configForm.executeMethod">
|
<a-radio-group
|
||||||
|
v-model:model-value="configForm.executeMethod"
|
||||||
|
:disabled="configForm.level === 2 && configForm.extended"
|
||||||
|
>
|
||||||
<a-radio :value="RunMode.SERIAL">{{ t('testPlan.testPlanIndex.serial') }}</a-radio>
|
<a-radio :value="RunMode.SERIAL">{{ t('testPlan.testPlanIndex.serial') }}</a-radio>
|
||||||
<a-radio :value="RunMode.PARALLEL">{{ t('testPlan.testPlanIndex.parallel') }}</a-radio>
|
<a-radio :value="RunMode.PARALLEL">{{ t('testPlan.testPlanIndex.parallel') }}</a-radio>
|
||||||
</a-radio-group>
|
</a-radio-group>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item v-if="configForm.executeMethod === RunMode.SERIAL" class="hidden-item">
|
<a-form-item v-if="configForm.executeMethod === RunMode.SERIAL" class="hidden-item">
|
||||||
<div class="flex items-center gap-[8px]">
|
<div class="flex items-center gap-[8px]">
|
||||||
<a-switch v-model:model-value="configForm.stopOnFail" size="small"></a-switch>
|
<a-switch
|
||||||
|
v-model:model-value="configForm.stopOnFail"
|
||||||
|
size="small"
|
||||||
|
:disabled="configForm.level === 2 && configForm.extended"
|
||||||
|
></a-switch>
|
||||||
<div>{{ t('ms.minders.failStop') }}</div>
|
<div>{{ t('ms.minders.failStop') }}</div>
|
||||||
</div>
|
</div>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
@ -206,7 +216,7 @@
|
||||||
class="hidden-item"
|
class="hidden-item"
|
||||||
>
|
>
|
||||||
<div class="flex items-center gap-[8px]">
|
<div class="flex items-center gap-[8px]">
|
||||||
<a-switch v-model:model-value="configForm.extended" size="small"></a-switch>
|
<a-switch v-model:model-value="configForm.extended" size="small" @change="handleExtendChange"></a-switch>
|
||||||
<div>{{ t('ms.minders.extend') }}</div>
|
<div>{{ t('ms.minders.extend') }}</div>
|
||||||
</div>
|
</div>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
@ -270,6 +280,7 @@
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
planId: string;
|
planId: string;
|
||||||
|
status: string;
|
||||||
}>();
|
}>();
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'save'): void;
|
(e: 'save'): void;
|
||||||
|
@ -297,7 +308,9 @@
|
||||||
const showConfigMenu = ref(false);
|
const showConfigMenu = ref(false);
|
||||||
const canShowDeleteMenu = ref(false);
|
const canShowDeleteMenu = ref(false);
|
||||||
const extraVisible = ref<boolean>(false);
|
const extraVisible = ref<boolean>(false);
|
||||||
const hasEditPermission = hasAnyPermission(['PROJECT_TEST_PLAN:READ+UPDATE']);
|
const hasEditPermission = computed(
|
||||||
|
() => props.status !== 'ARCHIVED' && hasAnyPermission(['PROJECT_TEST_PLAN:READ+UPDATE'])
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检测节点可展示的菜单项
|
* 检测节点可展示的菜单项
|
||||||
|
@ -306,13 +319,18 @@
|
||||||
function checkNodeCanShowMenu(node: PlanMinderNode) {
|
function checkNodeCanShowMenu(node: PlanMinderNode) {
|
||||||
const { data } = node;
|
const { data } = node;
|
||||||
|
|
||||||
if (!hasEditPermission && (data?.level === 1 || data?.level === 2)) {
|
if (!hasEditPermission.value && (data?.level === 1 || data?.level === 2)) {
|
||||||
// 没有编辑权限,只能查看配置菜单(功能用例只有关联用例,所以配置菜单也不能看)
|
// 没有编辑权限,只能查看配置菜单(功能用例只有关联用例,所以配置菜单也不能看)
|
||||||
if (data?.type === PlanMinderCollectionType.FUNCTIONAL) {
|
if (data?.type === PlanMinderCollectionType.FUNCTIONAL) {
|
||||||
canShowFloatMenu.value = false;
|
canShowFloatMenu.value = false;
|
||||||
} else {
|
} else {
|
||||||
canShowFloatMenu.value = true;
|
canShowFloatMenu.value = true;
|
||||||
showConfigMenu.value = true;
|
showConfigMenu.value = true;
|
||||||
|
showAssociateCaseMenu.value = false;
|
||||||
|
canShowExecuteMethodMenu.value = false;
|
||||||
|
canShowDeleteMenu.value = false;
|
||||||
|
insertSiblingMenus.value = [];
|
||||||
|
insertSonMenus.value = [];
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -694,6 +712,39 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleExtendChange(val: string | number | boolean) {
|
||||||
|
if (val && configForm.value) {
|
||||||
|
const node: PlanMinderNode = window.minder.getNodeById(configForm.value.id);
|
||||||
|
if (node.parent?.data) {
|
||||||
|
const {
|
||||||
|
priority,
|
||||||
|
executeMethod,
|
||||||
|
grouped,
|
||||||
|
environmentId,
|
||||||
|
testResourcePoolId,
|
||||||
|
retryOnFail,
|
||||||
|
retryType,
|
||||||
|
retryTimes,
|
||||||
|
retryInterval,
|
||||||
|
stopOnFail,
|
||||||
|
} = node.parent.data;
|
||||||
|
configForm.value = {
|
||||||
|
...configForm.value,
|
||||||
|
priority,
|
||||||
|
executeMethod,
|
||||||
|
grouped,
|
||||||
|
environmentId,
|
||||||
|
testResourcePoolId,
|
||||||
|
retryOnFail,
|
||||||
|
retryType,
|
||||||
|
retryTimes,
|
||||||
|
retryInterval,
|
||||||
|
stopOnFail,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化测试规划脑图
|
* 初始化测试规划脑图
|
||||||
*/
|
*/
|
||||||
|
@ -762,6 +813,7 @@
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
await editPlanMinder(makeMinderParams(fullJson));
|
await editPlanMinder(makeMinderParams(fullJson));
|
||||||
Message.success(t('common.saveSuccess'));
|
Message.success(t('common.saveSuccess'));
|
||||||
|
clearSelectedCases();
|
||||||
handleConfigCancel();
|
handleConfigCancel();
|
||||||
initMinder();
|
initMinder();
|
||||||
callback();
|
callback();
|
||||||
|
|
|
@ -90,7 +90,7 @@ export default function useEventListener(listener: UseEventListenerProps) {
|
||||||
|
|
||||||
// 监听脑图自定义事件
|
// 监听脑图自定义事件
|
||||||
watch(
|
watch(
|
||||||
() => minderStore.event.timestamp,
|
() => minderStore.event.eventId,
|
||||||
() => {
|
() => {
|
||||||
if (listener.handleMinderEvent) {
|
if (listener.handleMinderEvent) {
|
||||||
listener.handleMinderEvent(minderStore.event);
|
listener.handleMinderEvent(minderStore.event);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div ref="mec" class="ms-minder-container">
|
<div ref="mec" class="ms-minder-container">
|
||||||
<minderHeader :icon-buttons="props.iconButtons" @save="save" />
|
<minderHeader :icon-buttons="props.iconButtons" :disabled="props.disabled" @save="save" />
|
||||||
<Navigator />
|
<Navigator />
|
||||||
<div
|
<div
|
||||||
v-if="currentTreePath?.length > 0"
|
v-if="currentTreePath?.length > 0"
|
||||||
|
@ -125,7 +125,6 @@
|
||||||
]);
|
]);
|
||||||
if (selectNodes.length > 0 && !notChangeCommands.has(event.commandName.toLocaleLowerCase())) {
|
if (selectNodes.length > 0 && !notChangeCommands.has(event.commandName.toLocaleLowerCase())) {
|
||||||
minderStore.setMinderUnsaved(true);
|
minderStore.setMinderUnsaved(true);
|
||||||
minderStore.dispatchEvent(MinderEventName.MINDER_CHANGED);
|
|
||||||
selectNodes.forEach((node: MinderJsonNode) => {
|
selectNodes.forEach((node: MinderJsonNode) => {
|
||||||
markChangeNode(node);
|
markChangeNode(node);
|
||||||
});
|
});
|
||||||
|
@ -155,7 +154,7 @@
|
||||||
* 切换脑图展示的节点层级
|
* 切换脑图展示的节点层级
|
||||||
* @param node 切换的节点
|
* @param node 切换的节点
|
||||||
*/
|
*/
|
||||||
function switchNode(node: MinderJsonNode | MinderJsonNodeData) {
|
function switchNode(node?: MinderJsonNode | MinderJsonNodeData) {
|
||||||
if (minderStore.minderUnsaved) {
|
if (minderStore.minderUnsaved) {
|
||||||
// 切换前,如果脑图未保存,先把更改的节点信息同步一次
|
// 切换前,如果脑图未保存,先把更改的节点信息同步一次
|
||||||
replaceNodeInTree(
|
replaceNodeInTree(
|
||||||
|
@ -166,12 +165,12 @@
|
||||||
'id'
|
'id'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (node.id === 'NONE') {
|
if (node?.id === 'NONE') {
|
||||||
innerImportJson.value = importJson.value;
|
innerImportJson.value = importJson.value;
|
||||||
} else if (node.data) {
|
} else if (node?.data) {
|
||||||
innerImportJson.value = findNodePathByKey([importJson.value.root], node.data.id, 'data', 'id') as MinderJson;
|
innerImportJson.value = findNodePathByKey([importJson.value.root], node.data.id, 'data', 'id') as MinderJson;
|
||||||
} else {
|
} else {
|
||||||
innerImportJson.value = findNodePathByKey([importJson.value.root], node.id, 'data', 'id') as MinderJson;
|
innerImportJson.value = findNodePathByKey([importJson.value.root], node?.id, 'data', 'id') as MinderJson;
|
||||||
}
|
}
|
||||||
window.minder.importJson(innerImportJson.value);
|
window.minder.importJson(innerImportJson.value);
|
||||||
const root: MinderJsonNode = window.minder.getRoot();
|
const root: MinderJsonNode = window.minder.getRoot();
|
||||||
|
@ -203,7 +202,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => minderStore.event.timestamp,
|
() => minderStore.event.eventId,
|
||||||
() => {
|
() => {
|
||||||
if (minderStore.event.name === MinderEventName.HOTBOX && minderStore.event.nodePosition) {
|
if (minderStore.event.name === MinderEventName.HOTBOX && minderStore.event.nodePosition) {
|
||||||
const nodeDomWidth = minderStore.event.nodeDom?.getBoundingClientRect().width || 0;
|
const nodeDomWidth = minderStore.event.nodeDom?.getBoundingClientRect().width || 0;
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
<span></span>
|
<span></span>
|
||||||
<template #content>
|
<template #content>
|
||||||
<a-radio-group
|
<a-radio-group
|
||||||
v-if="currentNodeTags.length > 0 && tags.length > 0"
|
v-if="tags.length > 0"
|
||||||
v-model:model-value="currentNodeTags[0]"
|
v-model:model-value="currentNodeTags[0]"
|
||||||
type="button"
|
type="button"
|
||||||
size="mini"
|
size="mini"
|
||||||
|
@ -212,7 +212,7 @@
|
||||||
const menuPopupOffset = ref<TriggerPopupTranslate>([0, 0]);
|
const menuPopupOffset = ref<TriggerPopupTranslate>([0, 0]);
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => minderStore.event.timestamp,
|
() => minderStore.event.eventId,
|
||||||
async () => {
|
async () => {
|
||||||
if (window.minder) {
|
if (window.minder) {
|
||||||
let nodePosition: MinderNodePosition | undefined;
|
let nodePosition: MinderNodePosition | undefined;
|
||||||
|
|
|
@ -16,7 +16,7 @@ export interface MinderJsonNodeData {
|
||||||
text: string;
|
text: string;
|
||||||
resource?: string[];
|
resource?: string[];
|
||||||
expandState?: 'collapse' | 'expand';
|
expandState?: 'collapse' | 'expand';
|
||||||
priority?: number | string;
|
priority?: number;
|
||||||
// 前端渲染字段
|
// 前端渲染字段
|
||||||
isNew?: boolean; // 是否脑图新增节点,需要在初始化脑图数据时标记已存在节点为 false 以区分是否新增节点
|
isNew?: boolean; // 是否脑图新增节点,需要在初始化脑图数据时标记已存在节点为 false 以区分是否新增节点
|
||||||
changed?: boolean; // 脑图节点是否发生过变化
|
changed?: boolean; // 脑图节点是否发生过变化
|
||||||
|
|
|
@ -13,7 +13,7 @@ const useMinderStore = defineStore('minder', {
|
||||||
state: (): MinderState => ({
|
state: (): MinderState => ({
|
||||||
event: {
|
event: {
|
||||||
name: '' as MinderEventName,
|
name: '' as MinderEventName,
|
||||||
timestamp: 0,
|
eventId: '',
|
||||||
params: '',
|
params: '',
|
||||||
nodePosition: {
|
nodePosition: {
|
||||||
x: 0,
|
x: 0,
|
||||||
|
@ -49,7 +49,7 @@ const useMinderStore = defineStore('minder', {
|
||||||
this.event = {
|
this.event = {
|
||||||
name,
|
name,
|
||||||
params,
|
params,
|
||||||
timestamp: Date.now(),
|
eventId: getGenerateId(),
|
||||||
nodePosition: position,
|
nodePosition: position,
|
||||||
nodeDom,
|
nodeDom,
|
||||||
nodes,
|
nodes,
|
||||||
|
|
|
@ -17,7 +17,7 @@ export interface MinderNodePosition {
|
||||||
|
|
||||||
export interface MinderCustomEvent {
|
export interface MinderCustomEvent {
|
||||||
name: MinderEventName;
|
name: MinderEventName;
|
||||||
timestamp: number;
|
eventId: string;
|
||||||
params?: any;
|
params?: any;
|
||||||
nodePosition?: MinderNodePosition;
|
nodePosition?: MinderNodePosition;
|
||||||
nodeDom?: HTMLElement;
|
nodeDom?: HTMLElement;
|
||||||
|
|
|
@ -580,6 +580,7 @@ export function deleteNodes<T>(
|
||||||
treeArr: TreeNode<T>[],
|
treeArr: TreeNode<T>[],
|
||||||
targetKeys: (string | number)[],
|
targetKeys: (string | number)[],
|
||||||
deleteCondition?: (node: TreeNode<T>, parent?: TreeNode<T>) => boolean,
|
deleteCondition?: (node: TreeNode<T>, parent?: TreeNode<T>) => boolean,
|
||||||
|
deleteCallBack?: (node: TreeNode<T>) => void,
|
||||||
customKey = 'key'
|
customKey = 'key'
|
||||||
): boolean {
|
): boolean {
|
||||||
let hasDeleted = false;
|
let hasDeleted = false;
|
||||||
|
@ -589,6 +590,9 @@ export function deleteNodes<T>(
|
||||||
const node = tree[i];
|
const node = tree[i];
|
||||||
if (targetKeysSet.has(node[customKey])) {
|
if (targetKeysSet.has(node[customKey])) {
|
||||||
if (deleteCondition && deleteCondition(node, node.parent)) {
|
if (deleteCondition && deleteCondition(node, node.parent)) {
|
||||||
|
if (deleteCallBack) {
|
||||||
|
deleteCallBack(node);
|
||||||
|
}
|
||||||
tree.splice(i, 1); // 直接删除当前节点
|
tree.splice(i, 1); // 直接删除当前节点
|
||||||
hasDeleted = true;
|
hasDeleted = true;
|
||||||
targetKeysSet.delete(node[customKey]); // 删除后从集合中移除
|
targetKeysSet.delete(node[customKey]); // 删除后从集合中移除
|
||||||
|
|
|
@ -927,7 +927,8 @@
|
||||||
return item;
|
return item;
|
||||||
});
|
});
|
||||||
if (
|
if (
|
||||||
(!props.disabledExceptParam || !props.disabledParamValue) &&
|
!props.disabledExceptParam &&
|
||||||
|
!props.disabledParamValue &&
|
||||||
hasNoIdItem &&
|
hasNoIdItem &&
|
||||||
!filterKeyValParams(arr, defaultLineData.value, !props.selectable).lastDataIsDefault &&
|
!filterKeyValParams(arr, defaultLineData.value, !props.selectable).lastDataIsDefault &&
|
||||||
!props.isTreeTable
|
!props.isTreeTable
|
||||||
|
@ -935,7 +936,7 @@
|
||||||
addTableLine(arr.length - 1, false, true);
|
addTableLine(arr.length - 1, false, true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (props.disabledExceptParam) return;
|
if (props.disabledExceptParam || props.disabledParamValue) return;
|
||||||
const id = getGenerateId();
|
const id = getGenerateId();
|
||||||
paramsData.value = [
|
paramsData.value = [
|
||||||
{
|
{
|
||||||
|
|
|
@ -282,6 +282,9 @@
|
||||||
scenario.value.steps,
|
scenario.value.steps,
|
||||||
checkedKeys.value,
|
checkedKeys.value,
|
||||||
(node) => !node.isQuoteScenarioStep,
|
(node) => !node.isQuoteScenarioStep,
|
||||||
|
(node) => {
|
||||||
|
delete scenario.value.stepDetails[node.id];
|
||||||
|
},
|
||||||
'uniqueId'
|
'uniqueId'
|
||||||
);
|
);
|
||||||
if (deleteResult) {
|
if (deleteResult) {
|
||||||
|
|
|
@ -990,6 +990,7 @@
|
||||||
maskClosable: false,
|
maskClosable: false,
|
||||||
onBeforeOk: async () => {
|
onBeforeOk: async () => {
|
||||||
deleteNode(steps.value, node.uniqueId, 'uniqueId');
|
deleteNode(steps.value, node.uniqueId, 'uniqueId');
|
||||||
|
delete stepDetails.value[node.id];
|
||||||
scenario.value.unSaved = true;
|
scenario.value.unSaved = true;
|
||||||
},
|
},
|
||||||
hideCancel: false,
|
hideCancel: false,
|
||||||
|
|
|
@ -219,7 +219,7 @@
|
||||||
:module-id="props.activeFolder"
|
:module-id="props.activeFolder"
|
||||||
:modules-count="props.modulesCount"
|
:modules-count="props.modulesCount"
|
||||||
:module-name="props.moduleName"
|
:module-name="props.moduleName"
|
||||||
@save="emitTableParams"
|
@save="handleMinderSave"
|
||||||
/>
|
/>
|
||||||
<MsDrawer v-model:visible="visible" :width="480" :mask="false">
|
<MsDrawer v-model:visible="visible" :width="480" :mask="false">
|
||||||
{{ nodeData.text }}
|
{{ nodeData.text }}
|
||||||
|
@ -390,7 +390,7 @@
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'init', params: CaseModuleQueryParams): void;
|
(e: 'init', params: CaseModuleQueryParams, refreshModule?: boolean): void;
|
||||||
(e: 'import', type: 'Excel' | 'Xmind'): void;
|
(e: 'import', type: 'Excel' | 'Xmind'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
@ -894,14 +894,22 @@
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// 获取父组件模块数量
|
// 获取父组件模块数量
|
||||||
async function emitTableParams() {
|
async function emitTableParams(refreshModule = false) {
|
||||||
const tableParams = await initTableParams();
|
const tableParams = await initTableParams();
|
||||||
emit('init', {
|
emit(
|
||||||
...tableParams,
|
'init',
|
||||||
current: propsRes.value.msPagination?.current,
|
{
|
||||||
pageSize: propsRes.value.msPagination?.pageSize,
|
...tableParams,
|
||||||
filter: propsRes.value.filter,
|
current: propsRes.value.msPagination?.current,
|
||||||
});
|
pageSize: propsRes.value.msPagination?.pageSize,
|
||||||
|
filter: propsRes.value.filter,
|
||||||
|
},
|
||||||
|
refreshModule
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMinderSave() {
|
||||||
|
emitTableParams(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
const tableSelected = ref<(string | number)[]>([]);
|
const tableSelected = ref<(string | number)[]>([]);
|
||||||
|
|
|
@ -285,7 +285,10 @@
|
||||||
/**
|
/**
|
||||||
* 右侧表格数据刷新后,若当前展示的是模块,则刷新模块树的统计数量
|
* 右侧表格数据刷新后,若当前展示的是模块,则刷新模块树的统计数量
|
||||||
*/
|
*/
|
||||||
function initModulesCount(params: TableQueryParams) {
|
function initModulesCount(params: TableQueryParams, refreshModule = false) {
|
||||||
|
if (refreshModule) {
|
||||||
|
caseTreeRef.value.initModules();
|
||||||
|
}
|
||||||
featureCaseStore.getCaseModulesCount(params);
|
featureCaseStore.getCaseModulesCount(params);
|
||||||
featureCaseStore.getRecycleModulesCount(params);
|
featureCaseStore.getRecycleModulesCount(params);
|
||||||
tableFilterParams.value = { ...params };
|
tableFilterParams.value = { ...params };
|
||||||
|
|
|
@ -102,7 +102,7 @@
|
||||||
</MsCard>
|
</MsCard>
|
||||||
<!-- special-height的174: 上面卡片高度158 + mt的16 -->
|
<!-- special-height的174: 上面卡片高度158 + mt的16 -->
|
||||||
<MsCard class="mt-[16px]" :special-height="174" simple has-breadcrumb no-content-padding>
|
<MsCard class="mt-[16px]" :special-height="174" simple has-breadcrumb no-content-padding>
|
||||||
<Plan v-if="activeTab === 'plan'" :plan-id="planId" @refresh="initDetail" />
|
<Plan v-if="activeTab === 'plan'" :plan-id="planId" :status="detail.status || 'PREPARED'" @refresh="initDetail" />
|
||||||
<FeatureCase
|
<FeatureCase
|
||||||
v-if="activeTab === 'featureCase'"
|
v-if="activeTab === 'featureCase'"
|
||||||
ref="featureCaseRef"
|
ref="featureCaseRef"
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<div class="flex h-full flex-col p-[16px]">
|
<div class="flex h-full flex-col p-[16px]">
|
||||||
<MsNotRemind tip="testPlan.planTip" class="mb-[16px]" type="info" visited-key="testPlanTip" />
|
<MsNotRemind tip="testPlan.planTip" class="mb-[16px]" type="info" visited-key="testPlanTip" />
|
||||||
<div class="flex-1 overflow-hidden">
|
<div class="flex-1 overflow-hidden">
|
||||||
<MsTestPlanMinder :plan-id="props.planId" @save="emit('refresh')" />
|
<MsTestPlanMinder :plan-id="props.planId" :status="props.status" @save="emit('refresh')" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
planId: string;
|
planId: string;
|
||||||
|
status: string;
|
||||||
}>();
|
}>();
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'refresh'): void;
|
(e: 'refresh'): void;
|
||||||
|
|
Loading…
Reference in New Issue