feat(功能用例): 用例评审脑图操作-更多

This commit is contained in:
teukkk 2024-07-05 16:33:00 +08:00 committed by 刘瑞斌
parent 2510bcd24e
commit 07d1134f52
3 changed files with 125 additions and 61 deletions

View File

@ -65,7 +65,7 @@
</div> </div>
<template #content> <template #content>
<div <div
class="trigger-content rounded-[var(--border-radius-medium)] bg-white p-[6px] shadow-[0_-1px_4px_rgba(2,2,2,0.1)]" class="trigger-content w-[150px] rounded-[var(--border-radius-medium)] bg-white p-[6px] shadow-[0_-1px_4px_rgba(2,2,2,0.1)]"
> >
<div v-for="item in reviewUserStatusList" :key="item.id" class="my-[4px] flex justify-between"> <div v-for="item in reviewUserStatusList" :key="item.id" class="my-[4px] flex justify-between">
<div class="one-line-text max-w-[80px]"> <div class="one-line-text max-w-[80px]">
@ -73,6 +73,7 @@
</div> </div>
<ReviewResult :status="item.status" class="text-[12px]" :icon-size="12" /> <ReviewResult :status="item.status" class="text-[12px]" :icon-size="12" />
</div> </div>
<MsEmpty v-if="!reviewUserStatusList.length" />
</div> </div>
</template> </template>
</a-trigger> </a-trigger>
@ -94,6 +95,7 @@
import MsButton from '@/components/pure/ms-button/index.vue'; import MsButton from '@/components/pure/ms-button/index.vue';
import MsDescription, { Description } from '@/components/pure/ms-description/index.vue'; import MsDescription, { Description } from '@/components/pure/ms-description/index.vue';
import MsEmpty from '@/components/pure/ms-empty/index.vue';
import MsMinderEditor from '@/components/pure/ms-minder-editor/minderEditor.vue'; import MsMinderEditor from '@/components/pure/ms-minder-editor/minderEditor.vue';
import type { MinderJson, MinderJsonNode, MinderJsonNodeData } from '@/components/pure/ms-minder-editor/props'; import type { MinderJson, MinderJsonNode, MinderJsonNodeData } from '@/components/pure/ms-minder-editor/props';
import { MinderEvent } from '@/components/pure/ms-minder-editor/props'; import { MinderEvent } from '@/components/pure/ms-minder-editor/props';
@ -126,6 +128,10 @@
moduleTree: ModuleTreeNode[]; moduleTree: ModuleTreeNode[];
}>(); }>();
const emit = defineEmits<{
(e: 'operation', type: string, data: MinderJsonNodeData): void;
}>();
const route = useRoute(); const route = useRoute();
const appStore = useAppStore(); const appStore = useAppStore();
const { t } = useI18n(); const { t } = useI18n();
@ -348,7 +354,7 @@
} }
const extraVisible = ref<boolean>(false); const extraVisible = ref<boolean>(false);
const activeExtraKey = ref<'baseInfo' | 'attachment' | 'history'>('baseInfo'); const activeExtraKey = ref<'baseInfo' | 'attachment' | 'history'>('history');
const baseInfoLoading = ref(false); const baseInfoLoading = ref(false);
const activeCaseInfo = ref<Record<string, any>>({}); const activeCaseInfo = ref<Record<string, any>>({});
const descriptions = ref<Description[]>([]); const descriptions = ref<Description[]>([]);
@ -461,7 +467,7 @@
const node: MinderJsonNode = window.minder.getSelectedNode(); const node: MinderJsonNode = window.minder.getSelectedNode();
const { data } = node; const { data } = node;
if (extraVisible.value && data?.resource?.includes(caseTag)) { if (extraVisible.value && data?.resource?.includes(caseTag)) {
activeExtraKey.value = 'baseInfo'; activeExtraKey.value = 'history';
initCaseDetail(data); initCaseDetail(data);
initReviewHistoryList(data); initReviewHistoryList(data);
} }
@ -470,35 +476,35 @@
const canShowFloatMenu = ref(false); // const canShowFloatMenu = ref(false); //
const canShowEnterNode = ref(false); const canShowEnterNode = ref(false);
const showCaseMenu = ref(false); const showCaseMenu = ref(false);
const moreMenuOtherOperationList = [ const moreMenuOtherOperationList = ref();
{ function setMoreMenuOtherOperationList(data: MinderJsonNodeData) {
value: 'changeReviewer', moreMenuOtherOperationList.value = [
label: t('caseManagement.caseReview.changeReviewer'), {
permission: ['CASE_REVIEW:READ+UPDATE'], value: 'changeReviewer',
onClick: () => { label: t('caseManagement.caseReview.changeReviewer'),
// TODO permission: ['CASE_REVIEW:READ+UPDATE'],
console.log('🤔️ =>', t('caseManagement.caseReview.changeReviewer')); onClick: () => {
emit('operation', 'changeReviewer', data);
},
}, },
}, {
{ value: 'reReview',
value: 'reReview', label: t('caseManagement.caseReview.reReview'),
label: t('caseManagement.caseReview.reReview'), permission: ['CASE_REVIEW:READ+UPDATE'],
permission: ['CASE_REVIEW:READ+UPDATE'], onClick: () => {
onClick: () => { emit('operation', 'reReview', data);
// TODO },
console.log('🤔️ =>', t('caseManagement.caseReview.reReview'));
}, },
}, {
{ value: 'disassociate',
value: 'disassociate', label: t('caseManagement.caseReview.disassociate'),
label: t('caseManagement.caseReview.disassociate'), permission: ['CASE_REVIEW:READ+RELEVANCE'],
permission: ['CASE_REVIEW:READ+RELEVANCE'], onClick: () => {
onClick: () => { emit('operation', 'disassociate', data);
// TODO },
console.log('🤔️ =>', t('caseManagement.caseReview.disassociate'));
}, },
}, ];
]; }
/** /**
* 处理节点选中 * 处理节点选中
@ -515,8 +521,8 @@
} }
// : // :
if ( if (
node?.data?.resource?.includes(caseTag) || node.data?.resource?.includes(caseTag) ||
(node?.data?.resource?.includes(moduleTag) && node.type !== 'root' && (node.children || []).length > 0) (node.data?.resource?.includes(moduleTag) && node.type !== 'root' && (node.children || []).length > 0)
) { ) {
canShowFloatMenu.value = true; canShowFloatMenu.value = true;
} else { } else {
@ -532,6 +538,7 @@
if (data?.resource?.includes(caseTag)) { if (data?.resource?.includes(caseTag)) {
showCaseMenu.value = true; showCaseMenu.value = true;
setMoreMenuOtherOperationList(node.data as MinderJsonNodeData);
if (extraVisible.value) { if (extraVisible.value) {
toggleDetail(true); toggleDetail(true);
} }

View File

@ -87,6 +87,7 @@
</div> </div>
</template> </template>
</MsFileList> </MsFileList>
<MsEmpty v-if="!fileList.length" />
</a-spin> </a-spin>
<LinkFileDrawer <LinkFileDrawer
v-model:visible="showLinkFileDrawer" v-model:visible="showLinkFileDrawer"
@ -103,6 +104,7 @@
import { Message } from '@arco-design/web-vue'; import { Message } from '@arco-design/web-vue';
import MsButton from '@/components/pure/ms-button/index.vue'; import MsButton from '@/components/pure/ms-button/index.vue';
import MsEmpty from '@/components/pure/ms-empty/index.vue';
import MsFileList from '@/components/pure/ms-upload/fileList.vue'; import MsFileList from '@/components/pure/ms-upload/fileList.vue';
import { MsFileItem } from '@/components/pure/ms-upload/types'; import { MsFileItem } from '@/components/pure/ms-upload/types';
import MsAddAttachment from '@/components/business/ms-add-attachment/index.vue'; import MsAddAttachment from '@/components/business/ms-add-attachment/index.vue';

View File

@ -11,7 +11,7 @@
:search-placeholder="t('caseManagement.caseReview.searchPlaceholder')" :search-placeholder="t('caseManagement.caseReview.searchPlaceholder')"
@keyword-search="(val, filter) => searchCase(filter)" @keyword-search="(val, filter) => searchCase(filter)"
@adv-search="searchCase" @adv-search="searchCase"
@refresh="refresh" @refresh="refresh()"
> >
<template v-if="showType !== 'list'" #nameRight> <template v-if="showType !== 'list'" #nameRight>
<div v-if="reviewPassRule === 'MULTIPLE'" class="ml-[16px]"> <div v-if="reviewPassRule === 'MULTIPLE'" class="ml-[16px]">
@ -142,6 +142,7 @@
:modules-count="props.modulesCount" :modules-count="props.modulesCount"
:review-progress="props.reviewProgress" :review-progress="props.reviewProgress"
:review-pass-rule="props.reviewPassRule" :review-pass-rule="props.reviewPassRule"
@operation="handleMinderOperation"
/> />
</div> </div>
<a-modal <a-modal
@ -168,7 +169,7 @@
size="16" size="16"
/> />
</a-tooltip> </a-tooltip>
<div class="ml-[8px] font-normal text-[var(--color-text-4)]"> <div v-show="showType === 'list'" class="ml-[8px] font-normal text-[var(--color-text-4)]">
({{ t('caseManagement.caseReview.selectedCase', { count: batchParams.currentSelectCount }) }}) ({{ t('caseManagement.caseReview.selectedCase', { count: batchParams.currentSelectCount }) }})
</div> </div>
</div> </div>
@ -301,6 +302,7 @@
import { FilterFormItem, FilterResult, FilterType } from '@/components/pure/ms-advance-filter/type'; import { FilterFormItem, FilterResult, FilterType } from '@/components/pure/ms-advance-filter/type';
import MsButton from '@/components/pure/ms-button/index.vue'; import MsButton from '@/components/pure/ms-button/index.vue';
import MsIcon from '@/components/pure/ms-icon-font/index.vue'; import MsIcon from '@/components/pure/ms-icon-font/index.vue';
import type { MinderJsonNodeData } from '@/components/pure/ms-minder-editor/props';
import MsPopconfirm from '@/components/pure/ms-popconfirm/index.vue'; import MsPopconfirm from '@/components/pure/ms-popconfirm/index.vue';
import MsRichText from '@/components/pure/ms-rich-text/MsRichText.vue'; import MsRichText from '@/components/pure/ms-rich-text/MsRichText.vue';
import MsBaseTable from '@/components/pure/ms-table/base-table.vue'; import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
@ -329,7 +331,7 @@
import useTableStore from '@/hooks/useTableStore'; import useTableStore from '@/hooks/useTableStore';
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 { findNodeByKey } from '@/utils'; import { characterLimit, findNodeByKey } from '@/utils';
import { hasAnyPermission } from '@/utils/permission'; import { hasAnyPermission } from '@/utils/permission';
import { ReviewCaseItem, ReviewItem, ReviewPassRule, ReviewResult } from '@/models/caseManagement/caseReview'; import { ReviewCaseItem, ReviewItem, ReviewPassRule, ReviewResult } from '@/models/caseManagement/caseReview';
@ -364,6 +366,7 @@
const { t } = useI18n(); const { t } = useI18n();
const { openModal } = useModal(); const { openModal } = useModal();
const minderSelectData = ref(); //
const keyword = ref(''); const keyword = ref('');
const filterRowCount = ref(0); const filterRowCount = ref(0);
const filterConfigList = ref<FilterFormItem[]>([]); const filterConfigList = ref<FilterFormItem[]>([]);
@ -522,6 +525,7 @@
: {}, : {},
}; };
setLoadListParams(tableParams.value); setLoadListParams(tableParams.value);
resetSelector();
loadList(); loadList();
emit('init', { emit('init', {
...tableParams.value, ...tableParams.value,
@ -536,12 +540,28 @@
searchCase(); searchCase();
}); });
function refresh() { /**
* 更新数据
* @param getCount 获取模块树数量
*/
function refresh(getCount = true) {
if (showType.value === 'list') { if (showType.value === 'list') {
searchCase(); if (getCount) {
searchCase();
} else {
resetSelector();
loadList();
}
} else { } else {
msCaseReviewMinderRef.value?.initCaseTree(); msCaseReviewMinderRef.value?.initCaseTree();
emit('init', { moduleIds: [props.activeFolder], projectId: appStore.currentProjectId, pageSize: 10, current: 1 }); if (getCount) {
emit('init', {
moduleIds: [props.activeFolder],
projectId: appStore.currentProjectId,
pageSize: 10,
current: 1,
});
}
} }
} }
@ -669,9 +689,13 @@
// //
function batchDisassociate() { function batchDisassociate() {
const batchDisassociateTitle =
showType.value === 'list'
? t('caseManagement.caseReview.disassociateConfirmTitle', { count: batchParams.value.currentSelectCount })
: t('testPlan.featureCase.disassociateTip', { name: characterLimit(minderSelectData.value?.text) });
openModal({ openModal({
type: 'warning', type: 'warning',
title: t('caseManagement.caseReview.disassociateConfirmTitle', { count: batchParams.value.currentSelectCount }), title: batchDisassociateTitle,
content: t('caseManagement.caseReview.disassociateTipContent'), content: t('caseManagement.caseReview.disassociateTipContent'),
okText: t('caseManagement.caseReview.disassociate'), okText: t('caseManagement.caseReview.disassociate'),
cancelText: t('common.cancel'), cancelText: t('common.cancel'),
@ -681,14 +705,21 @@
await batchDisassociateReviewCase({ await batchDisassociateReviewCase({
reviewId: route.query.id as string, reviewId: route.query.id as string,
userId: props.onlyMine ? userStore.id || '' : '', userId: props.onlyMine ? userStore.id || '' : '',
moduleIds: props.activeFolder === 'all' ? [] : [props.activeFolder, ...props.offspringIds], ...(showType.value === 'list'
...batchParams.value, ? {
...tableParams.value, moduleIds: props.activeFolder === 'all' ? [] : [props.activeFolder, ...props.offspringIds],
...batchParams.value,
...tableParams.value,
}
: {
selectIds: [minderSelectData.value.id],
selectAll: false,
condition: {},
}),
}); });
Message.success(t('common.updateSuccess')); Message.success(t('common.updateSuccess'));
dialogLoading.value = false; dialogLoading.value = false;
resetSelector(); refresh();
loadList();
emit('refresh', { emit('refresh', {
...tableParams.value, ...tableParams.value,
current: propsRes.value.msPagination?.current, current: propsRes.value.msPagination?.current,
@ -741,13 +772,21 @@
status: 'RE_REVIEWED', status: 'RE_REVIEWED',
content: dialogForm.value.reason, content: dialogForm.value.reason,
notifier: dialogForm.value.commentIds.join(';'), notifier: dialogForm.value.commentIds.join(';'),
moduleIds: props.activeFolder === 'all' ? [] : [props.activeFolder, ...props.offspringIds], ...(showType.value === 'list'
...batchParams.value, ? {
...tableParams.value, moduleIds: props.activeFolder === 'all' ? [] : [props.activeFolder, ...props.offspringIds],
...batchParams.value,
...tableParams.value,
}
: {
selectIds: [minderSelectData.value.id],
selectAll: false,
condition: {},
}),
}); });
Message.success(t('common.updateSuccess')); Message.success(t('common.updateSuccess'));
dialogVisible.value = false; dialogVisible.value = false;
resetSelector(); refresh(false);
emit('refresh', { emit('refresh', {
...tableParams.value, ...tableParams.value,
current: propsRes.value.msPagination?.current, current: propsRes.value.msPagination?.current,
@ -755,7 +794,6 @@
total: propsRes.value.msPagination?.total, total: propsRes.value.msPagination?.total,
moduleIds: [], moduleIds: [],
}); });
loadList();
} catch (error) { } catch (error) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log(error); console.log(error);
@ -775,15 +813,22 @@
userId: props.onlyMine ? userStore.id || '' : '', userId: props.onlyMine ? userStore.id || '' : '',
reviewerId: dialogForm.value.reviewer.length > 0 ? dialogForm.value.reviewer : record.reviewers, reviewerId: dialogForm.value.reviewer.length > 0 ? dialogForm.value.reviewer : record.reviewers,
append: dialogForm.value.isAppend, // append: dialogForm.value.isAppend, //
moduleIds: props.activeFolder === 'all' ? [] : [props.activeFolder, ...props.offspringIds], ...(showType.value === 'list'
...batchParams.value, ? {
...tableParams.value, moduleIds: props.activeFolder === 'all' ? [] : [props.activeFolder, ...props.offspringIds],
selectIds: batchParams.value.selectIds.length > 0 ? batchParams.value.selectIds : [record.id], ...batchParams.value,
...tableParams.value,
selectIds: batchParams.value.selectIds.length > 0 ? batchParams.value.selectIds : [record.id],
}
: {
selectIds: [minderSelectData.value.id],
selectAll: false,
condition: {},
}),
}); });
Message.success(t('common.updateSuccess')); Message.success(t('common.updateSuccess'));
dialogVisible.value = false; dialogVisible.value = false;
resetSelector(); refresh();
loadList();
} catch (error) { } catch (error) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log(error); console.log(error);
@ -862,13 +907,8 @@
} }
} }
/** function handleOperation(type?: string) {
* 处理表格选中后批量操作 switch (type) {
* @param event 批量操作事件对象
*/
function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) {
batchParams.value = { ...params, selectIds: params?.selectedIds || [], condition: {} };
switch (event.eventTag) {
case 'review': case 'review':
dialogVisible.value = true; dialogVisible.value = true;
dialogShowType.value = 'review'; dialogShowType.value = 'review';
@ -890,6 +930,21 @@
} }
} }
//
function handleMinderOperation(type: string, data: MinderJsonNodeData) {
minderSelectData.value = data;
handleOperation(type);
}
/**
* 处理表格选中后批量操作
* @param event 批量操作事件对象
*/
function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) {
batchParams.value = { ...params, selectIds: params?.selectedIds || [], condition: {} };
handleOperation(event.eventTag);
}
// //
function review(record: ReviewCaseItem) { function review(record: ReviewCaseItem) {
router.push({ router.push({