fix(脑图): 脑图bug修复&权限

This commit is contained in:
baiqi 2024-06-17 12:57:35 +08:00 committed by Craftsman
parent 68231064cb
commit ae0732dc6c
12 changed files with 155 additions and 89 deletions

View File

@ -2,6 +2,7 @@
<a-spin :loading="attachmentLoading" class="block h-full pl-[16px]"> <a-spin :loading="attachmentLoading" class="block h-full pl-[16px]">
<MsAddAttachment <MsAddAttachment
v-model:file-list="fileList" v-model:file-list="fileList"
:disabled="!hasEditPermission"
multiple multiple
only-button only-button
@change="(files, file) => handleFileChange(file ? [file] : [])" @change="(files, file) => handleFileChange(file ? [file] : [])"
@ -81,6 +82,7 @@
v-if="activeCase.id && item.isUpdateFlag" v-if="activeCase.id && item.isUpdateFlag"
type="button" type="button"
status="primary" status="primary"
:disabled="!hasEditPermission"
@click="handleUpdateFile(item)" @click="handleUpdateFile(item)"
> >
{{ t('common.update') }} {{ t('common.update') }}
@ -125,6 +127,7 @@
import useModal from '@/hooks/useModal'; import useModal from '@/hooks/useModal';
import useAppStore from '@/store/modules/app'; import useAppStore from '@/store/modules/app';
import { downloadByteFile } from '@/utils'; import { downloadByteFile } from '@/utils';
import { hasAnyPermission } from '@/utils/permission';
import { AssociatedList } from '@/models/caseManagement/featureCase'; import { AssociatedList } from '@/models/caseManagement/featureCase';
import { TableQueryParams } from '@/models/common'; import { TableQueryParams } from '@/models/common';
@ -151,6 +154,7 @@
hiddenIds: [], hiddenIds: [],
}, },
}); });
const hasEditPermission = hasAnyPermission(['FUNCTIONAL_CASE:READ+UPDATE']);
// //
watch( watch(

View File

@ -6,7 +6,7 @@
<a-skeleton-line :rows="10" :line-height="30" :line-spacing="30" /> <a-skeleton-line :rows="10" :line-height="30" :line-spacing="30" />
</a-space> </a-space>
</a-skeleton> </a-skeleton>
<a-form v-else ref="baseInfoFormRef" :model="baseInfoForm" layout="vertical"> <a-form v-else ref="baseInfoFormRef" :model="baseInfoForm" :disabled="!hasEditPermission" layout="vertical">
<a-form-item <a-form-item
field="name" field="name"
:label="t('ms.minders.caseName')" :label="t('ms.minders.caseName')"
@ -21,13 +21,14 @@
v-model:api="fApi" v-model:api="fApi"
v-model:form-item="formItem" v-model:form-item="formItem"
:form-rule="formRules" :form-rule="formRules"
:disabled="!hasEditPermission"
/> />
<a-form-item field="tags" :label="t('common.tag')"> <a-form-item field="tags" :label="t('common.tag')">
<MsTagsInput v-model:model-value="baseInfoForm.tags" :max-tag-count="6" /> <MsTagsInput v-model:model-value="baseInfoForm.tags" :max-tag-count="6" />
</a-form-item> </a-form-item>
</a-form> </a-form>
</div> </div>
<div class="flex items-center gap-[12px] bg-white py-[16px]"> <div v-if="hasEditPermission" class="flex items-center gap-[12px] bg-white py-[16px]">
<a-button <a-button
v-permission="['FUNCTIONAL_CASE:READ+UPDATE']" v-permission="['FUNCTIONAL_CASE:READ+UPDATE']"
type="primary" type="primary"
@ -57,6 +58,7 @@
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import useAppStore from '@/store/modules/app'; import useAppStore from '@/store/modules/app';
import useUserStore from '@/store/modules/user'; import useUserStore from '@/store/modules/user';
import { hasAnyPermission } from '@/utils/permission';
import { OptionsFieldId } from '@/models/caseManagement/featureCase'; import { OptionsFieldId } from '@/models/caseManagement/featureCase';
@ -75,6 +77,7 @@
const userStore = useUserStore(); const userStore = useUserStore();
const { t } = useI18n(); const { t } = useI18n();
const hasEditPermission = hasAnyPermission(['FUNCTIONAL_CASE:READ+MINDER']);
const baseInfoFormRef = ref<FormInstance>(); const baseInfoFormRef = ref<FormInstance>();
const baseInfoForm = ref({ const baseInfoForm = ref({
name: '', name: '',

View File

@ -1,6 +1,6 @@
<template> <template>
<a-spin :loading="bugListLoading" class="block h-full pl-[16px]"> <a-spin :loading="bugListLoading" class="block h-full pl-[16px]">
<a-button v-if="hasAnyPermission(['FUNCTIONAL_CASE:READ+UPDATE'])" class="mr-3" type="primary" @click="linkBug"> <a-button v-if="hasEditPermission" class="mr-3" type="primary" @click="linkBug">
{{ t('caseManagement.featureCase.linkDefect') }} {{ t('caseManagement.featureCase.linkDefect') }}
</a-button> </a-button>
<a-button v-permission="['PROJECT_BUG:READ+ADD']" type="outline" @click="createBug"> <a-button v-permission="['PROJECT_BUG:READ+ADD']" type="outline" @click="createBug">
@ -22,7 +22,7 @@
<div class="bug-item"> <div class="bug-item">
<div class="mb-[4px] flex items-center justify-between"> <div class="mb-[4px] flex items-center justify-between">
<MsButton type="text" @click="goBug(item.id)">{{ item.num }}</MsButton> <MsButton type="text" @click="goBug(item.id)">{{ item.num }}</MsButton>
<MsButton type="text" @click="disassociateBug(item.id)"> <MsButton v-if="hasEditPermission" type="text" @click="disassociateBug(item.id)">
{{ t('ms.add.attachment.cancelAssociate') }} {{ t('ms.add.attachment.cancelAssociate') }}
</MsButton> </MsButton>
</div> </div>
@ -83,6 +83,7 @@
const appStore = useAppStore(); const appStore = useAppStore();
const { t } = useI18n(); const { t } = useI18n();
const hasEditPermission = hasAnyPermission(['FUNCTIONAL_CASE:READ+UPDATE']);
const bugList = ref<any[]>([]); const bugList = ref<any[]>([]);
const noMoreData = ref(false); const noMoreData = ref(false);
const pageNation = ref({ const pageNation = ref({

View File

@ -33,6 +33,7 @@
</template> </template>
</div> </div>
<inputComment <inputComment
v-if="hasEditPermission"
ref="commentInputRef" ref="commentInputRef"
v-model:content="content" v-model:content="content"
v-model:notice-user-ids="noticeUserIds" v-model:notice-user-ids="noticeUserIds"
@ -71,6 +72,7 @@
import { PreviewEditorImageUrl } from '@/api/requrls/case-management/featureCase'; import { PreviewEditorImageUrl } from '@/api/requrls/case-management/featureCase';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import useModal from '@/hooks/useModal'; import useModal from '@/hooks/useModal';
import { hasAnyPermission } from '@/utils/permission';
const props = defineProps<{ const props = defineProps<{
activeCase: Record<string, any>; activeCase: Record<string, any>;
@ -79,6 +81,8 @@
const { t } = useI18n(); const { t } = useI18n();
const { openModal } = useModal(); const { openModal } = useModal();
const hasEditPermission = hasAnyPermission(['FUNCTIONAL_CASE:READ+COMMENT']);
async function handleUploadImage(file: File) { async function handleUploadImage(file: File) {
const { data } = await editorUploadFile({ const { data } = await editorUploadFile({
fileList: [file], fileList: [file],

View File

@ -11,6 +11,7 @@
:priority-disable-check="priorityDisableCheck" :priority-disable-check="priorityDisableCheck"
:after-tag-edit="afterTagEdit" :after-tag-edit="afterTagEdit"
:extract-content-tab-list="extractContentTabList" :extract-content-tab-list="extractContentTabList"
:can-show-float-menu="canShowFloatMenu()"
:can-show-enter-node="canShowEnterNode" :can-show-enter-node="canShowEnterNode"
:insert-sibling-menus="insertSiblingMenus" :insert-sibling-menus="insertSiblingMenus"
:insert-son-menus="insertSonMenus" :insert-son-menus="insertSonMenus"
@ -18,6 +19,7 @@
:can-show-more-menu="canShowMoreMenu()" :can-show-more-menu="canShowMoreMenu()"
:can-show-priority-menu="canShowPriorityMenu()" :can-show-priority-menu="canShowPriorityMenu()"
:priority-tooltip="t('caseManagement.caseReview.caseLevel')" :priority-tooltip="t('caseManagement.caseReview.caseLevel')"
:disabled="!hasEditPermission"
single-tag single-tag
tag-enable tag-enable
sequence-enable sequence-enable
@ -89,6 +91,7 @@
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';
import { hasAnyPermission } from '@/utils/permission';
import { import {
FeatureCaseMinderEditType, FeatureCaseMinderEditType,
@ -114,6 +117,7 @@
const { t } = useI18n(); const { t } = useI18n();
const minderStore = useMinderStore(); const minderStore = useMinderStore();
const hasEditPermission = hasAnyPermission(['FUNCTIONAL_CASE:READ+MINDER']);
const { const {
caseTag, caseTag,
moduleTag, moduleTag,
@ -127,13 +131,14 @@
insertNode, insertNode,
handleBeforeExecCommand, handleBeforeExecCommand,
stopPaste, stopPaste,
canShowFloatMenu,
checkNodeCanShowMenu, checkNodeCanShowMenu,
canShowMoreMenu, canShowMoreMenu,
canShowPriorityMenu, canShowPriorityMenu,
handleContentChange, handleContentChange,
replaceableTags, replaceableTags,
priorityDisableCheck, priorityDisableCheck,
} = useMinderBaseApi(); } = useMinderBaseApi({ hasEditPermission });
const importJson = ref<MinderJson>({ const importJson = ref<MinderJson>({
root: {} as MinderJsonNode, root: {} as MinderJsonNode,
template: 'default', template: 'default',
@ -220,61 +225,6 @@
}); });
const baseInfoRef = ref<InstanceType<typeof baseInfo>>(); 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(textDescTag)) {
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 || getGenerateId(),
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: JSON.stringify(steps),
textDescription: textStep?.data?.text || '',
expectedResult: textStep?.children?.[0]?.data?.text || '',
description: remarkNode?.data?.text || '',
};
}
/**
* 获取节点的移动信息
* @param node 节点
* @param parent 父节点
*/
function getNodeMoveInfo(nodeIndex: number, parent?: MinderJsonNode): { moveMode: MoveMode; targetId?: string } {
const moveMode = nodeIndex === 0 ? 'BEFORE' : 'AFTER'; //
return {
moveMode,
targetId:
moveMode === 'BEFORE'
? parent?.children?.[1]?.data?.id
: parent?.children?.[(nodeIndex || parent.children.length - 1) - 1]?.data?.id,
};
}
const baseInfoLoading = ref(false); const baseInfoLoading = ref(false);
const formRules = ref<FormItem[]>([]); const formRules = ref<FormItem[]>([]);
@ -603,6 +553,65 @@
} }
} }
/**
* 解析用例节点信息
* @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(textDescTag)) {
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 || getGenerateId(),
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: JSON.stringify(steps),
textDescription: textStep?.data?.text || '',
expectedResult: textStep?.children?.[0]?.data?.text || '',
description: remarkNode?.data?.text || '',
};
}
/**
* 获取节点的移动信息
* @param node 节点
* @param parent 父节点
*/
function getNodeMoveInfo(nodeIndex: number, parent?: MinderJsonNode): { moveMode: MoveMode; targetId?: string } {
const moveMode = nodeIndex === 0 ? 'BEFORE' : 'AFTER'; //
if (!parent) {
//
parent = importJson.value.root;
}
return {
moveMode,
targetId:
moveMode === 'BEFORE'
? parent?.children?.[1]?.data?.id
: parent?.children?.[(nodeIndex || parent.children.length - 1) - 1]?.data?.id,
};
}
/** /**
* 生成脑图保存的入参 * 生成脑图保存的入参
*/ */

View File

@ -13,7 +13,7 @@ import { getGenerateId } from '@/utils';
* *
* @returns API * @returns API
*/ */
export default function useMinderBaseApi() { export default function useMinderBaseApi({ hasEditPermission }: { hasEditPermission: boolean }) {
const { t } = useI18n(); const { t } = useI18n();
const minderStore = useMinderStore(); const minderStore = useMinderStore();
@ -29,6 +29,22 @@ export default function useMinderBaseApi() {
const caseChildTags = [prerequisiteTag, stepTag, textDescTag, remarkTag]; const caseChildTags = [prerequisiteTag, stepTag, textDescTag, remarkTag];
const caseOffspringTags = [...caseChildTags, stepTag, stepExpectTag, textDescTag, remarkTag]; const caseOffspringTags = [...caseChildTags, stepTag, stepExpectTag, textDescTag, remarkTag];
/**
*
*/
function canShowFloatMenu() {
if (window.minder) {
const node: MinderJsonNode = window.minder.getSelectedNode();
if (node.data?.resource?.includes(caseTag)) {
return true;
}
if (!hasEditPermission) {
return false;
}
}
return false;
}
const insertSiblingMenus = ref<InsertMenuItem[]>([]); const insertSiblingMenus = ref<InsertMenuItem[]>([]);
const insertSonMenus = ref<InsertMenuItem[]>([]); const insertSonMenus = ref<InsertMenuItem[]>([]);
@ -37,6 +53,11 @@ export default function useMinderBaseApi() {
* @param node * @param node
*/ */
function checkNodeCanShowMenu(node: MinderJsonNode) { function checkNodeCanShowMenu(node: MinderJsonNode) {
if (!hasEditPermission) {
insertSiblingMenus.value = [];
insertSonMenus.value = [];
return;
}
const { data } = node; const { data } = node;
if (data?.resource?.includes(moduleTag)) { if (data?.resource?.includes(moduleTag)) {
// 模块节点 // 模块节点
@ -191,6 +212,9 @@ export default function useMinderBaseApi() {
* *
*/ */
function canShowMoreMenu() { function canShowMoreMenu() {
if (!hasEditPermission) {
return false;
}
if (window.minder) { if (window.minder) {
const node: MinderJsonNode = window.minder.getSelectedNode(); const node: MinderJsonNode = window.minder.getSelectedNode();
// 选中节点不为虚拟根节点时,可展示更多菜单 // 选中节点不为虚拟根节点时,可展示更多菜单
@ -203,6 +227,9 @@ export default function useMinderBaseApi() {
* *
*/ */
function canShowPriorityMenu() { function canShowPriorityMenu() {
if (!hasEditPermission) {
return false;
}
if (window.minder) { if (window.minder) {
const node: MinderJsonNode = window.minder.getSelectedNode(); const node: MinderJsonNode = window.minder.getSelectedNode();
// 选中节点是用例节点时,可展示优先级菜单 // 选中节点是用例节点时,可展示优先级菜单
@ -280,6 +307,9 @@ export default function useMinderBaseApi() {
* *
*/ */
function priorityDisableCheck(node: MinderJsonNode) { function priorityDisableCheck(node: MinderJsonNode) {
if (!hasEditPermission) {
return false;
}
if (node.data?.resource?.includes(caseTag)) { if (node.data?.resource?.includes(caseTag)) {
return false; return false;
} }
@ -678,6 +708,7 @@ export default function useMinderBaseApi() {
handleBeforeExecCommand, handleBeforeExecCommand,
stopPaste, stopPaste,
checkNodeCanShowMenu, checkNodeCanShowMenu,
canShowFloatMenu,
canShowMoreMenu, canShowMoreMenu,
canShowPriorityMenu, canShowPriorityMenu,
handleContentChange, handleContentChange,

View File

@ -13,6 +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"
custom-priority custom-priority
single-tag single-tag
tag-enable tag-enable
@ -20,7 +21,6 @@
@node-select="(node) => handleNodeSelect(node as PlanMinderNode)" @node-select="(node) => handleNodeSelect(node as PlanMinderNode)"
@before-exec-command="handleBeforeExecCommand" @before-exec-command="handleBeforeExecCommand"
@save="handleMinderSave" @save="handleMinderSave"
@float-menu-close="handleFloatMenuClose"
> >
<template #extractMenu> <template #extractMenu>
<a-tooltip v-if="showAssociateCaseMenu" :content="t('ms.case.associate.title')"> <a-tooltip v-if="showAssociateCaseMenu" :content="t('ms.case.associate.title')">
@ -85,8 +85,8 @@
<div class="one-line-text font-medium">{{ configForm.text }}</div> <div class="one-line-text font-medium">{{ configForm.text }}</div>
</a-tooltip> </a-tooltip>
</div> </div>
<a-form ref="configFormRef" :model="configForm" layout="vertical"> <a-form ref="configFormRef" :model="configForm" :disabled="!hasEditPermission" layout="vertical">
<a-form-item> <a-form-item v-if="hasEditPermission">
<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>
@ -94,6 +94,7 @@
<MsButton <MsButton
type="text" type="text"
:disabled=" :disabled="
!hasEditPermission ||
(selectedAssociateCasesParams.totalCount || selectedAssociateCasesParams.selectIds.length) === 0 (selectedAssociateCasesParams.totalCount || selectedAssociateCasesParams.selectIds.length) === 0
" "
@click="clearSelectedCases" @click="clearSelectedCases"
@ -118,7 +119,8 @@
v-permission="['CASE_REVIEW:READ+RELEVANCE']" v-permission="['CASE_REVIEW:READ+RELEVANCE']"
type="text" type="text"
class="font-medium" class="font-medium"
@click="caseAssociateVisible = true" :disabled="!hasEditPermission"
@click="openCaseAssociateDrawer"
> >
{{ t('ms.case.associate.title') }} {{ t('ms.case.associate.title') }}
</MsButton> </MsButton>
@ -149,7 +151,8 @@
<div>{{ t('ms.minders.failStop') }}</div> <div>{{ t('ms.minders.failStop') }}</div>
</div> </div>
</a-form-item> </a-form-item>
<a-form-item class="hidden-item"> <!-- 暂时不上 -->
<!-- <a-form-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.retryOnFail" size="small"></a-switch> <a-switch v-model:model-value="configForm.retryOnFail" size="small"></a-switch>
<div>{{ t('ms.minders.failRetry') }}</div> <div>{{ t('ms.minders.failRetry') }}</div>
@ -196,7 +199,7 @@
class="w-[120px]" class="w-[120px]"
></a-input-number> ></a-input-number>
</a-form-item> </a-form-item>
</template> </template> -->
</template> </template>
<a-form-item <a-form-item
v-if="configForm.type !== PlanMinderCollectionType.FUNCTIONAL && configForm.level === 2" v-if="configForm.type !== PlanMinderCollectionType.FUNCTIONAL && configForm.level === 2"
@ -208,7 +211,7 @@
</div> </div>
</a-form-item> </a-form-item>
</a-form> </a-form>
<div class="flex items-center gap-[12px] bg-white pb-[16px]"> <div v-if="hasEditPermission" class="flex items-center gap-[12px] bg-white pb-[16px]">
<a-button <a-button
v-permission="['FUNCTIONAL_CASE:READ+UPDATE']" v-permission="['FUNCTIONAL_CASE:READ+UPDATE']"
type="primary" type="primary"
@ -232,7 +235,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { FormInstance, SelectOptionData } from '@arco-design/web-vue'; import { type FormInstance, Message, type SelectOptionData } from '@arco-design/web-vue';
import { cloneDeep } from 'lodash-es'; import { cloneDeep } from 'lodash-es';
import MsButton from '@/components/pure/ms-button/index.vue'; import MsButton from '@/components/pure/ms-button/index.vue';
@ -253,6 +256,7 @@
import useAppStore from '@/store/modules/app'; import useAppStore from '@/store/modules/app';
import useMinderStore from '@/store/modules/components/minder-editor'; import useMinderStore from '@/store/modules/components/minder-editor';
import { filterTree, getGenerateId, mapTree } from '@/utils'; import { filterTree, getGenerateId, mapTree } from '@/utils';
import { hasAnyPermission } from '@/utils/permission';
import { import {
AssociateCaseRequest, AssociateCaseRequest,
@ -262,9 +266,7 @@
} from '@/models/testPlan/testPlan'; } from '@/models/testPlan/testPlan';
import { CaseLinkEnum } from '@/enums/caseEnum'; import { CaseLinkEnum } from '@/enums/caseEnum';
import { MinderEventName } from '@/enums/minderEnum'; import { MinderEventName } from '@/enums/minderEnum';
import { FailRetry, PlanMinderAssociateType, PlanMinderCollectionType, RunMode } from '@/enums/testPlanEnum'; import { PlanMinderAssociateType, PlanMinderCollectionType, RunMode } from '@/enums/testPlanEnum';
import Message from '@arco-design/web-vue/es/message';
const props = defineProps<{ const props = defineProps<{
planId: string; planId: string;
@ -290,11 +292,12 @@
const insertSiblingMenus = ref<InsertMenuItem[]>([]); const insertSiblingMenus = ref<InsertMenuItem[]>([]);
const insertSonMenus = ref<InsertMenuItem[]>([]); const insertSonMenus = ref<InsertMenuItem[]>([]);
const showAssociateCaseMenu = ref(false); const showAssociateCaseMenu = ref(false);
const canShowExecuteMethodMenu = ref(true); const canShowExecuteMethodMenu = ref(false);
const executeMethodMenuVisible = ref(false); const executeMethodMenuVisible = ref(false);
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']);
/** /**
* 检测节点可展示的菜单项 * 检测节点可展示的菜单项
@ -303,6 +306,17 @@
function checkNodeCanShowMenu(node: PlanMinderNode) { function checkNodeCanShowMenu(node: PlanMinderNode) {
const { data } = node; const { data } = node;
if (!hasEditPermission && (data?.level === 1 || data?.level === 2)) {
//
if (data?.type === PlanMinderCollectionType.FUNCTIONAL) {
canShowFloatMenu.value = false;
} else {
canShowFloatMenu.value = true;
showConfigMenu.value = true;
}
return;
}
if (data?.level === 1 || data?.level === 2) { if (data?.level === 1 || data?.level === 2) {
canShowFloatMenu.value = true; canShowFloatMenu.value = true;
if (data?.type === PlanMinderCollectionType.FUNCTIONAL) { if (data?.type === PlanMinderCollectionType.FUNCTIONAL) {
@ -499,12 +513,6 @@
return false; return false;
} }
function handleFloatMenuClose() {
if (!checkConfigFormUnsaved()) {
handleConfigCancel();
}
}
/** /**
* 处理节点选中 * 处理节点选中
* @param node 节点 * @param node 节点
@ -607,6 +615,11 @@
}); });
} }
function openCaseAssociateDrawer() {
currentSelectCase.value = (activePlanSet.value?.data?.type as unknown as CaseLinkEnum) || CaseLinkEnum.FUNCTIONAL;
caseAssociateVisible.value = true;
}
watch( watch(
() => [configForm.value, selectedAssociateCasesParams.value.selectIds], () => [configForm.value, selectedAssociateCasesParams.value.selectIds],
() => { () => {
@ -732,6 +745,11 @@
loading.value = true; loading.value = true;
await editPlanMinder(makeMinderParams(fullJson)); await editPlanMinder(makeMinderParams(fullJson));
Message.success(t('common.saveSuccess')); Message.success(t('common.saveSuccess'));
tempMinderParams.value = {
planId: props.planId,
editList: [],
deletedIds: [],
};
handleConfigCancel(); handleConfigCancel();
initMinder(); initMinder();
callback(); callback();

View File

@ -21,8 +21,6 @@
</template> </template>
<script lang="ts" name="minderContainer" setup> <script lang="ts" name="minderContainer" setup>
import { onMounted, ref, watch } from 'vue';
import nodeFloatMenu from '../menu/nodeFloatMenu.vue'; import nodeFloatMenu from '../menu/nodeFloatMenu.vue';
import minderHeader from './header.vue'; import minderHeader from './header.vue';
import Navigator from './navigator.vue'; import Navigator from './navigator.vue';

View File

@ -188,10 +188,11 @@
import { MinderEventName } from '@/enums/minderEnum'; import { MinderEventName } from '@/enums/minderEnum';
import { floatMenuProps, insertProps, MinderJsonNode, priorityProps, tagProps } from '../props'; import { floatMenuProps, insertProps, mainEditorProps, MinderJsonNode, priorityProps, tagProps } from '../props';
import { isDisableNode, isNodeInMinderView, setPriorityView } from '../script/tool/utils'; import { isDisableNode, isNodeInMinderView, setPriorityView } from '../script/tool/utils';
const props = defineProps({ const props = defineProps({
...mainEditorProps,
...floatMenuProps, ...floatMenuProps,
...insertProps, ...insertProps,
...tagProps, ...tagProps,
@ -219,7 +220,7 @@
if (minderStore.event.name === MinderEventName.NODE_SELECT) { if (minderStore.event.name === MinderEventName.NODE_SELECT) {
nodePosition = minderStore.event.nodePosition; nodePosition = minderStore.event.nodePosition;
currentNodeTags.value = minderStore.event.nodes?.[0].data?.resource || []; currentNodeTags.value = minderStore.event.nodes?.[0].data?.resource || [];
if (props.replaceableTags) { if (props.replaceableTags && !props.disabled) {
tags.value = props.replaceableTags(selectedNodes); tags.value = props.replaceableTags(selectedNodes);
} else { } else {
tags.value = []; tags.value = [];

View File

@ -104,15 +104,12 @@
} }
); );
onMounted(async () => {
window.minderProps = props;
});
function save(data: MinderJson, callback: () => void) { function save(data: MinderJson, callback: () => void) {
emit('save', data, callback); emit('save', data, callback);
} }
onMounted(() => { onMounted(() => {
window.minderProps = props;
useMinderEventListener({ useMinderEventListener({
handleSelectionChange: (node?: MinderJsonNode) => { handleSelectionChange: (node?: MinderJsonNode) => {
if (node) { if (node) {

View File

@ -233,7 +233,7 @@
...cloneDeep(defaultDebugParams), ...cloneDeep(defaultDebugParams),
id, id,
isNew: !defaultProps?.id, // tabidid isNew: !defaultProps?.id, // tabidid
protocol: activeDebug.value.protocol, // tab使tab protocol: activeDebug.value.protocol || defaultDebugParams.protocol, // tab使tab
...defaultProps, ...defaultProps,
}); });
activeDebug.value = debugTabs.value[debugTabs.value.length - 1]; activeDebug.value = debugTabs.value[debugTabs.value.length - 1];

View File

@ -306,7 +306,7 @@
id, id,
isNew: !defaultProps?.id, // tabidid isNew: !defaultProps?.id, // tabidid
definitionActiveKey: !defaultProps ? 'definition' : 'preview', definitionActiveKey: !defaultProps ? 'definition' : 'preview',
protocol: activeApiTab.value.protocol, // tab使tab protocol: activeApiTab.value.protocol || defaultDefinitionParams.protocol, // tab使tab
...defaultProps, ...defaultProps,
}); });
activeApiTab.value = apiTabs.value[apiTabs.value.length - 1]; activeApiTab.value = apiTabs.value[apiTabs.value.length - 1];