fix: 全局bug&添加用例相关标表头筛选

This commit is contained in:
xinxin.wu 2024-02-24 12:41:19 +08:00 committed by 刘瑞斌
parent c8fd930be2
commit 01f4631797
40 changed files with 678 additions and 309 deletions

View File

@ -156,7 +156,7 @@ export function getCaseDetail(id: string) {
return MSR.get({ url: `${DetailCaseUrl}/${id}` });
}
// 批量删除用例
export function batchDeleteCase(data: BatchDeleteType) {
export function batchDeleteCase(data: TableQueryParams) {
return MSR.post({ url: `${BatchDeleteCaseUrl}`, data });
}
// 批量编辑属性
@ -180,7 +180,7 @@ export function getRecycleListRequest(data: TableQueryParams) {
return MSR.post<CommonList<CaseManagementTable>>({ url: GetRecycleCaseListUrl, data });
}
// 获取回收站模块数量
export function getRecycleModulesCounts(data: CaseModuleQueryParams) {
export function getRecycleModulesCounts(data: TableQueryParams) {
return MSR.post({ url: GetRecycleCaseModulesCountUrl, data });
}
// 获取全部用例模块数量
@ -188,11 +188,11 @@ export function getCaseModulesCounts(data: TableQueryParams) {
return MSR.post({ url: GetCaseModulesCountUrl, data });
}
// 批量恢复回收站用例表
export function restoreCaseList(data: BatchMoveOrCopyType) {
export function restoreCaseList(data: TableQueryParams) {
return MSR.post({ url: RestoreCaseListUrl, data });
}
// 批量彻底删除回收站用例表
export function batchDeleteRecycleCase(data: BatchMoveOrCopyType) {
export function batchDeleteRecycleCase(data: TableQueryParams) {
return MSR.post({ url: BatchDeleteRecycleCaseListUrl, data });
}
// 恢复回收站单个用例

View File

@ -6,6 +6,7 @@ import {
EditProjectMemberUrl,
GetProjectMemberListUrl,
ProjectMemberCommentOptions,
ProjectMemberList,
ProjectMemberOptions,
ProjectUserGroupUrl,
RemoveProjectMemberUrl,
@ -52,6 +53,10 @@ export function getProjectUserGroup(projectId: string) {
export function getProjectMemberOptions(projectId: string, keyword?: string) {
return MSR.get({ url: `${ProjectMemberOptions}/${projectId}`, params: { keyword } });
}
// 项目成员下拉选项不包含组织
export function getProjectOptions(projectId: string, keyword?: string) {
return MSR.get({ url: `${ProjectMemberList}/${projectId}`, params: { keyword } });
}
// 项目成员-@成员下拉选项
export function getProjectMemberCommentOptions(projectId: string, keyword?: string) {

View File

@ -6,4 +6,5 @@ export const RemoveProjectMemberUrl = '/project/member/remove';
export const BatchAddUserGroup = '/project/member/add-role';
export const ProjectUserGroupUrl = '/project/member/get-role/option';
export const ProjectMemberOptions = '/project/member/get-member/option';
export const ProjectMemberList = '/project/get-member/option';
export const ProjectMemberCommentOptions = '/project/member/comment/user-option'; // 项目成员-@成员下拉列表

View File

@ -333,6 +333,9 @@
padding-right: 16px;
}
.arco-textarea-wrapper {
resize: vertical !important;
}
/** form-item **/
.arco-form-item-content-flex {

View File

@ -21,7 +21,7 @@
<div class="flex flex-1 items-center justify-between">
<div class="flex items-center">
<a-tooltip :content="props.title">
<span> {{ props.title }}</span>
<span> {{ characterLimit(props.title) }}</span>
</a-tooltip>
<slot name="headerLeft"></slot>
@ -119,8 +119,8 @@
import useFullScreen from '@/hooks/useFullScreen';
import { useI18n } from '@/hooks/useI18n';
import { characterLimit } from '@/utils';
import { getMaxZIndexLayer } from '@/utils/dom';
//
const MsDescription = defineAsyncComponent(() => import('@/components/pure/ms-description/index.vue'));

View File

@ -149,11 +149,8 @@ export const TEXTAREA = {
value: '',
props: {
'placeholder': t('formCreate.PleaseEnter'),
'auto-size': {
minRows: 1,
maxRows: 3,
},
'max-length': 1000,
'auto-size': '{ minRows: 1 }',
},
};
export const JIRAKEY = {

View File

@ -11,7 +11,7 @@
<template v-if="showJumpMethod">
<div class="mb-2 flex items-center">
<span class="text-[var(--color-text-4)]">{{ t('msTable.columnSetting.mode') }}</span>
<a-tooltip>
<a-tooltip position="right">
<template #content>
<span>{{ t('msTable.columnSetting.tooltipContentDrawer') }}</span
><br />

View File

@ -309,46 +309,116 @@ export const pathMap: PathMapItem[] = [
level: MENU_LEVEL[1],
},
{
key: 'SETTING_ORGANIZATION_TEMPLATE', // 系统设置-组织-模板
locale: 'menu.settings.organization.template',
key: 'SETTING_ORGANIZATION_TEMPLATE', // 系统设置-组织-模板管理
locale: 'menu.projectManagement.templateManager',
route: RouteEnum.SETTING_ORGANIZATION_TEMPLATE,
permission: [],
level: MENU_LEVEL[1],
},
{
key: 'SETTING_ORGANIZATION_TEMPLATE_FILED_SETTING', // 系统设置-模板管理-字段设置
locale: 'menu.settings.organization.templateFieldSetting',
route: RouteEnum.SETTING_ORGANIZATION_TEMPLATE_FILED_SETTING,
permission: [],
level: MENU_LEVEL[1],
},
{
key: 'SETTING_ORGANIZATION_TEMPLATE_MANAGEMENT', // 系统设置-模板管理列表
locale: 'menu.settings.organization.templateManagementList',
route: RouteEnum.SETTING_ORGANIZATION_TEMPLATE_MANAGEMENT,
permission: [],
level: MENU_LEVEL[1],
},
{
key: 'SETTING_ORGANIZATION_TEMPLATE_MANAGEMENT_CREATE', // 系统设置-模板管理-创建
locale: 'menu.settings.organization.templateManagementDetail',
route: RouteEnum.SETTING_ORGANIZATION_TEMPLATE_MANAGEMENT_DETAIL,
permission: [],
level: MENU_LEVEL[1],
},
{
key: 'SETTING_ORGANIZATION_TEMPLATE_MANAGEMENT_UPDATE', // 系统设置-模板管理-更新模版
locale: 'menu.settings.organization.templateManagementEdit',
route: RouteEnum.SETTING_ORGANIZATION_TEMPLATE_MANAGEMENT_DETAIL,
permission: [],
level: MENU_LEVEL[1],
},
{
key: 'SETTING_ORGANIZATION_TEMPLATE_MANAGEMENT_WORKFLOW', // 系统设置-模板管理-工作流
locale: 'menu.settings.organization.templateManagementWorkFlow',
route: RouteEnum.SETTING_ORGANIZATION_TEMPLATE_MANAGEMENT_WORKFLOW,
permission: [],
level: MENU_LEVEL[1],
children: [
{
key: 'SETTING_ORGANIZATION_TEMPLATE_FUNCTIONAL', // 模板管理-用例模板
locale: 'system.orgTemplate.caseTemplates',
route: RouteEnum.SETTING_ORGANIZATION_TEMPLATE_MANAGEMENT,
permission: [],
routeQuery: {
type: 'FUNCTIONAL',
},
level: MENU_LEVEL[1],
children: [
{
key: 'SETTING_ORGANIZATION_TEMPLATE_FUNCTIONAL_FIELD', // 模板管理-用例模板-用例模板字段管理
locale: 'system.orgTemplate.field',
route: RouteEnum.SETTING_ORGANIZATION_TEMPLATE_FILED_SETTING,
permission: [],
routeQuery: {
type: 'FUNCTIONAL',
},
level: MENU_LEVEL[1],
},
{
key: 'SETTING_ORGANIZATION_TEMPLATE_FUNCTIONAL_TEMPLATE', // 模板管理-用例模板-用例模板管理
locale: 'system.orgTemplate.caseTemplateManagement',
route: RouteEnum.SETTING_ORGANIZATION_TEMPLATE_MANAGEMENT,
permission: [],
routeQuery: {
type: 'FUNCTIONAL',
},
level: MENU_LEVEL[1],
},
],
},
{
key: 'SETTING_ORGANIZATION_TEMPLATE_API', // 模板管理-接口模板
locale: 'system.orgTemplate.APITemplates',
route: RouteEnum.SETTING_ORGANIZATION_TEMPLATE_MANAGEMENT,
permission: [],
routeQuery: {
type: 'API',
},
level: MENU_LEVEL[1],
children: [
{
key: 'SETTING_ORGANIZATION_TEMPLATE_API_FIELD', // 模板管理-接口模板-接口模板字段管理
locale: 'system.orgTemplate.field',
route: RouteEnum.SETTING_ORGANIZATION_TEMPLATE_FILED_SETTING,
permission: [],
routeQuery: {
type: 'API',
},
level: MENU_LEVEL[1],
},
{
key: 'SETTING_ORGANIZATION_TEMPLATE_API_TEMPLATE', // 模板管理-接口模板-接口模板管理
locale: 'system.orgTemplate.apiTemplateManagement',
route: RouteEnum.SETTING_ORGANIZATION_TEMPLATE_MANAGEMENT,
permission: [],
routeQuery: {
type: 'API',
},
level: MENU_LEVEL[1],
},
],
},
{
key: 'SETTING_ORGANIZATION_TEMPLATE_BUG', // 模板管理-缺陷模板
locale: 'system.orgTemplate.defectTemplates',
route: RouteEnum.SETTING_ORGANIZATION_TEMPLATE_MANAGEMENT,
permission: [],
routeQuery: {
type: 'BUG',
},
level: MENU_LEVEL[1],
children: [
{
key: 'SETTING_ORGANIZATION_TEMPLATE_BUG_FIELD', // 模板管理-缺陷模板管理-字段管理
locale: 'system.orgTemplate.field',
route: RouteEnum.SETTING_ORGANIZATION_TEMPLATE_FILED_SETTING,
permission: [],
routeQuery: {
type: 'BUG',
},
level: MENU_LEVEL[1],
},
{
key: 'SETTING_ORGANIZATION_TEMPLATE_BUG_TEMPLATE', // 模板管理-缺陷模板-缺陷模板管理
locale: 'system.orgTemplate.bugTemplateManagement',
route: RouteEnum.SETTING_ORGANIZATION_TEMPLATE_MANAGEMENT,
permission: [],
routeQuery: {
type: 'BUG',
},
level: MENU_LEVEL[1],
},
{
key: 'SETTING_ORGANIZATION_TEMPLATE_BUG_WORKFLOW', // 模板管理-缺陷模板-缺陷工作流
locale: 'menu.settings.organization.templateManagementWorkFlow',
route: RouteEnum.SETTING_ORGANIZATION_TEMPLATE_MANAGEMENT_WORKFLOW,
permission: [],
level: MENU_LEVEL[1],
},
],
},
],
},
],
},
@ -406,54 +476,118 @@ export const pathMap: PathMapItem[] = [
],
},
{
key: 'PROJECT_MANAGEMENT_TEMPLATE', // 项目管理-模板管理
locale: 'menu.settings.organization.template',
key: 'PROJECT_MANAGEMENT_TEMPLATE', // 系统设置-组织-模板管理
locale: 'menu.projectManagement.templateManager',
route: RouteEnum.PROJECT_MANAGEMENT_TEMPLATE,
permission: [],
level: MENU_LEVEL[2],
},
{
key: 'PROJECT_MANAGEMENT_TEMPLATE_FIELD_SETTING', // 项目管理-模板管理-字段设置
locale: 'menu.settings.organization.templateFieldSetting',
route: RouteEnum.PROJECT_MANAGEMENT_TEMPLATE_FIELD_SETTING,
permission: [],
level: MENU_LEVEL[2],
},
{
key: 'PROJECT_CUSTOM_FIELD', // 项目管理-模板管理-字段设置-新增字段
locale: 'system.orgTemplate.addField',
route: '',
permission: [],
level: MENU_LEVEL[2],
},
{
key: 'PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT', // 项目管理-模板管理列表
locale: 'menu.settings.organization.templateManagementList',
route: RouteEnum.PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT,
permission: [],
level: MENU_LEVEL[2],
},
{
key: 'PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT_CREATE', // 项目管理-模板管理-创建模版
locale: 'menu.settings.organization.templateManagementDetail',
route: RouteEnum.PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT_DETAIL,
permission: [],
level: MENU_LEVEL[2],
},
{
key: 'PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT_UPDATE', // 项目管理-模板管理-更新模版
locale: 'menu.settings.organization.templateManagementEdit',
route: RouteEnum.PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT_DETAIL,
permission: [],
level: MENU_LEVEL[2],
},
{
key: 'PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT_WORKFLOW', // 项目管理-模板管理-工作流
locale: 'menu.settings.organization.templateManagementWorkFlow',
route: RouteEnum.PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT_WORKFLOW,
permission: [],
level: MENU_LEVEL[2],
level: MENU_LEVEL[1],
children: [
{
key: 'PROJECT_MANAGEMENT_TEMPLATE_FUNCTIONAL', // 模板管理-用例模板
locale: 'system.orgTemplate.caseTemplates',
route: RouteEnum.PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT,
permission: [],
routeQuery: {
type: 'FUNCTIONAL',
},
level: MENU_LEVEL[1],
children: [
{
key: 'PROJECT_MANAGEMENT_TEMPLATE_FUNCTIONAL_FIELD', // 模板管理-用例模板-用例模板字段管理
locale: 'system.orgTemplate.field',
route: RouteEnum.PROJECT_MANAGEMENT_TEMPLATE_FIELD_SETTING,
permission: [],
routeQuery: {
type: 'FUNCTIONAL',
},
level: MENU_LEVEL[1],
},
{
key: 'PROJECT_MANAGEMENT_TEMPLATE_FUNCTIONAL_TEMPLATE', // 模板管理-用例模板-用例模板管理
locale: 'system.orgTemplate.caseTemplateManagement',
route: RouteEnum.PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT,
permission: [],
routeQuery: {
type: 'FUNCTIONAL',
},
level: MENU_LEVEL[1],
},
],
},
{
key: 'PROJECT_MANAGEMENT_TEMPLATE_API', // 模板管理-接口模板
locale: 'system.orgTemplate.APITemplates',
route: RouteEnum.PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT,
permission: [],
routeQuery: {
type: 'API',
},
level: MENU_LEVEL[1],
children: [
{
key: 'PROJECT_MANAGEMENT_TEMPLATE_API_FIELD', // 模板管理-接口模板-接口模板字段管理
locale: 'system.orgTemplate.field',
route: RouteEnum.PROJECT_MANAGEMENT_TEMPLATE_FIELD_SETTING,
permission: [],
routeQuery: {
type: 'API',
},
level: MENU_LEVEL[1],
},
{
key: 'PROJECT_MANAGEMENT_TEMPLATE_API_TEMPLATE', // 模板管理-接口模板-接口模板管理
locale: 'system.orgTemplate.apiTemplateManagement',
route: RouteEnum.PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT,
permission: [],
routeQuery: {
type: 'API',
},
level: MENU_LEVEL[1],
},
],
},
{
key: 'PROJECT_MANAGEMENT_TEMPLATE_BUG', // 模板管理-缺陷模板
locale: 'system.orgTemplate.defectTemplates',
route: RouteEnum.PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT,
permission: [],
routeQuery: {
type: 'BUG',
},
level: MENU_LEVEL[1],
children: [
{
key: 'PROJECT_MANAGEMENT_TEMPLATE_BUG_FIELD', // 模板管理-缺陷模板管理-字段管理
locale: 'system.orgTemplate.field',
route: RouteEnum.PROJECT_MANAGEMENT_TEMPLATE_FIELD_SETTING,
permission: [],
routeQuery: {
type: 'BUG',
},
level: MENU_LEVEL[1],
},
{
key: 'PROJECT_MANAGEMENT_TEMPLATE_BUG_TEMPLATE', // 模板管理-缺陷模板-缺陷模板管理
locale: 'system.orgTemplate.bugTemplateManagement',
route: RouteEnum.PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT,
permission: [],
routeQuery: {
type: 'BUG',
},
level: MENU_LEVEL[1],
},
{
key: 'PROJECT_MANAGEMENT_TEMPLATE_BUG_WORKFLOW', // 模板管理-缺陷模板-缺陷工作流
locale: 'menu.settings.organization.templateManagementWorkFlow',
route: RouteEnum.PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT_WORKFLOW,
permission: [],
level: MENU_LEVEL[1],
},
],
},
],
},
{
key: 'PROJECT_MANAGEMENT_FILE_MANAGEMENT', // 项目管理-文件管理
locale: 'menu.projectManagement.fileManagement',

View File

@ -1,9 +1,16 @@
import { defineStore } from 'pinia';
import { getCaseModulesCounts, getRecycleModulesCounts } from '@/api/modules/case-management/featureCase';
import {
getCaseDefaultFields,
getCaseDetail,
getCaseModulesCounts,
getRecycleModulesCounts,
} from '@/api/modules/case-management/featureCase';
import type { CaseModuleQueryParams, TabItemType } from '@/models/caseManagement/featureCase';
import { ModuleTreeNode } from '@/models/common';
import type { CaseModuleQueryParams, CustomAttributes, TabItemType } from '@/models/caseManagement/featureCase';
import { ModuleTreeNode, TableQueryParams } from '@/models/common';
import useAppStore from '../app';
const useFeatureCaseStore = defineStore('featureCase', {
persist: true,
@ -15,6 +22,8 @@ const useFeatureCaseStore = defineStore('featureCase', {
operatingState: boolean; // 操作状态
tabSettingList: TabItemType[]; // 详情tab
activeTab: string; // 激活tab
defaultFields: CustomAttributes[];
defaultCount: Record<string, any>;
} => ({
moduleId: [],
caseTree: [],
@ -23,6 +32,8 @@ const useFeatureCaseStore = defineStore('featureCase', {
operatingState: false,
tabSettingList: [],
activeTab: 'detail',
defaultFields: [],
defaultCount: {},
}),
actions: {
// 设置选择moduleId
@ -38,18 +49,17 @@ const useFeatureCaseStore = defineStore('featureCase', {
this.caseTree = tree;
},
// 获取模块数量
async getCaseModulesCount(params: CaseModuleQueryParams) {
async getCaseModulesCount(params: TableQueryParams) {
try {
this.modulesCount = {};
// this.modulesCount = {};
this.modulesCount = await getCaseModulesCounts(params);
} catch (error) {
console.log(error);
}
},
// 获取模块数量
async getRecycleModulesCount(params: CaseModuleQueryParams) {
async getRecycleModulesCount(params: TableQueryParams) {
try {
this.recycleModulesCount = {};
this.recycleModulesCount = await getRecycleModulesCounts(params);
} catch (error) {
console.log(error);
@ -90,6 +100,39 @@ const useFeatureCaseStore = defineStore('featureCase', {
};
});
},
// 获取默认模版
async getDefaultTemplate() {
try {
const appStore = useAppStore();
const result = await getCaseDefaultFields(appStore.currentProjectId);
this.defaultFields = result.customFields;
} catch (error) {
console.log(error);
}
},
// 获取系统字段用例等级
getSystemCaseLevelFields() {
return this.defaultFields.find((item: any) => item.internal && item.fieldName === '用例等级')?.options || [];
},
// 获取详情
async getCaseCounts(caseId: string) {
try {
const result = await getCaseDetail(caseId);
const { bugCount, caseCount, caseReviewCount, demandCount, relateEdgeCount, testPlanCount } = result;
const countMap: Record<string, any> = {
case: caseCount,
dependency: relateEdgeCount,
caseReview: caseReviewCount,
testPlan: testPlanCount,
bug: bugCount,
requirement: demandCount,
};
this.initCountMap(countMap);
} catch (error) {
console.log(error);
}
},
},
});

View File

@ -160,10 +160,12 @@
//
function copyStep(record: StepList) {
stepData.value.push({
const index = stepData.value.map((item: any) => item.id).indexOf(record.id);
const insertItem = {
...record,
id: getGenerateId(),
});
};
stepData.value.splice(index + 1, 0, insertItem);
}
//

View File

@ -158,6 +158,7 @@
formRef.value?.resetFields();
form.value = { ...initForm };
formRules.value = [{ ...initDefaultForm }];
form.value.tags = [];
}
async function confirmHandler(enable: boolean | undefined) {
@ -174,12 +175,12 @@
});
const { selectedIds, selectAll } = props.batchParams;
const params: TableQueryParams = {
selectedIds,
selectIds: selectAll ? [] : selectedIds,
selectAll,
projectId: currentProjectId.value,
append: enable as boolean,
tags: form.value.tags,
customField,
customField: form.value.selectedAttrsId === 'systemTags' ? {} : customField,
};
await batchEditAttrs(params);
Message.success(t('caseManagement.featureCase.editSuccess'));

View File

@ -186,6 +186,12 @@
<span class="label"> {{ t('caseManagement.featureCase.tableColumnCreateTime') }}</span>
<span>{{ dayjs(detailInfo?.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
</div>
<div class="baseItem">
<span class="label"> {{ t('caseManagement.featureCase.tableColumnCreateTime') }}</span>
<span>
<MsTag v-for="item of detailInfo.tags" :key="item"> {{ item }} </MsTag>
</span>
</div>
</div>
</template>
</MsSplitBox>
@ -216,6 +222,7 @@
import type { FormItem, FormRuleItem } from '@/components/pure/ms-form-create/types';
import MsSplitBox from '@/components/pure/ms-split-box/index.vue';
import type { MsPaginationI } from '@/components/pure/ms-table/type';
import MsTag from '@/components/pure/ms-tag/ms-tag.vue';
import caseLevel from '@/components/business/ms-case-associate/caseLevel.vue';
import type { CaseLevel } from '@/components/business/ms-case-associate/types';
import inputComment from '@/components/business/ms-comment/input.vue';
@ -365,6 +372,7 @@
async function updateSuccess() {
detailDrawerRef.value?.initDetail();
emit('success');
}
function updateHandler(type: string) {
@ -627,6 +635,7 @@
line-height: 32px;
@apply flex;
.label {
flex-shrink: 0;
width: 38%;
color: var(--color-text-3);
}

View File

@ -37,12 +37,14 @@
@change="changeHandler"
>
<template #num="{ record, rowIndex }">
<a-button type="text" class="flex w-full" @click="showCaseDetail(record.id, rowIndex)">{{ record.num }}</a-button>
<span type="text" class="px-0" @click="showCaseDetail(record.id, rowIndex)">{{ record.num }}</span>
</template>
<template #name="{ record, rowIndex }">
<span type="text" class="px-0" @click="showCaseDetail(record.id, rowIndex)">{{ record.name }}</span>
<a-button type="text" class="flex w-full" @click="showCaseDetail(record.id, rowIndex)">{{
record.name
}}</a-button>
</template>
<template #updateUser="{ record }">
<template #updateUserName="{ record }">
<span type="text" class="px-0">{{ record.updateUserName || '-' }}</span>
</template>
<template #caseLevel="{ record }">
@ -337,7 +339,7 @@
getCustomFieldsTable,
updateCaseRequest,
} from '@/api/modules/case-management/featureCase';
import { getProjectMemberOptions } from '@/api/modules/project-management/projectMember';
import { getProjectOptions } from '@/api/modules/project-management/projectMember';
import { useI18n } from '@/hooks/useI18n';
import useModal from '@/hooks/useModal';
import { useAppStore, useTableStore } from '@/store';
@ -491,6 +493,7 @@
{
title: 'caseManagement.featureCase.tableColumnLevel',
slotName: 'caseLevel',
dataIndex: 'caseLevel',
titleSlotName: 'caseLevelFilter',
showInTable: true,
width: 200,
@ -541,7 +544,7 @@
},
{
title: 'caseManagement.featureCase.tableColumnUpdateUser',
slotName: 'updateUser',
slotName: 'updateUserName,',
dataIndex: 'updateUser',
titleSlotName: 'updateUserFilter',
sortable: {
@ -657,9 +660,11 @@
const searchCustomFields = ref<FilterFormItem[]>([]);
const scrollWidth = ref<number>(3400);
const memberOptions = ref<{ label: string; value: string }[]>([]);
const updateUserFilters = ref<string[]>([]);
const createUserFilters = ref<string[]>([]);
async function initFilter() {
const result = await getCustomFieldsTable(currentProjectId.value);
memberOptions.value = await getProjectMemberOptions(appStore.currentProjectId, keyword.value);
memberOptions.value = await getProjectOptions(appStore.currentProjectId, keyword.value);
memberOptions.value = memberOptions.value.map((e: any) => ({ label: e.name, value: e.id }));
filterConfigList.value = [
{
@ -796,7 +801,7 @@
selectable: true,
showJumpMethod: true,
showSetting: true,
heightUsed: 374,
heightUsed: 380,
enableDrag: true,
},
(record) => {
@ -815,13 +820,41 @@
updateCaseName
);
const batchParams = ref<BatchActionQueryParams>({
selectedIds: [],
selectAll: false,
excludeIds: [],
currentSelectCount: 0,
});
const statusFilters = ref<string[]>(Object.keys(statusIconMap));
const caseFilters = ref<string[]>([]);
const executeResultFilters = ref(Object.keys(executionResultMap));
function initTableParams() {
return {
keyword: keyword.value,
moduleIds: props.activeFolder === 'all' ? [] : [props.activeFolder, ...props.offspringIds],
projectId: currentProjectId.value,
filter: {
reviewStatus: statusFilters.value,
caseLevel: caseFilters.value,
lastExecuteResult: executeResultFilters.value,
updateUserName: updateUserFilters.value,
createUserName: createUserFilters.value,
},
condition: {
keyword: keyword.value,
filter: propsRes.value.filter,
combine: batchParams.value.condition,
},
};
}
//
function emitTableParams() {
const moduleIds = props.activeFolder === 'all' ? [] : [props.activeFolder, ...props.offspringIds];
emit('init', {
keyword: keyword.value,
moduleIds,
projectId: currentProjectId.value,
...initTableParams(),
current: propsRes.value.msPagination?.current,
pageSize: propsRes.value.msPagination?.pageSize,
});
@ -837,7 +870,7 @@
projectId: currentProjectId.value,
moduleIds: [],
});
const statusFilters = ref<string[]>(Object.keys(statusIconMap));
const caseLevelFields = ref<Record<string, any>>({});
//
const caseFilterVisible = ref(false);
@ -846,10 +879,6 @@
return caseLevelFields.value?.options || [];
});
const executeResultFilters = ref(Object.keys(executionResultMap));
const updateUserFilters = ref(memberOptions.value.map((item) => item.value));
const createUserFilters = ref(memberOptions.value.map((item) => item.value));
function getExecuteResultList() {
const list: any = [];
Object.keys(executionResultMap).forEach((key) => {
@ -860,7 +889,6 @@
return list;
}
const executeResultFilterList = ref(getExecuteResultList());
const caseFilters = ref<string[]>([]);
function getLoadListParams() {
if (props.activeFolder === 'all') {
@ -868,17 +896,7 @@
} else {
searchParams.value.moduleIds = [...featureCaseStore.moduleId, ...props.offspringIds];
}
setLoadListParams({
...searchParams.value,
keyword: keyword.value,
filter: {
reviewStatus: statusFilters.value,
caseLevel: caseFilters.value,
lastExecuteResult: executeResultFilters.value,
updateUserName: updateUserFilters.value,
createUserName: createUserFilters.value,
},
});
setLoadListParams(initTableParams());
}
//
@ -971,13 +989,6 @@
const selectedModuleKeys = ref<string[]>([]); //
const batchMoveCaseLoading = ref(false);
const batchParams = ref<BatchActionQueryParams>({
selectedIds: [],
selectAll: false,
excludeIds: [],
currentSelectCount: 0,
});
const isMove = ref<boolean>(false);
//
async function handleCaseMoveOrCopy() {
@ -987,7 +998,11 @@
selectIds: batchParams.value.selectedIds || [],
selectAll: !!batchParams.value?.selectAll,
excludeIds: batchParams.value?.excludeIds || [],
condition: { keyword: keyword.value },
condition: {
keyword: keyword.value,
filter: propsRes.value.filter,
combine: batchParams.value.condition,
},
projectId: currentProjectId.value,
moduleIds: props.activeFolder === 'all' ? [] : [props.activeFolder, ...props.offspringIds],
moduleId: selectedModuleKeys.value[0],
@ -1056,9 +1071,17 @@
},
onBeforeOk: async () => {
try {
const { selectedIds, selectAll, excludeIds } = batchParams.value;
await batchDeleteCase({
selectIds: batchParams.value.selectedIds as string[],
projectId: currentProjectId.value,
selectIds: selectAll ? [] : selectedIds,
excludeIds: excludeIds || [],
condition: {
keyword: keyword.value,
filter: propsRes.value.filter,
combine: batchParams.value.condition,
},
selectAll,
});
resetSelector();
Message.success(t('common.deleteSuccess'));
@ -1132,14 +1155,12 @@
const fetchData = (keywordStr = '') => {
setKeyword(keywordStr);
getLoadListParams();
loadList();
initData();
};
function successHandler() {
initData();
emitTableParams();
resetSelector();
initData();
}
const showDetailDrawer = ref(false);
const activeDetailId = ref<string>('');
@ -1165,6 +1186,7 @@
//
async function getDefaultFields() {
customFieldsColumns = [];
const result = await getCaseDefaultFields(currentProjectId.value);
initDefaultFields.value = result.customFields;
customFieldsColumns = initDefaultFields.value
@ -1180,7 +1202,7 @@
};
});
caseLevelFields.value = result.customFields.find((item: any) => item.internal);
caseLevelFields.value = result.customFields.find((item: any) => item.internal && item.fieldName === '用例等级');
caseFilters.value = caseLevelFields.value.options.map((item: any) => item.value);
fullColumns = [
...columns.slice(0, columns.length - 1),
@ -1419,7 +1441,7 @@
showCaseDetail(route.query.id as string, 0);
}
await getDefaultFields();
initFilter();
await initFilter();
initData();
});

View File

@ -179,7 +179,7 @@
<a-form-item
field="moduleId"
asterisk-position="end"
:label="t('system.orgTemplate.modules')"
:label="t('caseManagement.featureCase.ModuleOwned')"
:rules="[{ required: true, message: t('system.orgTemplate.moduleRuleTip') }]"
@change="changeSelectModule"
>
@ -505,7 +505,7 @@
const { customFields, attachments, steps } = detailResult;
form.value = {
...detailResult,
name: route.params.mode === 'copy' ? `${detailResult.name}_copy` : detailResult.name,
name: route.params.mode === 'copy' ? `copy_${detailResult.name}` : detailResult.name,
};
//
formRules.value = (customFields || []).map((item: any) => {

View File

@ -66,8 +66,9 @@
:filter-config-list="filterConfigList"
:custom-fields-config-list="searchCustomFields"
:row-count="filterRowCount"
@keyword-search="initRecycleList"
@keyword-search="fetchData"
@adv-search="handleAdvSearch"
@refresh="fetchData()"
>
<template #left>
<div class="text-[var(--color-text-1)]"
@ -196,9 +197,12 @@
<span class="one-line-text inline-block">{{ getModules(record.moduleId) }}</span>
</a-tooltip>
</template>
<template #updateUser="{ record }">
<template #updateUserName="{ record }">
<span type="text" class="px-0">{{ record.updateUserName || '-' }}</span>
</template>
<template #createUserName="{ record }">
<span type="text" class="px-0">{{ record.createUserName || '-' }}</span>
</template>
<!-- 回收站自定义字段 -->
<template v-for="item in customFieldsColumns" :key="item.slotName" #[item.slotName]="{ record }">
<a-tooltip
@ -260,19 +264,14 @@
recoverRecycleCase,
restoreCaseList,
} from '@/api/modules/case-management/featureCase';
import { getProjectMemberOptions } from '@/api/modules/project-management/projectMember';
import { getProjectOptions } from '@/api/modules/project-management/projectMember';
import { useI18n } from '@/hooks/useI18n';
import useModal from '@/hooks/useModal';
import { useAppStore, useTableStore } from '@/store';
import useFeatureCaseStore from '@/store/modules/case/featureCase';
import { characterLimit, findNodeByKey, findNodePathByKey, mapTree } from '@/utils';
import type {
BatchMoveOrCopyType,
CaseManagementTable,
CaseModuleQueryParams,
CustomAttributes,
} from '@/models/caseManagement/featureCase';
import type { BatchMoveOrCopyType, CaseManagementTable, CustomAttributes } from '@/models/caseManagement/featureCase';
import type { ModuleTreeNode, TableQueryParams } from '@/models/common';
import { TableKeyEnum } from '@/enums/tableEnum';
@ -291,7 +290,7 @@
const currentProjectId = computed(() => appStore.currentProjectId);
const scrollWidth = ref<number>(3400);
const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector, setAdvanceFilter } = useTable(
const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector, setAdvanceFilter, setKeyword } = useTable(
getRecycleListRequest,
{
tableKey: TableKeyEnum.CASE_MANAGEMENT_RECYCLE_TABLE,
@ -299,7 +298,7 @@
selectable: true,
showSetting: true,
showJumpMethod: true,
heightUsed: 340,
heightUsed: 380,
enableDrag: true,
},
(record) => ({
@ -395,7 +394,7 @@
},
{
title: 'caseManagement.featureCase.tableColumnUpdateUser',
slotName: 'updateUser',
slotName: 'updateUserName',
dataIndex: 'updateUser',
titleSlotName: 'updateUserFilter',
sortable: {
@ -421,7 +420,8 @@
{
title: 'caseManagement.featureCase.tableColumnCreateUser',
slotName: 'createUserName',
dataIndex: 'createUserName',
dataIndex: 'createUser',
titleSlotName: 'createUserFilter',
showInTable: true,
width: 200,
showDrag: true,
@ -562,23 +562,30 @@
: findNodeByKey<Record<string, any>>(caseTree.value, featureCaseStore.moduleId[0], 'id')?.name;
});
const memberOptions = ref<{ label: string; value: string }[]>([]);
const searchParams = ref<TableQueryParams>({
projectId: currentProjectId.value,
moduleIds: [],
});
const batchParams = ref<BatchActionQueryParams>({
selectedIds: [],
selectAll: false,
excludeIds: [],
currentSelectCount: 0,
});
//
const statusFilters = ref<string[]>(Object.keys(statusIconMap));
const caseLevelFields = ref<Record<string, any>>({});
//
const caseFilterVisible = ref(false);
const caseLevelList = computed(() => {
return caseLevelFields.value?.options || [];
});
const caseFilters = ref<string[]>([]);
const executeResultFilters = ref(Object.keys(executionResultMap));
const updateUserFilters = ref(memberOptions.value.map((item) => item.value));
const createUserFilters = ref(memberOptions.value.map((item) => item.value));
const updateUserFilters = ref<string[]>([]);
const createUserFilters = ref<string[]>([]);
function getExecuteResultList() {
const list: any = [];
@ -591,41 +598,58 @@
}
const executeResultFilterList = ref(getExecuteResultList());
// count
const emitTableParams: CaseModuleQueryParams = {
keyword: keyword.value,
moduleIds: [],
projectId: currentProjectId.value,
current: propsRes.value.msPagination?.current,
pageSize: propsRes.value.msPagination?.pageSize,
};
//
function initRecycleModulesCount() {
featureCaseStore.getRecycleModulesCount(emitTableParams);
}
const batchParams = ref<BatchActionQueryParams>({
selectedIds: [],
selectAll: false,
excludeIds: [],
currentSelectCount: 0,
});
//
function getBatchParams(): BatchMoveOrCopyType {
function getBatchParams(): TableQueryParams {
return {
excludeIds: batchParams.value.excludeIds,
selectAll: batchParams.value.selectAll,
selectIds: batchParams.value.selectedIds,
condition: {
keyword: keyword.value,
},
moduleIds: searchParams.value.moduleIds,
projectId: currentProjectId.value,
filter: {
reviewStatus: statusFilters.value,
caseLevel: caseFilters.value,
lastExecuteResult: executeResultFilters.value,
updateUserName: updateUserFilters.value,
createUserName: createUserFilters.value,
},
condition: {
keyword: keyword.value,
filter: propsRes.value.filter,
combine: batchParams.value.condition,
},
};
}
function initTableParams() {
return {
keyword: keyword.value,
moduleIds: activeFolder.value === 'all' ? [] : [activeFolder.value, ...offspringIds.value],
projectId: currentProjectId.value,
filter: {
reviewStatus: statusFilters.value,
caseLevel: caseFilters.value,
lastExecuteResult: executeResultFilters.value,
updateUserName: updateUserFilters.value,
createUserName: createUserFilters.value,
},
condition: {
keyword: keyword.value,
filter: propsRes.value.filter,
combine: batchParams.value.condition,
},
};
}
//
function initRecycleModulesCount() {
featureCaseStore.getRecycleModulesCount({
...initTableParams(),
current: propsRes.value.msPagination?.current,
pageSize: propsRes.value.msPagination?.pageSize,
});
}
//
function getLoadListParams() {
if (activeFolder.value === 'all') {
@ -633,17 +657,7 @@
} else {
searchParams.value.moduleIds = [activeFolder.value, ...offspringIds.value];
}
setLoadListParams({
...searchParams.value,
keyword: keyword.value,
filter: {
reviewStatus: statusFilters.value,
caseLevel: caseFilters.value,
lastExecuteResult: executeResultFilters.value,
updateUserName: updateUserFilters.value,
createUserName: createUserFilters.value,
},
});
setLoadListParams(initTableParams());
}
//
@ -652,19 +666,24 @@
const createUserFilterVisible = ref(false);
//
function initRecycleList() {
async function initRecycleList() {
getLoadListParams();
loadList();
await loadList();
initRecycleModulesCount();
}
const fetchData = (keywordStr = '') => {
setKeyword(keywordStr);
initRecycleList();
};
//
async function handleBatchRecover() {
try {
await restoreCaseList(getBatchParams());
Message.success(t('caseManagement.featureCase.recoveredSuccessfully'));
initRecycleList();
resetSelector();
initRecycleModulesCount();
initRecycleList();
} catch (error) {
console.log(error);
}
@ -684,9 +703,8 @@
try {
await batchDeleteRecycleCase(getBatchParams());
Message.success(t('common.deleteSuccess'));
loadList();
resetSelector();
initRecycleModulesCount();
initRecycleList();
} catch (error) {
console.log(error);
}
@ -723,9 +741,8 @@
try {
await recoverRecycleCase(id);
Message.success(t('caseManagement.featureCase.recoveredSuccessfully'));
loadList();
resetSelector();
initRecycleModulesCount();
initRecycleList();
} catch (error) {
console.log(error);
}
@ -746,8 +763,8 @@
try {
await deleteRecycleCaseList(record.id);
Message.success(t('common.deleteSuccess'));
loadList();
initRecycleModulesCount();
resetSelector();
initRecycleList();
} catch (error) {
console.log(error);
}
@ -783,7 +800,6 @@
//
let customFieldsColumns: Record<string, any>[] = [];
const tableRef = ref<InstanceType<typeof MsBaseTable> | null>(null);
const initDefaultFields = ref<CustomAttributes[]>([]);
@ -791,6 +807,7 @@
//
async function getDefaultFields() {
customFieldsColumns = [];
const result = await getCaseDefaultFields(currentProjectId.value);
initDefaultFields.value = result.customFields.filter((item: any) => !item.internal);
customFieldsColumns = initDefaultFields.value.map((item: any) => {
@ -803,7 +820,7 @@
width: 300,
};
});
caseLevelFields.value = result.customFields.find((item: any) => item.internal);
caseLevelFields.value = result.customFields.find((item: any) => item.internal && item.fieldName === '用例等级');
caseFilters.value = caseLevelFields.value.options.map((item: any) => item.value);
fullColumns = [
...columns.slice(0, columns.length - 1),
@ -815,7 +832,7 @@
async function initFilter() {
const result = await getCustomFieldsTable(currentProjectId.value);
memberOptions.value = await getProjectMemberOptions(appStore.currentProjectId, keyword.value);
memberOptions.value = await getProjectOptions(appStore.currentProjectId, keyword.value);
memberOptions.value = memberOptions.value.map((e: any) => ({ label: e.name, value: e.id }));
filterConfigList.value = [
{
@ -953,11 +970,10 @@
}
onMounted(async () => {
await getDefaultFields();
initFilter();
initRecycleList();
getRecycleModules();
initRecycleModulesCount();
await getDefaultFields();
await initFilter();
initRecycleList();
});
</script>

View File

@ -17,14 +17,14 @@
</div>
<div v-else class="font-medium">{{ t('caseManagement.featureCase.testPlanLinkList') }}</div>
<div class="mb-4">
<!-- <a-radio-group v-model:model-value="showType" type="button" class="file-show-type ml-[4px]">
<a-radio-group v-model:model-value="showType" type="button" class="file-show-type ml-[4px]">
<a-radio value="link" class="show-type-icon p-[2px]">{{
t('caseManagement.featureCase.directLink')
}}</a-radio>
<a-radio value="testPlan" class="show-type-icon p-[2px]">{{
<!-- <a-radio value="testPlan" class="show-type-icon p-[2px]">{{
t('caseManagement.featureCase.testPlan')
}}</a-radio>
</a-radio-group> -->
}}</a-radio> -->
</a-radio-group>
<a-input-search
v-model:model-value="keyword"
:placeholder="t('caseManagement.featureCase.searchByNameAndId')"
@ -267,8 +267,7 @@
} else {
setTestPlanListParams({ keyword: keyword.value, projectId: appStore.currentProjectId, caseId: props.caseId });
await testPlanLinkList();
const { msPagination } = testPlanPropsRes.value;
featureCaseStore.setListCount(featureCaseStore.activeTab, msPagination?.total || 0);
featureCaseStore.getCaseCounts(props.caseId);
}
}
const cancelLoading = ref<boolean>(false);

View File

@ -265,8 +265,7 @@
sourceType: currentSelectCase.value,
});
await loadList();
const { msPagination } = propsRes.value;
featureCaseStore.setListCount(featureCaseStore.activeTab, msPagination?.total || 0);
featureCaseStore.getCaseCounts(props.caseId);
}
async function searchCase() {

View File

@ -99,15 +99,14 @@
columns,
tableKey: TableKeyEnum.CASE_MANAGEMENT_TAB_REVIEW,
scroll: { x: '100%' },
heightUsed: 340,
heightUsed: 360,
enableDrag: true,
});
async function initData() {
setLoadListParams({ keyword: keyword.value, caseId: props.caseId });
await loadList();
const { msPagination } = propsRes.value;
featureCaseStore.setListCount(featureCaseStore.activeTab, msPagination?.total || 0);
featureCaseStore.getCaseCounts(props.caseId);
}
const searchList = debounce(() => {

View File

@ -225,8 +225,7 @@
module: 'FUNCTIONAL_CASE',
});
await loadList();
const { msPagination } = propsRes.value;
featureCaseStore.setListCount(featureCaseStore.activeTab, msPagination?.total || 0);
featureCaseStore.getCaseCounts(props.caseId);
}
onMounted(() => {

View File

@ -71,6 +71,7 @@
const emit = defineEmits<{
(e: 'update:visible', v: boolean): void;
(e: 'update:form', v: CreateOrUpdateDemand): void;
(e: 'success'): void;
(e: 'save', params: CreateOrUpdateDemand, isContinue: boolean): void;
}>();
@ -85,8 +86,6 @@
const showModal = ref<boolean>(false);
// const confirmLoading = ref<boolean>(false);
const initModelForm: DemandFormList = {
demandId: '',
demandName: '',
@ -124,6 +123,12 @@
}
});
}
const title = ref<string>('');
watchEffect(() => {
title.value = form.value.id
? t('caseManagement.featureCase.updateDemand', { name: props.form.demandName })
: t('caseManagement.featureCase.addDemand');
});
watch(
() => props.visible,
@ -139,22 +144,25 @@
}
);
const title = ref<string>('');
watchEffect(() => {
title.value = form.value.id
? t('caseManagement.featureCase.updateDemand', { name: props.form.demandName })
: t('caseManagement.featureCase.addDemand');
});
watch(
() => props.form,
(val) => {
form.value.id = '';
modelForm.value = { ...val };
form.value.id = val.id;
updateName.value = val.demandName;
}
);
watch(
() => form.value,
(val) => {
if (val) {
emit('update:form', val);
}
}
);
defineExpose({
resetForm,
});

View File

@ -7,7 +7,7 @@
>
</template>
<template #operation="{ record }">
<MsButton v-if="record.demandPlatform !== pageConfig.platformName" @click="emit('cancel', record)">
<MsButton @click="emit('cancel', record)">
{{ t('caseManagement.featureCase.cancelAssociation') }}
</MsButton>
<MsButton v-if="record.demandPlatform === pageConfig.platformName" @click="emit('update', record)">
@ -77,7 +77,7 @@
width: 200,
},
{
title: 'caseManagement.featureCase.tableColumnName',
title: 'caseManagement.featureCase.name',
slotName: 'demandName',
dataIndex: 'demandName',
width: 300,
@ -95,7 +95,7 @@
slotName: 'operation',
dataIndex: 'operation',
fixed: 'right',
width: 100,
width: 150,
showInTable: true,
showDrag: false,
},
@ -107,13 +107,13 @@
scroll: { x: '100%' },
selectable: false,
showSetting: false,
heightUsed: 360,
});
const initData = async () => {
setLoadListParams({ ...props.funParams });
await loadList();
const { msPagination } = propsRes.value;
featureCaseStore.setListCount(featureCaseStore.activeTab, msPagination?.total || 0);
featureCaseStore.getCaseCounts(props.funParams.caseId);
};
onMounted(() => {

View File

@ -29,8 +29,8 @@
<AddDemandModal
ref="demandModalRef"
v-model:visible="showAddModel"
v-model:form="modelForm"
:case-id="props.caseId"
:form="modelForm"
:loading="confirmLoading"
@save="saveHandler"
@success="searchList()"
@ -121,10 +121,7 @@
const showAddModel = ref<boolean>(false);
function addDemand() {
showAddModel.value = true;
}
const modelForm = ref<DemandItem>({
const initModelForm: DemandItem = {
id: '',
caseId: '', // ID
demandId: '', // ID
@ -136,6 +133,10 @@
createUser: '',
updateUser: '',
children: [], //
};
const modelForm = ref<DemandItem>({
...initModelForm,
});
//
@ -181,6 +182,7 @@
columns: fullColumns.value,
rowKey: 'demandId',
scroll: { x: '100%' },
heightUsed: 290,
selectable: true,
showSetting: false,
});
@ -348,6 +350,11 @@
}
}
function addDemand() {
showAddModel.value = true;
modelForm.value = { ...initModelForm };
}
onMounted(async () => {
try {
const result = await getCaseRelatedInfo(currentProjectId.value);

View File

@ -87,6 +87,20 @@
<template #caseLevel="{ record }">
<caseLevel :case-level="getCaseLevels(record.customFields)" />
</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 v-if="(keyword || '').trim() === ''" #empty>
<div class="flex w-full items-center justify-center p-[8px] text-[var(--color-text-4)]">
{{ t('caseManagement.caseReview.tableNoData') }}
@ -135,6 +149,7 @@
import type { CaseLevel } from '@/components/business/ms-case-associate/types';
import MsTree from '@/components/business/ms-tree/index.vue';
import type { MsTreeNodeData } from '@/components/business/ms-tree/types';
import TableFilter from '../../tableFilter.vue';
import {
addPrepositionRelation,
@ -145,9 +160,10 @@
} from '@/api/modules/case-management/featureCase';
import { useI18n } from '@/hooks/useI18n';
import useAppStore from '@/store/modules/app';
import useFeatureCaseStore from '@/store/modules/case/featureCase';
import { mapTree } from '@/utils';
import type { CaseManagementTable, CaseModuleQueryParams } from '@/models/caseManagement/featureCase';
import type { CaseManagementTable, CaseModuleQueryParams, OptionsFieldId } from '@/models/caseManagement/featureCase';
import type { ModuleTreeNode, TableQueryParams } from '@/models/common';
import { CaseManagementRouteEnum } from '@/enums/routeEnum';
@ -155,6 +171,7 @@
const appStore = useAppStore();
const currentProjectId = computed(() => appStore.currentProjectId);
const featureStore = useFeatureCaseStore();
const { t } = useI18n();
const props = defineProps<{
@ -276,7 +293,8 @@
title: 'ms.case.associate.caseLevel',
dataIndex: 'caseLevel',
slotName: 'caseLevel',
width: 90,
titleSlotName: 'caseLevelFilter',
width: 100,
},
{
title: 'caseManagement.featureCase.tableColumnVersion',
@ -299,7 +317,7 @@
},
showSetting: false,
selectable: true,
heightUsed: 300,
heightUsed: 380,
showSelectAll: true,
},
(record) => {
@ -376,6 +394,11 @@
moduleIds: [],
excludeIds: [],
});
//
const caseLevelFields = ref<Record<string, any>>({});
const caseFilterVisible = ref(false);
const caseLevelList = ref<OptionsFieldId[]>([]);
const caseFilters = ref<string[]>([]);
//
function getLoadListParams() {
@ -389,6 +412,9 @@
keyword: keyword.value,
id: props.caseId,
type: props.showType === 'preposition' ? 'PRE' : 'POST',
filter: {
caseLevel: caseFilters.value,
},
});
}
@ -441,10 +467,17 @@
}
}
async function initFilter() {
await featureStore.getDefaultTemplate();
caseLevelList.value = featureStore.getSystemCaseLevelFields();
caseFilters.value = caseLevelList.value.map((item) => item.value);
}
watch(
() => innerVisible.value,
(val) => {
if (val) {
initFilter();
searchCase();
}
}

View File

@ -1,6 +1,6 @@
<template>
<div>
<div class="flex items-center justify-between">
<div class="mb-4 flex items-center justify-between">
<div>
<a-button v-if="showType === 'preposition'" class="mr-3" type="primary" @click="addCase">
{{ t('caseManagement.featureCase.addPresetCase') }}
@ -27,6 +27,9 @@
</div>
</div>
<ms-base-table ref="tableRef" v-bind="propsRes" v-on="propsEvent">
<template #num="{ record }">
{{ record.num }}
</template>
<template #operation="{ record }">
<MsRemoveButton
position="br"
@ -94,7 +97,8 @@
const columns: MsTableColumn = [
{
title: 'caseManagement.featureCase.tableColumnID',
dataIndex: 'id',
dataIndex: 'num',
slotName: 'num',
width: 200,
showInTable: true,
showTooltip: true,
@ -140,7 +144,7 @@
const { propsRes, propsEvent, loadList, setLoadListParams } = useTable(getDependOnCase, {
columns,
scroll: { x: '100%' },
heightUsed: 340,
heightUsed: 360,
selectable: false,
noDisable: true,
showSetting: false,
@ -159,8 +163,7 @@
async function initData() {
getParams();
await loadList();
const { msPagination } = propsRes.value;
featureCaseStore.setListCount(featureCaseStore.activeTab, msPagination?.total || 0);
featureCaseStore.getCaseCounts(props.caseId);
}
const cancelLoading = ref<boolean>(false);

View File

@ -157,7 +157,7 @@
<!-- 本地文件 -->
<div v-if="item.local || item.status === 'init'" class="flex flex-nowrap">
<MsButton
v-if="item.status !== 'init'"
v-if="item.file.type.includes('/image')"
type="button"
status="primary"
class="!mr-[4px]"
@ -192,7 +192,7 @@
<!-- 关联文件 -->
<div v-else class="flex flex-nowrap">
<MsButton
v-if="item.status !== 'init'"
v-if="item.file.type.includes('/image')"
type="button"
status="primary"
class="!mr-[4px]"

View File

@ -1,4 +1,5 @@
import { MsTableColumnData } from '@/components/pure/ms-table/type';
import { getFileEnum } from '@/components/pure/ms-upload/iconMap';
import type { MsFileItem } from '@/components/pure/ms-upload/types';
import type { CaseLevel } from '@/components/business/ms-case-associate/types';
@ -91,7 +92,11 @@ export const executionResultMap = {
export function convertToFile(fileInfo: AssociatedList): MsFileItem {
const gatewayAddress = `${window.location.protocol}//${window.location.hostname}:${window.location.port}`;
const fileName = fileInfo.fileType ? `${fileInfo.name}.${fileInfo.fileType || ''}` : `${fileInfo.name}`;
const type = fileName.split('.')[1];
const fileFormatMatch = fileName.match(/\.([a-zA-Z0-9]+)$/);
const fileFormatType = fileFormatMatch ? fileFormatMatch[1] : 'none';
const type = getFileEnum(fileFormatType);
console.log(type);
const file = new File([new Blob()], `${fileName}`, {
type: `application/${type}`,
});
@ -132,9 +137,10 @@ export function getTableFields(customFields: CustomAttributes[], itemDataIndex:
);
if (currentColumnData) {
let selectValue;
// 处理多选项
if (multipleExcludes.includes(currentColumnData.type)) {
const selectValue = JSON.parse(currentColumnData.defaultValue);
if (multipleExcludes.includes(currentColumnData.type) && currentColumnData.defaultValue) {
selectValue = JSON.parse(currentColumnData.defaultValue);
return (
(currentColumnData.options || [])
.filter((item: any) => selectValue.includes(item.value))

View File

@ -146,6 +146,7 @@
import useFeatureCaseStore from '@/store/modules/case/featureCase';
import type { CaseModuleQueryParams, CreateOrUpdateModule, ValidateInfo } from '@/models/caseManagement/featureCase';
import { TableQueryParams } from '@/models/common';
import { CaseManagementRouteEnum } from '@/enums/routeEnum';
import type { FileItem } from '@arco-design/web-vue';
@ -241,7 +242,7 @@
}
//
const tableFilterParams = ref<CaseModuleQueryParams>({
const tableFilterParams = ref<TableQueryParams>({
moduleIds: [],
projectId: '',
});
@ -257,7 +258,7 @@
/**
* 右侧表格数据刷新后若当前展示的是模块则刷新模块树的统计数量
*/
function initModulesCount(params: CaseModuleQueryParams) {
function initModulesCount(params: TableQueryParams) {
featureCaseStore.getCaseModulesCount(params);
featureCaseStore.getRecycleModulesCount(params);
tableFilterParams.value = { ...params };

View File

@ -32,6 +32,8 @@ export default {
'caseManagement.featureCase.moduleMoveSuccess': 'Move successfully',
'caseManagement.featureCase.tableColumnID': 'ID',
'caseManagement.featureCase.tableColumnName': 'Case Name',
'caseManagement.featureCase.demandName': 'Demand Name',
'caseManagement.featureCase.demandID': 'ID',
'caseManagement.featureCase.tableColumnLevel': 'Case Level',
'caseManagement.featureCase.tableColumnCaseState': 'Case State',
'caseManagement.featureCase.tableColumnReviewResult': 'Review Result',
@ -253,4 +255,5 @@ export default {
'caseManagement.featureCase.sortSuccess': 'Sort successfully',
'caseManagement.featureCase.zentao': 'zentao',
'caseManagement.featureCase.searchPlaceholder': 'Search by ID, name, or tag',
'caseManagement.featureCase.ModuleOwned': 'Module owned',
};

View File

@ -31,6 +31,8 @@ export default {
'caseManagement.featureCase.moduleMoveSuccess': '移动成功',
'caseManagement.featureCase.tableColumnID': 'ID',
'caseManagement.featureCase.tableColumnName': '用例名称',
'caseManagement.featureCase.demandName': '需求名称',
'caseManagement.featureCase.demandID': '需求ID',
'caseManagement.featureCase.tableColumnLevel': '用例等级',
'caseManagement.featureCase.tableColumnCaseState': '用例状态',
'caseManagement.featureCase.tableColumnReviewResult': '评审结果',
@ -248,4 +250,5 @@ export default {
'caseManagement.featureCase.sortSuccess': '排序成功',
'caseManagement.featureCase.zentao': '禅道',
'caseManagement.featureCase.searchPlaceholder': '通过ID、名称或标签搜索',
'caseManagement.featureCase.ModuleOwned': '所属模块',
};

View File

@ -39,9 +39,8 @@
v-model="templateForm.remark"
:max-length="1000"
:placeholder="t('system.orgTemplate.resDescription')"
:auto-size="{
maxRows: 1,
}"
:auto-size="{ minRows: 1 }"
style="resize: vertical"
class="max-w-[732px]"
></a-textarea>
</a-form-item>
@ -193,7 +192,7 @@
const { name, customFields, systemFields } = res;
templateForm.value = {
...res,
name: route.params.mode === 'copy' ? `${name}_copy` : name,
name: route.params.mode === 'copy' ? `copy_${name}` : name,
};
if (route.params.mode === 'copy') {
templateForm.value.id = undefined;

View File

@ -53,9 +53,11 @@
</template>
<template #name="{ record }">
<div class="flex items-center">
<span class="ml-2 cursor-pointer text-[rgb(var(--primary-5))]" @click="previewDetail(record)">{{
record.name
}}</span>
<span
class="one-line-text ml-2 cursor-pointer text-[rgb(var(--primary-5))]"
@click="previewDetail(record.id)"
>{{ record.name }}</span
>
<MsTag v-if="record.internal" size="small" class="ml-2">{{ t('system.orgTemplate.isSystem') }}</MsTag>
</div>
</template>
@ -171,6 +173,7 @@
fixed: 'left',
showDrag: true,
showInTable: true,
showTooltip: true,
},
{
title: 'system.orgTemplate.defaultTemplate',
@ -356,13 +359,14 @@
const titleDetail = ref<string>();
const defectForm = ref<Record<string, any>>({ ...initDetailForm });
//
const previewDetail = async (record: OrdTemplateManagement) => {
const previewDetail = async (id: string) => {
showDetailVisible.value = true;
titleDetail.value = record.name;
try {
totalData.value = await getProjectFieldList({ scopedId: currentProjectId.value, scene: route.query.type });
getFieldOptionList();
const res = await getProjectTemplateInfo(record.id);
const res = await getProjectTemplateInfo(id);
titleDetail.value = res.name;
selectData.value = getCustomDetailFields(totalData.value as DefinedFieldItem[], res.customFields);
res.systemFields.forEach((item: any) => {
defectForm.value[item.fieldId] = item.defaultValue;
@ -400,6 +404,12 @@
return route.query.type !== 'BUG';
});
onMounted(() => {
if (route.query.id) {
previewDetail(route.query.id as string);
}
});
onMounted(() => {
fetchData();
updateColumns();

View File

@ -31,7 +31,7 @@
<a-textarea
v-model:model-value="form.remark"
:max-length="1000"
:placeholder="t('system.config.auth.descPlaceholder')"
:placeholder="t('system.orgTemplate.enterStatusDesc')"
allow-clear
></a-textarea>
</a-form-item>

View File

@ -7,7 +7,7 @@
:width="800"
:show-continue="!isEdit"
@confirm="handleDrawerConfirm"
@continue="handleDrawerConfirm(true)"
@continue="saveAndContinue"
@cancel="handleDrawerCancel"
>
<div class="form">
@ -31,9 +31,8 @@
v-model="fieldForm.remark"
:max-length="1000"
:placeholder="t('system.orgTemplate.resDescription')"
:auto-size="{
maxRows: 1,
}"
:auto-size="{ minRows: 1 }"
style="resize: vertical"
></a-textarea>
</a-form-item>
<a-form-item
@ -251,10 +250,8 @@
const { addOrUpdate, detail } = getFieldRequestApi(props.mode);
//
const confirmHandler = async (isContinue: boolean) => {
const confirmHandler = async (isContinue = false) => {
try {
drawerLoading.value = true;
const formCopy = cloneDeep(fieldForm.value);
formCopy.scene = route.query.type;
@ -291,7 +288,7 @@
params.id = id;
}
await addOrUpdate(params);
Message.success(isEdit.value ? t('common.updateSuccess') : t('common.addSuccess'));
Message.success(isEdit.value ? t('common.updateSuccess') : t('common.newSuccess'));
if (!isContinue) {
handleDrawerCancel();
}
@ -303,27 +300,48 @@
drawerLoading.value = false;
}
};
const fieldDefaultValues = ref<FormItemModel[]>([]);
function userFormFiledValidate(cb: () => Promise<any>) {
fieldFormRef.value?.validate((errors: undefined | Record<string, ValidatedError>) => {
if (errors) {
return;
}
batchFormRef.value?.formValidate(async (list: any) => {
try {
drawerLoading.value = true;
fieldDefaultValues.value = [...list];
if (showOptionsSelect) {
fieldForm.value.options = (batchFormRef.value?.getFormResult() || []).map((item: any) => {
return {
...item,
value: fieldForm.value.enableOptionKey ? item.value : getGenerateId(),
};
});
}
await cb();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
} finally {
drawerLoading.value = false;
}
});
});
}
// ||
const handleDrawerConfirm = (isContinue: boolean) => {
fieldFormRef.value?.validate(async (errors: Record<string, ValidatedError> | undefined) => {
if (!errors) {
if (showOptionsSelect) {
fieldForm.value.options = (batchFormRef.value?.getFormResult() || []).map((item: any) => {
return {
...item,
value: fieldForm.value.enableOptionKey ? item.value : getGenerateId(),
};
});
}
confirmHandler(isContinue);
}
});
userFormFiledValidate(confirmHandler);
};
function saveAndContinue() {
userFormFiledValidate(async () => {
await confirmHandler(true);
resetForm();
});
}
//
const fieldOptions = ref<fieldIconAndNameModal[]>([]);
const fieldDefaultValues = ref([]);
//
const getFieldDetail = async (id: string) => {

View File

@ -1,10 +1,23 @@
<template>
<div>
<a-alert class="mb-6" :type="isEnabledTemplate && props.mode === 'organization' ? 'warning' : 'info'">{{
isEnabledTemplate && props.mode === 'organization'
? t('system.orgTemplate.enableDescription')
: t('system.orgTemplate.fieldLimit')
}}</a-alert>
<a-alert
v-if="isShowTip"
class="mb-6"
:type="isEnabledTemplate && props.mode === 'organization' ? 'warning' : 'info'"
>
<div class="flex items-start justify-between">
<span>
{{
isEnabledTemplate && props.mode === 'organization'
? t('system.orgTemplate.enableDescription')
: t('system.orgTemplate.fieldLimit')
}}</span
>
<span class="cursor-pointer text-[var(--color-text-2)]" @click="noRemindHandler">{{
t('system.orgTemplate.noReminders')
}}</span>
</div>
</a-alert>
<div class="mb-4 flex items-center justify-between">
<span v-if="isEnabledTemplate" class="font-medium">{{ t('system.orgTemplate.fieldList') }}</span>
<a-button v-permission="props.createPermission" type="primary" :disabled="isDisabled" @click="fieldHandler">
@ -145,6 +158,7 @@
import { useI18n } from '@/hooks/useI18n';
import useModal from '@/hooks/useModal';
import useVisit from '@/hooks/useVisit';
import { useAppStore, useTableStore } from '@/store';
import useTemplateStore from '@/store/modules/setting/template';
import { characterLimit } from '@/utils';
@ -157,6 +171,9 @@
const templateStore = useTemplateStore();
const visitedKey = 'notRemindField';
const { addVisited } = useVisit(visitedKey);
const { getIsVisited } = useVisit(visitedKey);
const { t } = useI18n();
const tableStore = useTableStore();
const appStore = useAppStore();
@ -363,7 +380,20 @@
fetchData();
};
const isShowTip = ref<boolean>(true);
//
const doCheckIsTip = () => {
isShowTip.value = !getIsVisited();
};
const noRemindHandler = () => {
isShowTip.value = false;
addVisited();
};
onMounted(() => {
doCheckIsTip();
isEnableOperation();
fetchData();
});

View File

@ -39,9 +39,8 @@
v-model="templateForm.remark"
:max-length="1000"
:placeholder="t('system.orgTemplate.resDescription')"
:auto-size="{
maxRows: 1,
}"
:auto-size="{ minRows: 1 }"
style="resize: vertical"
class="max-w-[732px]"
></a-textarea>
</a-form-item>
@ -187,7 +186,7 @@
const { name, customFields, systemFields } = res;
templateForm.value = {
...res,
name: route.params.mode === 'copy' ? `${name}_copy` : name,
name: route.params.mode === 'copy' ? `copy_${name}` : name,
};
if (route.params.mode === 'copy') {
templateForm.value.id = undefined;

View File

@ -103,4 +103,12 @@
width: 428px;
}
}
:deep(.arco-picker-disabled) {
border-color: var(--color-text-n8);
background: var(--color-text-n8);
&:hover {
border-color: var(--color-text-n8);
background: var(--color-text-n8);
}
}
</style>

View File

@ -173,7 +173,9 @@
<span class="label">{{ t('system.orgTemplate.description') }}</span>
</div>
<div class="flex w-[60%] flex-col">
<span class="content">{{ detailInfo?.name }}</span>
<a-tooltip position="left" :content="detailInfo?.name">
<span class="content">{{ characterLimit(detailInfo?.name) }}</span>
</a-tooltip>
<span class="content">{{ detailInfo?.remark || '-' }}</span>
</div>
</div>

View File

@ -184,4 +184,9 @@ export default {
'system.orgTemplate.associatedField': 'Associated field ',
'system.orgTemplate.associatedHasField': 'Associate an added field',
'system.orgTemplate.addFieldDesc': 'Adds a new field',
'system.orgTemplate.enterStatusDesc': 'Please enter a status description',
'system.orgTemplate.field': 'Field',
'system.orgTemplate.caseTemplateManagement': 'Use case template management',
'system.orgTemplate.apiTemplateManagement': 'Interface template management',
'system.orgTemplate.bugTemplateManagement': 'Defect template management',
};

View File

@ -175,4 +175,9 @@ export default {
'system.orgTemplate.addFieldDesc': '新增一个新的字段',
'system.orgTemplate.toTop': '上移',
'system.orgTemplate.toBottom': '下移',
'system.orgTemplate.enterStatusDesc': '请输入状态描述',
'system.orgTemplate.field': '字段',
'system.orgTemplate.caseTemplateManagement': '用例模板管理',
'system.orgTemplate.apiTemplateManagement': '接口模板管理',
'system.orgTemplate.bugTemplateManagement': '缺陷模板管理',
};

View File

@ -392,7 +392,7 @@
enable: !record.enable,
};
await updatePlugin(params);
Message.success(t('system.plugin.disablePluginSuccess'));
Message.success(t('system.plugin.enablePluginSuccess'));
loadData();
} catch (error) {
console.log(error);