fix(用例管理): 修复功能用例详情相关权限以及评审评论详情增加用例等级问题
--bug=1037142 --user=郭雨琦 https://www.tapd.cn/55049933/bugtrace/bugs/view/1155049933001037142 --bug=1036754 --user=郭雨琦 https://www.tapd.cn/55049933/bugtrace/bugs/view/1155049933001036754 --bug=1036044 --user=郭雨琦 https://www.tapd.cn/55049933/bugtrace/bugs/view/1155049933001036044
This commit is contained in:
parent
a3aad0b82c
commit
4adc3c3355
|
@ -51,7 +51,7 @@ public class FunctionalCaseCommentController {
|
||||||
|
|
||||||
@GetMapping("/get/list/{caseId}")
|
@GetMapping("/get/list/{caseId}")
|
||||||
@Operation(summary = "用例管理-功能用例-用例评论-获取用例评论")
|
@Operation(summary = "用例管理-功能用例-用例评论-获取用例评论")
|
||||||
@RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ_COMMENT)
|
@RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ)
|
||||||
@CheckOwner(resourceId = "#caseId", resourceType = "functional_case")
|
@CheckOwner(resourceId = "#caseId", resourceType = "functional_case")
|
||||||
public List<FunctionalCaseCommentDTO> getCommentList(@PathVariable String caseId) {
|
public List<FunctionalCaseCommentDTO> getCommentList(@PathVariable String caseId) {
|
||||||
return functionalCaseCommentService.getCommentList(caseId);
|
return functionalCaseCommentService.getCommentList(caseId);
|
||||||
|
|
|
@ -61,4 +61,7 @@ public class ReviewFunctionalCaseDTO implements Serializable {
|
||||||
@Schema(description = "只看我的评审状态")
|
@Schema(description = "只看我的评审状态")
|
||||||
private String myStatus;
|
private String myStatus;
|
||||||
|
|
||||||
|
@Schema(description = "自定义字段集合")
|
||||||
|
private List<FunctionalCaseCustomFieldDTO> customFields;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,6 +111,12 @@
|
||||||
and functional_case.version_id in
|
and functional_case.version_id in
|
||||||
<include refid="io.metersphere.system.mapper.BaseMapper.filterInWrapper"/>
|
<include refid="io.metersphere.system.mapper.BaseMapper.filterInWrapper"/>
|
||||||
</when>
|
</when>
|
||||||
|
<when test="key=='caseLevel'">
|
||||||
|
and functional_case.id in (
|
||||||
|
select case_id from functional_case_custom_field where `value` in
|
||||||
|
<include refid="io.metersphere.system.mapper.BaseMapper.filterInWrapper"/>
|
||||||
|
)
|
||||||
|
</when>
|
||||||
<when test="key.startsWith('custom_single')">
|
<when test="key.startsWith('custom_single')">
|
||||||
and functional_case.id in (
|
and functional_case.id in (
|
||||||
select resource_id from custom_field_test_case where concat('custom_single-',field_id) =
|
select resource_id from custom_field_test_case where concat('custom_single-',field_id) =
|
||||||
|
|
|
@ -26,12 +26,16 @@ import io.metersphere.sdk.exception.MSException;
|
||||||
import io.metersphere.sdk.util.BeanUtils;
|
import io.metersphere.sdk.util.BeanUtils;
|
||||||
import io.metersphere.sdk.util.LogUtils;
|
import io.metersphere.sdk.util.LogUtils;
|
||||||
import io.metersphere.sdk.util.Translator;
|
import io.metersphere.sdk.util.Translator;
|
||||||
|
import io.metersphere.system.domain.CustomFieldOption;
|
||||||
import io.metersphere.system.domain.UserRoleRelation;
|
import io.metersphere.system.domain.UserRoleRelation;
|
||||||
import io.metersphere.system.domain.UserRoleRelationExample;
|
import io.metersphere.system.domain.UserRoleRelationExample;
|
||||||
import io.metersphere.system.dto.sdk.BaseTreeNode;
|
import io.metersphere.system.dto.sdk.BaseTreeNode;
|
||||||
import io.metersphere.system.dto.sdk.OptionDTO;
|
import io.metersphere.system.dto.sdk.OptionDTO;
|
||||||
import io.metersphere.system.mapper.UserRoleRelationMapper;
|
import io.metersphere.system.mapper.UserRoleRelationMapper;
|
||||||
import io.metersphere.system.notice.constants.NoticeConstants;
|
import io.metersphere.system.notice.constants.NoticeConstants;
|
||||||
|
import io.metersphere.system.service.BaseCustomFieldOptionService;
|
||||||
|
import io.metersphere.system.service.BaseCustomFieldService;
|
||||||
|
import io.metersphere.system.service.UserLoginService;
|
||||||
import io.metersphere.system.uid.IDGenerator;
|
import io.metersphere.system.uid.IDGenerator;
|
||||||
import io.metersphere.system.utils.ServiceUtils;
|
import io.metersphere.system.utils.ServiceUtils;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
|
@ -101,6 +105,14 @@ public class CaseReviewFunctionalCaseService {
|
||||||
private PermissionCheckService permissionCheckService;
|
private PermissionCheckService permissionCheckService;
|
||||||
@Resource
|
@Resource
|
||||||
private CaseReviewMapper caseReviewMapper;
|
private CaseReviewMapper caseReviewMapper;
|
||||||
|
@Resource
|
||||||
|
private FunctionalCaseCustomFieldService functionalCaseCustomFieldService;
|
||||||
|
@Resource
|
||||||
|
private BaseCustomFieldService baseCustomFieldService;
|
||||||
|
@Resource
|
||||||
|
private BaseCustomFieldOptionService baseCustomFieldOptionService;
|
||||||
|
@Resource
|
||||||
|
private UserLoginService userLoginService;
|
||||||
|
|
||||||
|
|
||||||
private static final String CASE_MODULE_COUNT_ALL = "all";
|
private static final String CASE_MODULE_COUNT_ALL = "all";
|
||||||
|
@ -150,12 +162,14 @@ public class CaseReviewFunctionalCaseService {
|
||||||
caseStatusMap = new LinkedHashMap<>();
|
caseStatusMap = new LinkedHashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<String, List<FunctionalCaseCustomFieldDTO>> collect = getCaseCustomFiledMap(caseIds);
|
||||||
|
|
||||||
list.forEach(item -> {
|
list.forEach(item -> {
|
||||||
item.setModuleName(moduleMap.get(item.getModuleId()));
|
item.setModuleName(moduleMap.get(item.getModuleId()));
|
||||||
item.setVersionName(versionMap.get(item.getVersionId()));
|
item.setVersionName(versionMap.get(item.getVersionId()));
|
||||||
item.setReviewers(Collections.singletonList(userIdMap.get(item.getCaseId())));
|
item.setReviewers(Collections.singletonList(userIdMap.get(item.getCaseId())));
|
||||||
item.setReviewNames(Collections.singletonList(userNameMap.get(item.getCaseId())));
|
item.setReviewNames(Collections.singletonList(userNameMap.get(item.getCaseId())));
|
||||||
|
item.setCustomFields(collect.get(item.getCaseId()));
|
||||||
if (request.isViewStatusFlag()) {
|
if (request.isViewStatusFlag()) {
|
||||||
List<CaseReviewHistory> histories = caseStatusMap.get(item.getCaseId());
|
List<CaseReviewHistory> histories = caseStatusMap.get(item.getCaseId());
|
||||||
if (CollectionUtils.isNotEmpty(histories)) {
|
if (CollectionUtils.isNotEmpty(histories)) {
|
||||||
|
@ -170,6 +184,23 @@ public class CaseReviewFunctionalCaseService {
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<String, List<FunctionalCaseCustomFieldDTO>> getCaseCustomFiledMap(List<String> ids) {
|
||||||
|
List<FunctionalCaseCustomFieldDTO> customFields = functionalCaseCustomFieldService.getCustomFieldsByCaseIds(ids);
|
||||||
|
customFields.forEach(customField -> {
|
||||||
|
if (customField.getInternal()) {
|
||||||
|
customField.setFieldName(baseCustomFieldService.translateInternalField(customField.getFieldName()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
List<String> fieldIds = customFields.stream().map(FunctionalCaseCustomFieldDTO::getFieldId).toList();
|
||||||
|
List<CustomFieldOption> fieldOptions = baseCustomFieldOptionService.getByFieldIds(fieldIds);
|
||||||
|
Map<String, List<CustomFieldOption>> customOptions = fieldOptions.stream().collect(Collectors.groupingBy(CustomFieldOption::getFieldId));
|
||||||
|
customFields.forEach(customField -> {
|
||||||
|
customField.setOptions(customOptions.get(customField.getFieldId()));
|
||||||
|
});
|
||||||
|
return customFields.stream().collect(Collectors.groupingBy(FunctionalCaseCustomFieldDTO::getCaseId));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private String getMyStatus(List<CaseReviewHistory> histories, String viewStatusUserId) {
|
private String getMyStatus(List<CaseReviewHistory> histories, String viewStatusUserId) {
|
||||||
List<CaseReviewHistory> list = histories.stream().filter(history -> StringUtils.equalsIgnoreCase(history.getCreateUser(), viewStatusUserId)).toList();
|
List<CaseReviewHistory> list = histories.stream().filter(history -> StringUtils.equalsIgnoreCase(history.getCreateUser(), viewStatusUserId)).toList();
|
||||||
if (CollectionUtils.isNotEmpty(list)) {
|
if (CollectionUtils.isNotEmpty(list)) {
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
<span class="text-[var(--color-text-4)]">({{ element.childComments?.length }})</span>
|
<span class="text-[var(--color-text-4)]">({{ element.childComments?.length }})</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
v-if="hasAnyPermission(['PROJECT_BUG:READ+COMMENT', 'FUNCTIONAL_CASE:READ+COMMENT'])"
|
||||||
class="comment-btn hover:bg-[var(--color-bg-3)]"
|
class="comment-btn hover:bg-[var(--color-bg-3)]"
|
||||||
:class="{ 'bg-[var(--color-text-n8)]': status === 'reply' }"
|
:class="{ 'bg-[var(--color-text-n8)]': status === 'reply' }"
|
||||||
@click="replyClick"
|
@click="replyClick"
|
||||||
|
@ -63,6 +64,7 @@
|
||||||
|
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useUserStore from '@/store/modules/user/index';
|
import useUserStore from '@/store/modules/user/index';
|
||||||
|
import { hasAnyPermission } from '@/utils/permission';
|
||||||
|
|
||||||
import { CommentItem } from './types';
|
import { CommentItem } from './types';
|
||||||
|
|
||||||
|
@ -81,7 +83,10 @@
|
||||||
|
|
||||||
// 是否拥有编辑|删除权限
|
// 是否拥有编辑|删除权限
|
||||||
const hasAuth = computed(() => {
|
const hasAuth = computed(() => {
|
||||||
return props.element.createUser === userStore.id;
|
return (
|
||||||
|
props.element.createUser === userStore.id &&
|
||||||
|
hasAnyPermission(['PROJECT_BUG:READ+COMMENT', 'FUNCTIONAL_CASE:READ+COMMENT'])
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const status = defineModel<'normal' | 'edit' | 'reply' | 'delete'>('status', { default: 'normal' });
|
const status = defineModel<'normal' | 'edit' | 'reply' | 'delete'>('status', { default: 'normal' });
|
||||||
|
|
|
@ -318,7 +318,7 @@
|
||||||
.ms-drawer-no-mask {
|
.ms-drawer-no-mask {
|
||||||
left: auto;
|
left: auto;
|
||||||
.arco-drawer {
|
.arco-drawer {
|
||||||
box-shadow: -1px 0 4px 0 rgb(2 2 2 / 10%);
|
box-shadow: 0 4px 10px -1px rgb(100 100 102 / 15%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.ms-drawer-no-content-padding {
|
.ms-drawer-no-content-padding {
|
||||||
|
|
|
@ -952,7 +952,7 @@
|
||||||
versionId: '',
|
versionId: '',
|
||||||
refId: '',
|
refId: '',
|
||||||
});
|
});
|
||||||
Message.success(t('common.updateSuccess'));
|
Message.success(t('case.detail.execute.success'));
|
||||||
cancelBatchExecute();
|
cancelBatchExecute();
|
||||||
loadCaseListAndResetSelector();
|
loadCaseListAndResetSelector();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
@ -519,6 +519,9 @@
|
||||||
// );
|
// );
|
||||||
const total = ref<number>(0);
|
const total = ref<number>(0);
|
||||||
async function initBugList() {
|
async function initBugList() {
|
||||||
|
if (!hasAnyPermission(['PROJECT_BUG:READ'])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const res = await getBugList({
|
const res = await getBugList({
|
||||||
current: 1,
|
current: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
|
|
|
@ -32,10 +32,13 @@
|
||||||
</template>
|
</template>
|
||||||
<template v-if="(keyword || '').trim() === ''" #empty>
|
<template v-if="(keyword || '').trim() === ''" #empty>
|
||||||
<div class="flex w-full items-center justify-center text-[var(--color-text-4)]">
|
<div class="flex w-full items-center justify-center text-[var(--color-text-4)]">
|
||||||
{{ t('caseManagement.caseReview.tableNoData') }}
|
<span v-if="hasAnyPermission(['FUNCTIONAL_CASE:READ+UPDATE'])">{{
|
||||||
|
t('caseManagement.caseReview.tableNoData')
|
||||||
|
}}</span>
|
||||||
|
<span v-else>{{ t('caseManagement.featureCase.tableNoData') }}</span>
|
||||||
|
|
||||||
<a-dropdown @select="handleSelect">
|
<a-dropdown @select="handleSelect">
|
||||||
<MsButton class="ml-[8px]">
|
<MsButton v-permission="['FUNCTIONAL_CASE:READ+UPDATE']" class="ml-[8px]">
|
||||||
{{ t('caseManagement.featureCase.linkCase') }}
|
{{ t('caseManagement.featureCase.linkCase') }}
|
||||||
</MsButton>
|
</MsButton>
|
||||||
<template #content>
|
<template #content>
|
||||||
|
@ -89,6 +92,7 @@
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import { useAppStore } from '@/store';
|
import { useAppStore } from '@/store';
|
||||||
import useFeatureCaseStore from '@/store/modules/case/featureCase';
|
import useFeatureCaseStore from '@/store/modules/case/featureCase';
|
||||||
|
import { hasAnyPermission } from '@/utils/permission';
|
||||||
|
|
||||||
import type { TableQueryParams } from '@/models/common';
|
import type { TableQueryParams } from '@/models/common';
|
||||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||||
|
|
|
@ -132,25 +132,21 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getAllCommentList() {
|
async function getAllCommentList() {
|
||||||
if (hasAnyPermission(['FUNCTIONAL_CASE:READ+COMMENT'])) {
|
switch (activeComment.value) {
|
||||||
switch (activeComment.value) {
|
case 'caseComment':
|
||||||
case 'caseComment':
|
await initCommentList();
|
||||||
await initCommentList();
|
featureCaseStore.getCaseCounts(props.caseId);
|
||||||
featureCaseStore.getCaseCounts(props.caseId);
|
break;
|
||||||
break;
|
case 'reviewComment':
|
||||||
case 'reviewComment':
|
await initReviewCommentList();
|
||||||
await initReviewCommentList();
|
featureCaseStore.getCaseCounts(props.caseId);
|
||||||
featureCaseStore.getCaseCounts(props.caseId);
|
break;
|
||||||
break;
|
case 'executiveComment':
|
||||||
case 'executiveComment':
|
await initCommentList();
|
||||||
await initCommentList();
|
featureCaseStore.getCaseCounts(props.caseId);
|
||||||
featureCaseStore.getCaseCounts(props.caseId);
|
break;
|
||||||
break;
|
default:
|
||||||
default:
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Message.error(t('common.noPermission'));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,21 +6,53 @@
|
||||||
><span class="one-text-line text-[rgb(var(--primary-5))]">({{ (record.children || []).length || 0 }})</span>
|
><span class="one-text-line text-[rgb(var(--primary-5))]">({{ (record.children || []).length || 0 }})</span>
|
||||||
</template>
|
</template>
|
||||||
<template #operation="{ record }">
|
<template #operation="{ record }">
|
||||||
<MsButton @click="emit('cancel', record)">
|
<MsButton
|
||||||
|
v-permission="['FUNCTIONAL_CASE:READ+ADD', 'FUNCTIONAL_CASE:READ+UPDATE', 'FUNCTIONAL_CASE:READ+DELETE']"
|
||||||
|
@click="emit('cancel', record)"
|
||||||
|
>
|
||||||
{{ t('caseManagement.featureCase.cancelAssociation') }}
|
{{ t('caseManagement.featureCase.cancelAssociation') }}
|
||||||
</MsButton>
|
</MsButton>
|
||||||
<MsButton v-if="record.demandPlatform === pageConfig.platformName" @click="emit('update', record)">
|
<MsButton
|
||||||
|
v-if="record.demandPlatform === pageConfig.platformName"
|
||||||
|
v-permission="['FUNCTIONAL_CASE:READ+ADD', 'FUNCTIONAL_CASE:READ+UPDATE', 'FUNCTIONAL_CASE:READ+DELETE']"
|
||||||
|
@click="emit('update', record)"
|
||||||
|
>
|
||||||
{{ t('common.edit') }}
|
{{ t('common.edit') }}
|
||||||
</MsButton>
|
</MsButton>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="(props.funParams.keyword || '').trim() === '' && props.showEmpty" #empty>
|
<template v-if="(props.funParams.keyword || '').trim() === '' && props.showEmpty" #empty>
|
||||||
<div class="flex w-full items-center justify-center text-[var(--color-text-4)]">
|
<div class="flex w-full items-center justify-center text-[var(--color-text-4)]">
|
||||||
{{ t('caseManagement.caseReview.tableNoData') }}
|
<span
|
||||||
<MsButton class="ml-[8px]" @click="emit('associate')">
|
v-if="
|
||||||
|
hasAnyPermission(['FUNCTIONAL_CASE:READ+ADD', 'FUNCTIONAL_CASE:READ+UPDATE', 'FUNCTIONAL_CASE:READ+DELETE'])
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ t('caseManagement.caseReview.tableNoData') }}
|
||||||
|
</span>
|
||||||
|
<span v-else> {{ t('caseManagement.featureCase.tableNoData') }} </span>
|
||||||
|
<MsButton
|
||||||
|
v-if="
|
||||||
|
hasAnyPermission(['FUNCTIONAL_CASE:READ+ADD', 'FUNCTIONAL_CASE:READ+UPDATE', 'FUNCTIONAL_CASE:READ+DELETE'])
|
||||||
|
"
|
||||||
|
class="ml-[8px]"
|
||||||
|
@click="emit('associate')"
|
||||||
|
>
|
||||||
{{ t('caseManagement.featureCase.associatedDemand') }}
|
{{ t('caseManagement.featureCase.associatedDemand') }}
|
||||||
</MsButton>
|
</MsButton>
|
||||||
{{ t('caseManagement.featureCase.or') }}
|
<span
|
||||||
<MsButton class="ml-[8px]" @click="emit('create')">
|
v-if="
|
||||||
|
hasAnyPermission(['FUNCTIONAL_CASE:READ+ADD', 'FUNCTIONAL_CASE:READ+UPDATE', 'FUNCTIONAL_CASE:READ+DELETE'])
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ t('caseManagement.featureCase.or') }}
|
||||||
|
</span>
|
||||||
|
<MsButton
|
||||||
|
v-if="
|
||||||
|
hasAnyPermission(['FUNCTIONAL_CASE:READ+ADD', 'FUNCTIONAL_CASE:READ+UPDATE', 'FUNCTIONAL_CASE:READ+DELETE'])
|
||||||
|
"
|
||||||
|
class="ml-[8px]"
|
||||||
|
@click="emit('create')"
|
||||||
|
>
|
||||||
{{ t('caseManagement.featureCase.addDemand') }}
|
{{ t('caseManagement.featureCase.addDemand') }}
|
||||||
</MsButton>
|
</MsButton>
|
||||||
</div>
|
</div>
|
||||||
|
@ -41,6 +73,7 @@
|
||||||
import { useAppStore } from '@/store';
|
import { useAppStore } from '@/store';
|
||||||
import useFeatureCaseStore from '@/store/modules/case/featureCase';
|
import useFeatureCaseStore from '@/store/modules/case/featureCase';
|
||||||
import { characterLimit } from '@/utils';
|
import { characterLimit } from '@/utils';
|
||||||
|
import { hasAnyPermission } from '@/utils/permission';
|
||||||
|
|
||||||
import type { DemandItem } from '@/models/caseManagement/featureCase';
|
import type { DemandItem } from '@/models/caseManagement/featureCase';
|
||||||
|
|
||||||
|
|
|
@ -288,7 +288,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function openDemandUrl(record: DemandItem) {
|
function openDemandUrl(record: DemandItem) {
|
||||||
window.open(record.demandUrl);
|
if (record.demandUrl) {
|
||||||
|
window.open(record.demandUrl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const platformInfo = ref<Record<string, any>>({});
|
const platformInfo = ref<Record<string, any>>({});
|
||||||
|
|
|
@ -51,8 +51,11 @@
|
||||||
</template>
|
</template>
|
||||||
<template v-if="(keyword || '').trim() === ''" #empty>
|
<template v-if="(keyword || '').trim() === ''" #empty>
|
||||||
<div class="flex w-full items-center justify-center text-[var(--color-text-4)]">
|
<div class="flex w-full items-center justify-center text-[var(--color-text-4)]">
|
||||||
{{ t('caseManagement.caseReview.tableNoData') }}
|
<span v-if="hasAnyPermission(['FUNCTIONAL_CASE:READ+UPDATE'])">{{
|
||||||
<MsButton class="ml-[8px]" @click="addCase">
|
t('caseManagement.caseReview.tableNoData')
|
||||||
|
}}</span>
|
||||||
|
<span v-else>{{ t('caseManagement.featureCase.tableNoData') }}</span>
|
||||||
|
<MsButton v-if="hasAnyPermission(['FUNCTIONAL_CASE:READ+UPDATE'])" class="ml-[8px]" @click="addCase">
|
||||||
{{
|
{{
|
||||||
showType === 'preposition'
|
showType === 'preposition'
|
||||||
? t('caseManagement.featureCase.addPresetCase')
|
? t('caseManagement.featureCase.addPresetCase')
|
||||||
|
@ -88,6 +91,7 @@
|
||||||
import { useAppStore } from '@/store';
|
import { useAppStore } from '@/store';
|
||||||
import useFeatureCaseStore from '@/store/modules/case/featureCase';
|
import useFeatureCaseStore from '@/store/modules/case/featureCase';
|
||||||
import { characterLimit } from '@/utils';
|
import { characterLimit } from '@/utils';
|
||||||
|
import { hasAnyPermission } from '@/utils/permission';
|
||||||
|
|
||||||
const featureCaseStore = useFeatureCaseStore();
|
const featureCaseStore = useFeatureCaseStore();
|
||||||
// const activeTab = computed(() => featureCaseStore.activeTab);
|
// const activeTab = computed(() => featureCaseStore.activeTab);
|
||||||
|
|
|
@ -32,10 +32,36 @@
|
||||||
v-on="propsEvent"
|
v-on="propsEvent"
|
||||||
@batch-action="handleTableBatch"
|
@batch-action="handleTableBatch"
|
||||||
>
|
>
|
||||||
<template #resultTitle>
|
<template #resultTitle="{ columnConfig }">
|
||||||
<div class="flex items-center text-[var(--color-text-3)]">
|
<a-trigger
|
||||||
{{ t('caseManagement.caseReview.reviewResult') }}
|
v-model:popup-visible="statusFilterVisible"
|
||||||
</div>
|
trigger="click"
|
||||||
|
@popup-visible-change="handleFilterHidden"
|
||||||
|
>
|
||||||
|
<a-button type="text" class="arco-btn-text--secondary p-[8px_4px]" @click="statusFilterVisible = true">
|
||||||
|
<div class="font-medium">
|
||||||
|
{{ t(columnConfig.title as string) }}
|
||||||
|
</div>
|
||||||
|
<icon-down :class="statusFilterVisible ? 'text-[rgb(var(--primary-5))]' : ''" />
|
||||||
|
</a-button>
|
||||||
|
<template #content>
|
||||||
|
<div class="arco-table-filters-content">
|
||||||
|
<div class="flex items-center justify-center px-[6px] py-[2px]">
|
||||||
|
<a-checkbox-group v-model:model-value="statusFilters" direction="vertical" size="small">
|
||||||
|
<a-checkbox v-for="key of Object.keys(reviewResultMap)" :key="key" :value="key">
|
||||||
|
<a-tag
|
||||||
|
:color="reviewResultMap[key].color"
|
||||||
|
:class="[reviewResultMap[key].class, 'px-[4px]']"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
{{ t(reviewResultMap[key].label) }}
|
||||||
|
</a-tag>
|
||||||
|
</a-checkbox>
|
||||||
|
</a-checkbox-group>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</a-trigger>
|
||||||
</template>
|
</template>
|
||||||
<template #num="{ record }">
|
<template #num="{ record }">
|
||||||
<a-tooltip :content="record.num">
|
<a-tooltip :content="record.num">
|
||||||
|
@ -44,6 +70,23 @@
|
||||||
</a-button>
|
</a-button>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</template>
|
</template>
|
||||||
|
<template #caseLevel="{ record }">
|
||||||
|
<span class="text-[var(--color-text-2)]"> <caseLevel :case-level="record.caseLevel" /></span>
|
||||||
|
</template>
|
||||||
|
<template #caseLevelFilter="{ columnConfig }">
|
||||||
|
<TableFilter
|
||||||
|
v-model:visible="caseFilterVisible"
|
||||||
|
v-model:status-filters="caseFilters"
|
||||||
|
:title="(columnConfig.title as string)"
|
||||||
|
:list="caseLevelList"
|
||||||
|
value-key="value"
|
||||||
|
@search="searchCase()"
|
||||||
|
>
|
||||||
|
<template #item="{ item }">
|
||||||
|
<div class="flex"> <caseLevel :case-level="item.text" /></div>
|
||||||
|
</template>
|
||||||
|
</TableFilter>
|
||||||
|
</template>
|
||||||
<template #reviewNames="{ record }">
|
<template #reviewNames="{ record }">
|
||||||
<a-tooltip :content="record.reviewNames.join('、')">
|
<a-tooltip :content="record.reviewNames.join('、')">
|
||||||
<div class="one-line-text">{{ record.reviewNames.join('、') }}</div>
|
<div class="one-line-text">{{ record.reviewNames.join('、') }}</div>
|
||||||
|
@ -246,7 +289,9 @@
|
||||||
import type { BatchActionParams, BatchActionQueryParams, MsTableColumn } from '@/components/pure/ms-table/type';
|
import type { BatchActionParams, BatchActionQueryParams, MsTableColumn } from '@/components/pure/ms-table/type';
|
||||||
import useTable from '@/components/pure/ms-table/useTable';
|
import useTable from '@/components/pure/ms-table/useTable';
|
||||||
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 MsSelect from '@/components/business/ms-select';
|
import MsSelect from '@/components/business/ms-select';
|
||||||
|
import TableFilter from '@/views/case-management/caseManagementFeature/components/tableFilter.vue';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
batchChangeReviewer,
|
batchChangeReviewer,
|
||||||
|
@ -256,7 +301,7 @@
|
||||||
getReviewDetailCasePage,
|
getReviewDetailCasePage,
|
||||||
getReviewUsers,
|
getReviewUsers,
|
||||||
} from '@/api/modules/case-management/caseReview';
|
} from '@/api/modules/case-management/caseReview';
|
||||||
import { editorUploadFile } from '@/api/modules/case-management/featureCase';
|
import { editorUploadFile, getCaseDefaultFields } from '@/api/modules/case-management/featureCase';
|
||||||
import { getProjectMemberCommentOptions } from '@/api/modules/project-management/projectMember';
|
import { getProjectMemberCommentOptions } from '@/api/modules/project-management/projectMember';
|
||||||
import { reviewResultMap } from '@/config/caseManagement';
|
import { reviewResultMap } from '@/config/caseManagement';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
@ -271,6 +316,13 @@
|
||||||
import { CaseManagementRouteEnum } from '@/enums/routeEnum';
|
import { CaseManagementRouteEnum } from '@/enums/routeEnum';
|
||||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||||
|
|
||||||
|
const caseLevelFields = ref<Record<string, any>>({});
|
||||||
|
const caseFilterVisible = ref(false);
|
||||||
|
const caseFilters = ref<string[]>([]);
|
||||||
|
const caseLevelList = computed(() => {
|
||||||
|
return caseLevelFields.value?.options || [];
|
||||||
|
});
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
activeFolder: string | number;
|
activeFolder: string | number;
|
||||||
onlyMine: boolean;
|
onlyMine: boolean;
|
||||||
|
@ -293,6 +345,9 @@
|
||||||
const filterConfigList = ref<FilterFormItem[]>([]);
|
const filterConfigList = ref<FilterFormItem[]>([]);
|
||||||
const tableParams = ref<Record<string, any>>({});
|
const tableParams = ref<Record<string, any>>({});
|
||||||
|
|
||||||
|
const statusFilterVisible = ref(false);
|
||||||
|
const statusFilters = ref<string[]>(Object.keys(reviewResultMap));
|
||||||
|
|
||||||
const hasOperationPermission = computed(() =>
|
const hasOperationPermission = computed(() =>
|
||||||
hasAnyPermission(['CASE_REVIEW:READ+REVIEW', 'CASE_REVIEW:READ+RELEVANCE'])
|
hasAnyPermission(['CASE_REVIEW:READ+REVIEW', 'CASE_REVIEW:READ+RELEVANCE'])
|
||||||
);
|
);
|
||||||
|
@ -319,6 +374,15 @@
|
||||||
showTooltip: true,
|
showTooltip: true,
|
||||||
width: 200,
|
width: 200,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: 'caseManagement.featureCase.tableColumnLevel',
|
||||||
|
slotName: 'caseLevel',
|
||||||
|
dataIndex: 'caseLevel',
|
||||||
|
titleSlotName: 'caseLevelFilter',
|
||||||
|
showInTable: true,
|
||||||
|
width: 200,
|
||||||
|
showDrag: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: 'caseManagement.caseReview.reviewer',
|
title: 'caseManagement.caseReview.reviewer',
|
||||||
dataIndex: 'reviewNames',
|
dataIndex: 'reviewNames',
|
||||||
|
@ -393,6 +457,7 @@
|
||||||
moduleIds: props.activeFolder === 'all' ? [] : [props.activeFolder, ...props.offspringIds],
|
moduleIds: props.activeFolder === 'all' ? [] : [props.activeFolder, ...props.offspringIds],
|
||||||
keyword: keyword.value,
|
keyword: keyword.value,
|
||||||
viewFlag: props.onlyMine,
|
viewFlag: props.onlyMine,
|
||||||
|
filter: { status: statusFilters.value, caseLevel: caseFilters.value },
|
||||||
combine: filter
|
combine: filter
|
||||||
? {
|
? {
|
||||||
...filter.combine,
|
...filter.combine,
|
||||||
|
@ -410,6 +475,12 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleFilterHidden(val: boolean) {
|
||||||
|
if (!val) {
|
||||||
|
searchCase();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
searchCase();
|
searchCase();
|
||||||
});
|
});
|
||||||
|
@ -548,6 +619,13 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取用例等级数据
|
||||||
|
async function getCaseLevelFields() {
|
||||||
|
const result = await getCaseDefaultFields(appStore.currentProjectId);
|
||||||
|
caseLevelFields.value = result.customFields.find((item: any) => item.internal && item.fieldName === '用例等级');
|
||||||
|
caseFilters.value = caseLevelFields.value?.options.map((item: any) => item.text);
|
||||||
|
}
|
||||||
|
|
||||||
// 批量重新评审
|
// 批量重新评审
|
||||||
async function reReview() {
|
async function reReview() {
|
||||||
try {
|
try {
|
||||||
|
@ -715,6 +793,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
onBeforeMount(async () => {
|
onBeforeMount(async () => {
|
||||||
|
getCaseLevelFields();
|
||||||
const [, memberRes] = await Promise.all([
|
const [, memberRes] = await Promise.all([
|
||||||
initReviewers(),
|
initReviewers(),
|
||||||
getProjectMemberCommentOptions(appStore.currentProjectId, keyword.value),
|
getProjectMemberCommentOptions(appStore.currentProjectId, keyword.value),
|
||||||
|
|
|
@ -64,7 +64,7 @@ export default {
|
||||||
'caseManagement.caseReview.belongModulePlaceholder': '请选择该评审所属模块',
|
'caseManagement.caseReview.belongModulePlaceholder': '请选择该评审所属模块',
|
||||||
'caseManagement.caseReview.reviewerPlaceholder': '请选择评审人',
|
'caseManagement.caseReview.reviewerPlaceholder': '请选择评审人',
|
||||||
'caseManagement.caseReview.defaultReviewer': '默认评审人',
|
'caseManagement.caseReview.defaultReviewer': '默认评审人',
|
||||||
'caseManagement.caseReview.defaultReviewerRequired': '默认评审人',
|
'caseManagement.caseReview.defaultReviewerRequired': '默认评审人不能为空',
|
||||||
'caseManagement.caseReview.defaultReviewerTip': '新添加的用例,评审人为默认评审人',
|
'caseManagement.caseReview.defaultReviewerTip': '新添加的用例,评审人为默认评审人',
|
||||||
'caseManagement.caseReview.pickCases': '选择需要评审的用例',
|
'caseManagement.caseReview.pickCases': '选择需要评审的用例',
|
||||||
'caseManagement.caseReview.switchProject': '切换项目:',
|
'caseManagement.caseReview.switchProject': '切换项目:',
|
||||||
|
|
Loading…
Reference in New Issue