feat(功能用例): 用例评审脑图-模块操作

This commit is contained in:
teukkk 2024-07-09 12:02:34 +08:00 committed by 刘瑞斌
parent 106156a51f
commit 2de9d0534d
4 changed files with 131 additions and 98 deletions

View File

@ -11,57 +11,56 @@
:can-show-more-menu="canShowFloatMenu" :can-show-more-menu="canShowFloatMenu"
:can-show-enter-node="canShowEnterNode" :can-show-enter-node="canShowEnterNode"
:can-show-more-menu-node-operation="false" :can-show-more-menu-node-operation="false"
:more-menu-other-operation-list="canShowEnterNode ? [] : moreMenuOtherOperationList" :more-menu-other-operation-list="canShowFloatMenu ? moreMenuOtherOperationList : []"
disabled disabled
@node-select="handleNodeSelect" @node-select="handleNodeSelect"
@before-exec-command="handleBeforeExecCommand" @before-exec-command="handleBeforeExecCommand"
> >
<template #extractMenu> <template #extractMenu>
<template v-if="showCaseMenu"> <!-- 评审 查看详情 -->
<!-- 评审 查看详情 --> <a-trigger
<a-trigger v-if="hasAnyPermission(['CASE_REVIEW:READ+REVIEW']) && isReviewer"
v-if="hasAnyPermission(['CASE_REVIEW:READ+REVIEW']) && isReviewer" v-model:popup-visible="reviewVisible"
v-model:popup-visible="reviewVisible" trigger="click"
trigger="click" position="bl"
position="bl" :click-outside-to-close="false"
:click-outside-to-close="false" popup-container=".ms-minder-container"
popup-container=".ms-minder-container" >
> <a-tooltip :content="t('caseManagement.caseReview.review')">
<a-tooltip :content="t('caseManagement.caseReview.review')">
<MsButton
type="icon"
:class="[
'ms-minder-node-float-menu-icon-button',
`${reviewVisible ? 'ms-minder-node-float-menu-icon-button--focus' : ''}`,
]"
>
<MsIcon type="icon-icon_audit" class="text-[var(--color-text-4)]" />
</MsButton>
</a-tooltip>
<template #content>
<div class="w-[440px] rounded bg-white p-[16px] shadow-[0_0_10px_rgba(0,0,0,0.05)]">
<ReviewSubmit
:review-pass-rule="reviewPassRule"
:case-id="selectCaseId"
:review-id="route.query.id as string"
@done="handleReviewDone"
/>
</div>
</template>
</a-trigger>
<a-tooltip :content="t('common.detail')">
<MsButton <MsButton
type="icon" type="icon"
:class="[ :class="[
'ms-minder-node-float-menu-icon-button', 'ms-minder-node-float-menu-icon-button',
`${extraVisible ? 'ms-minder-node-float-menu-icon-button--focus' : ''}`, `${reviewVisible ? 'ms-minder-node-float-menu-icon-button--focus' : ''}`,
]" ]"
@click="toggleDetail"
> >
<MsIcon type="icon-icon_describe_outlined" class="text-[var(--color-text-4)]" /> <MsIcon type="icon-icon_audit" class="text-[var(--color-text-4)]" />
</MsButton> </MsButton>
</a-tooltip> </a-tooltip>
</template> <template #content>
<div class="w-[440px] rounded bg-white p-[16px] shadow-[0_0_10px_rgba(0,0,0,0.05)]">
<ReviewSubmit
:review-pass-rule="reviewPassRule"
:select-node="selectNode"
:user-id="props.viewFlag ? userStore.id || '' : ''"
:review-id="route.query.id as string"
@done="handleReviewDone"
/>
</div>
</template>
</a-trigger>
<a-tooltip v-if="canShowDetail" :content="t('common.detail')">
<MsButton
type="icon"
:class="[
'ms-minder-node-float-menu-icon-button',
`${extraVisible ? 'ms-minder-node-float-menu-icon-button--focus' : ''}`,
]"
@click="toggleDetail"
>
<MsIcon type="icon-icon_describe_outlined" class="text-[var(--color-text-4)]" />
</MsButton>
</a-tooltip>
</template> </template>
<template #extractTabContent> <template #extractTabContent>
<MsDescription <MsDescription
@ -169,7 +168,7 @@
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'operation', type: string, data: MinderJsonNodeData): void; (e: 'operation', type: string, node: MinderJsonNode): void;
(e: 'handleReviewDone'): void; (e: 'handleReviewDone'): void;
}>(); }>();
@ -519,16 +518,16 @@
const isReviewer = ref(false); // const isReviewer = ref(false); //
const caseReviewerList = ref<CaseReviewFunctionalCaseUserItem[]>([]); const caseReviewerList = ref<CaseReviewFunctionalCaseUserItem[]>([]);
const canShowEnterNode = ref(false); const canShowEnterNode = ref(false);
const showCaseMenu = ref(false); const canShowDetail = ref(false);
const moreMenuOtherOperationList = ref(); const moreMenuOtherOperationList = ref();
function setMoreMenuOtherOperationList(data: MinderJsonNodeData) { function setMoreMenuOtherOperationList(node: MinderJsonNode) {
moreMenuOtherOperationList.value = [ moreMenuOtherOperationList.value = [
{ {
value: 'changeReviewer', value: 'changeReviewer',
label: t('caseManagement.caseReview.changeReviewer'), label: t('caseManagement.caseReview.changeReviewer'),
permission: ['CASE_REVIEW:READ+UPDATE'], permission: ['CASE_REVIEW:READ+UPDATE'],
onClick: () => { onClick: () => {
emit('operation', 'changeReviewer', data); emit('operation', 'changeReviewer', node);
}, },
}, },
{ {
@ -536,7 +535,7 @@
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); emit('operation', 'reReview', node);
}, },
}, },
{ {
@ -544,31 +543,16 @@
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); emit('operation', 'disassociate', node);
}, },
}, },
]; ];
} }
const selectCaseId = ref(''); const selectNode = ref();
const reviewVisible = ref(false); const reviewVisible = ref(false);
function handleReviewDone(status: ReviewResultStatus) { function handleReviewDone() {
reviewVisible.value = false; reviewVisible.value = false;
let origin = window.minder.queryCommandValue('resource');
if (origin[0] !== caseTag) {
origin[0] = statusTagMap[status];
} else {
origin = [statusTagMap[status], ...origin];
}
window.minder.execCommand('resource', origin);
minderStore.dispatchEvent(
MinderEventName.SET_TAG,
undefined,
undefined,
undefined,
window.minder.getSelectedNodes()
);
setPriorityView(true, 'P');
emit('handleReviewDone'); emit('handleReviewDone');
} }
@ -594,27 +578,34 @@
setPriorityView(true, 'P'); setPriorityView(true, 'P');
return; return;
} }
// : selectNode.value = node;
// :
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.children || []).length > 0)
) { ) {
canShowFloatMenu.value = true; canShowFloatMenu.value = true;
setMoreMenuOtherOperationList(node);
} else { } else {
canShowFloatMenu.value = false; canShowFloatMenu.value = false;
} }
// : // :
if (data?.resource?.includes(moduleTag)) { if (data?.resource?.includes(moduleTag) && (node.children || []).length > 0 && node.type !== 'root') {
canShowEnterNode.value = true; canShowEnterNode.value = true;
} else { } else {
canShowEnterNode.value = false; canShowEnterNode.value = false;
} }
if (data?.resource?.includes(moduleTag) && (node.children || []).length > 0) {
isReviewer.value = true;
} else {
isReviewer.value = false;
}
if (data?.resource?.includes(caseTag)) { if (data?.resource?.includes(caseTag)) {
showCaseMenu.value = true; canShowDetail.value = true;
selectCaseId.value = node.data?.caseId ?? '';
setMoreMenuOtherOperationList(node.data as MinderJsonNodeData);
setIsReviewer(node.data); setIsReviewer(node.data);
if (extraVisible.value) { if (extraVisible.value) {
toggleDetail(true); toggleDetail(true);
@ -622,11 +613,11 @@
} else if (data?.resource?.includes(moduleTag) && data.count > 0 && data.isLoaded !== true) { } else if (data?.resource?.includes(moduleTag) && data.count > 0 && data.isLoaded !== true) {
// //
await initNodeCases(node); await initNodeCases(node);
showCaseMenu.value = false;
extraVisible.value = false; extraVisible.value = false;
canShowDetail.value = false;
} else { } else {
showCaseMenu.value = false;
extraVisible.value = false; extraVisible.value = false;
canShowDetail.value = false;
resetExtractInfo(); resetExtractInfo();
removeFakeNode(node, 'fakeNode'); removeFakeNode(node, 'fakeNode');
} }

View File

@ -0,0 +1,37 @@
import type { MinderJsonNode } from '@/components/pure/ms-minder-editor/props';
import { useI18n } from '@/hooks/useI18n';
import { mapTree } from '@/utils';
const { t } = useI18n();
export function getMinderOffspringIds(node: MinderJsonNode) {
const offspringIds: string[] = [];
mapTree(node.children || [], (e) => {
if (e.data.resource?.includes(t('common.module')) && e.data.id !== 'fakeNode') {
offspringIds.push(e.data.id);
}
return e;
});
return offspringIds;
}
/**
*
* @param node
*/
export function getMinderOperationParams(node: MinderJsonNode) {
if (node.data?.resource?.includes(t('common.module'))) {
return {
selectIds: [],
selectAll: true,
condition: {},
moduleIds: node.data?.id === 'NONE' ? [] : [node.data?.id, ...getMinderOffspringIds(node)],
};
}
return {
selectIds: [node.data?.caseId],
selectAll: false,
condition: {},
};
}

View File

@ -143,7 +143,7 @@
:review-progress="props.reviewProgress" :review-progress="props.reviewProgress"
:review-pass-rule="props.reviewPassRule" :review-pass-rule="props.reviewPassRule"
@operation="handleMinderOperation" @operation="handleMinderOperation"
@handle-review-done="emitRefresh" @handle-review-done="handleReviewDone"
/> />
</div> </div>
<a-modal <a-modal
@ -303,7 +303,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 type { MinderJsonNode, 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';
@ -313,6 +313,7 @@
import { MsFileItem } from '@/components/pure/ms-upload/types'; import { MsFileItem } from '@/components/pure/ms-upload/types';
import caseLevel from '@/components/business/ms-case-associate/caseLevel.vue'; import caseLevel from '@/components/business/ms-case-associate/caseLevel.vue';
import MsCaseReviewMinder from '@/components/business/ms-minders/caseReviewMinder/index.vue'; import MsCaseReviewMinder from '@/components/business/ms-minders/caseReviewMinder/index.vue';
import { getMinderOperationParams } from '@/components/business/ms-minders/caseReviewMinder/utils';
import MsSelect from '@/components/business/ms-select'; import MsSelect from '@/components/business/ms-select';
import { import {
@ -367,7 +368,8 @@
const { t } = useI18n(); const { t } = useI18n();
const { openModal } = useModal(); const { openModal } = useModal();
const minderSelectData = ref(); // const minderSelectData = ref<MinderJsonNodeData>(); //
const minderParams = ref();
const keyword = ref(''); const keyword = ref('');
const filterRowCount = ref(0); const filterRowCount = ref(0);
const filterConfigList = ref<FilterFormItem[]>([]); const filterConfigList = ref<FilterFormItem[]>([]);
@ -725,11 +727,7 @@
...batchParams.value, ...batchParams.value,
...tableParams.value, ...tableParams.value,
} }
: { : minderParams.value),
selectIds: [minderSelectData.value.id],
selectAll: false,
condition: {},
}),
}); });
Message.success(t('common.updateSuccess')); Message.success(t('common.updateSuccess'));
dialogLoading.value = false; dialogLoading.value = false;
@ -786,11 +784,7 @@
...batchParams.value, ...batchParams.value,
...tableParams.value, ...tableParams.value,
} }
: { : minderParams.value),
selectIds: [minderSelectData.value.id],
selectAll: false,
condition: {},
}),
}); });
Message.success(t('common.updateSuccess')); Message.success(t('common.updateSuccess'));
dialogVisible.value = false; dialogVisible.value = false;
@ -822,11 +816,7 @@
...tableParams.value, ...tableParams.value,
selectIds: batchParams.value.selectIds.length > 0 ? batchParams.value.selectIds : [record.id], selectIds: batchParams.value.selectIds.length > 0 ? batchParams.value.selectIds : [record.id],
} }
: { : minderParams.value),
selectIds: [minderSelectData.value.id],
selectAll: false,
condition: {},
}),
}); });
Message.success(t('common.updateSuccess')); Message.success(t('common.updateSuccess'));
dialogVisible.value = false; dialogVisible.value = false;
@ -927,11 +917,17 @@
} }
// //
function handleMinderOperation(type: string, data: MinderJsonNodeData) { function handleMinderOperation(type: string, node: MinderJsonNode) {
minderSelectData.value = data; minderSelectData.value = node.data;
minderParams.value = getMinderOperationParams(node);
handleOperation(type); handleOperation(type);
} }
function handleReviewDone() {
refresh(false);
emitRefresh();
}
/** /**
* 处理表格选中后批量操作 * 处理表格选中后批量操作
* @param event 批量操作事件对象 * @param event 批量操作事件对象

View File

@ -34,23 +34,31 @@
import { useEventListener } from '@vueuse/core'; import { useEventListener } from '@vueuse/core';
import { Message } from '@arco-design/web-vue'; import { Message } from '@arco-design/web-vue';
import type { MinderJsonNode } from '@/components/pure/ms-minder-editor/props';
import { getMinderOperationParams } from '@/components/business/ms-minders/caseReviewMinder/utils';
import ReviewForm from './reviewFormRichText.vue'; import ReviewForm from './reviewFormRichText.vue';
import { saveCaseReviewResult } from '@/api/modules/case-management/caseReview'; import { batchReview } from '@/api/modules/case-management/caseReview';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import useAppStore from '@/store/modules/app'; import useAppStore from '@/store/modules/app';
import { ReviewFormParams, ReviewPassRule, ReviewResult } from '@/models/caseManagement/caseReview'; import {
BatchReviewCaseParams,
ReviewFormParams,
ReviewPassRule,
ReviewResult,
} from '@/models/caseManagement/caseReview';
import { StartReviewStatus } from '@/enums/caseEnum'; import { StartReviewStatus } from '@/enums/caseEnum';
const props = defineProps<{ const props = defineProps<{
caseId: string; selectNode: MinderJsonNode;
reviewPassRule: ReviewPassRule; reviewPassRule: ReviewPassRule;
reviewId: string; reviewId: string;
userId: string;
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'done', status: ReviewResult): void; (e: 'done'): void;
}>(); }>();
const { t } = useI18n(); const { t } = useI18n();
@ -84,7 +92,7 @@
}); });
watch( watch(
() => props.caseId, () => props.selectNode.data?.caseId,
() => { () => {
form.value = { ...defaultForm }; form.value = { ...defaultForm };
} }
@ -94,18 +102,19 @@
async function submit() { async function submit() {
try { try {
submitLoading.value = true; submitLoading.value = true;
const params = { const params: BatchReviewCaseParams = {
projectId: appStore.currentProjectId, projectId: appStore.currentProjectId,
caseId: props.caseId, userId: props.userId,
reviewId: props.reviewId, reviewId: props.reviewId,
reviewPassRule: props.reviewPassRule, reviewPassRule: props.reviewPassRule,
...form.value, ...form.value,
notifier: form.value.notifiers?.join(';') ?? '', notifier: form.value.notifiers?.join(';') ?? '',
...getMinderOperationParams(props.selectNode),
}; };
await saveCaseReviewResult(params); await batchReview(params);
modalVisible.value = false; modalVisible.value = false;
Message.success(t('caseManagement.caseReview.reviewSuccess')); Message.success(t('caseManagement.caseReview.reviewSuccess'));
emit('done', form.value.status); emit('done');
} catch (error) { } catch (error) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log(error); console.log(error);