feat(用例评审): 用例评审 fake-page&全局行高调整

This commit is contained in:
baiqi 2023-11-28 17:43:07 +08:00 committed by Craftsman
parent a33a0580ff
commit 730583ecf9
53 changed files with 4458 additions and 578 deletions

View File

@ -0,0 +1,110 @@
// import MSR from '@/api/http/index';
export const getCaseList = () => {
// return MSR.post<CommonList<FileItem>>({ url: FilePageUrl, data });
return Promise.resolve({
list: [
{
id: 'ded3d43',
name: '测试评审1',
creator: '张三',
reviewer: '李四',
module: '模块1',
status: 0, // 未开始、进行中、已完成、已归档
result: 0, // 通过、不通过、评审中
caseCount: 100,
passCount: 0,
failCount: 10,
reviewCount: 20,
reviewingCount: 25,
tags: ['标签1', '标签2'],
type: 'single',
desc: 'douifd9304',
cycle: [1700200794229, 1700200994229],
},
{
id: 'g545hj4',
name: '测试评审2',
creator: '张三',
reviewer: '李四',
module: '模块1',
status: 1, // 未开始、进行中、已完成、已归档
result: 1, // 通过、不通过、评审中
caseCount: 105,
passCount: 50,
failCount: 10,
reviewCount: 20,
reviewingCount: 25,
tags: ['标签1', '标签2'],
type: 'single',
desc: 'douifd9304',
cycle: [1700200794229, 1700200994229],
},
{
id: 'hj65b54',
name: '测试评审3',
creator: '张三',
reviewer: '李四',
module: '模块1',
status: 2, // 未开始、进行中、已完成、已归档
result: 2, // 通过、不通过、评审中
caseCount: 125,
passCount: 70,
failCount: 10,
reviewCount: 20,
reviewingCount: 25,
passRate: '80%',
tags: ['标签1', '标签2'],
type: 'single',
desc: 'douifd9304',
cycle: [1700200794229, 1700200994229],
},
{
id: 'wefwefw',
name: '测试评审4',
creator: '张三',
reviewer: '李四',
module: '模块1',
status: 3, // 未开始、进行中、已完成、已归档
result: 3, // 通过、不通过、评审中
caseCount: 130,
passCount: 70,
failCount: 10,
reviewCount: 0,
reviewingCount: 50,
passRate: '80%',
tags: ['标签1', '标签2'],
type: 'single',
desc: 'douifd9304',
cycle: [1700200794229, 1700200994229],
},
{
id: 'g4ggtrgrtg',
name: '测试评审5',
creator: '张三',
reviewer: '李四',
module: '模块1',
status: 3, // 未开始、进行中、已完成、已归档
result: 4, // 通过、不通过、评审中
caseCount: 130,
passCount: 70,
failCount: 10,
reviewCount: 0,
reviewingCount: 50,
passRate: '80%',
tags: ['标签1', '标签2'],
type: 'single',
desc: 'douifd9304',
cycle: [1700200794229, 1700200994229],
},
],
current: 1,
pageSize: 10,
total: 2,
});
};
export const getCaseDetail = () => {
// return MSR.post<CommonList<FileItem>>({ url: FilePageUrl, data });
return new Promise((resolve) => {});
};

View File

@ -27,6 +27,61 @@ export interface PathMapItem {
* children /tab集合
*/
export const pathMap: PathMapItem[] = [
{
key: 'CASE_MANAGEMENT', // 功能测试
locale: 'menu.caseManagement',
route: RouteEnum.CASE_MANAGEMENT,
permission: [],
level: MENU_LEVEL[2],
children: [
{
key: 'CASE_MANAGEMENT_CASE', // 功能测试-功能用例
locale: 'menu.caseManagement.featureCase',
route: RouteEnum.CASE_MANAGEMENT_CASE,
permission: [],
level: MENU_LEVEL[2],
},
// {
// key: 'CASE_MANAGEMENT_CASE_DETAIL', // 功能测试-功能用例-创建用例
// locale: 'menu.caseManagement.featureCaseDetail',
// route: RouteEnum.CASE_MANAGEMENT_CASE_DETAIL,
// permission: [],
// level: MENU_LEVEL[2],
// },
{
key: 'CASE_MANAGEMENT_REVIEW', // 功能测试-功能用例-用例评审
locale: 'menu.caseManagement.caseManagementReview',
route: RouteEnum.CASE_MANAGEMENT_REVIEW,
permission: [],
level: MENU_LEVEL[2],
children: [
{
key: 'CASE_MANAGEMENT_REVIEW_CREATE', // 功能测试-功能用例-创建评审
locale: 'menu.caseManagement.caseManagementReviewCreate',
route: RouteEnum.CASE_MANAGEMENT_REVIEW_CREATE,
permission: [],
level: MENU_LEVEL[2],
},
{
key: 'CASE_MANAGEMENT_REVIEW_DETAIL', // 功能测试-功能用例-评审详情
locale: 'menu.caseManagement.caseManagementReviewDetail',
route: RouteEnum.CASE_MANAGEMENT_REVIEW_DETAIL,
permission: [],
level: MENU_LEVEL[2],
children: [
{
key: 'CASE_MANAGEMENT_REVIEW_DETAIL_CASE_DETAIL', // 功能测试-功能用例-评审详情-用例详情
locale: 'menu.caseManagement.caseManagementReviewDetailCaseDetail',
route: RouteEnum.CASE_MANAGEMENT_REVIEW_DETAIL_CASE_DETAIL,
permission: [],
level: MENU_LEVEL[2],
},
],
},
],
},
],
},
{
key: 'SETTING', // 系统设置
locale: 'menu.settings',
@ -338,37 +393,37 @@ export const pathMap: PathMapItem[] = [
],
},
{
key: 'FEATURE_TEST', // 功能测试
locale: 'menu.featureTest',
route: RouteEnum.FEATURE_TEST,
key: 'CASE_MANAGEMENT', // 功能测试
locale: 'menu.caseManagement',
route: RouteEnum.CASE_MANAGEMENT,
permission: [],
level: MENU_LEVEL[2],
children: [
{
key: 'FEATURE_TEST_CASE', // 功能测试-功能用例
locale: 'menu.featureTest.featureCase',
route: RouteEnum.FEATURE_TEST_CASE,
key: 'CASE_MANAGEMENT_CASE', // 功能测试-功能用例
locale: 'menu.caseManagement.featureCase',
route: RouteEnum.CASE_MANAGEMENT_CASE,
permission: [],
level: MENU_LEVEL[2],
},
{
key: 'FEATURE_TEST_CASE_DETAIL', // 功能测试-功能用例详情
locale: 'menu.featureTest.featureCaseDetail',
route: RouteEnum.FEATURE_TEST_CASE_DETAIL,
key: 'CASE_MANAGEMENT_CASE_DETAIL', // 功能测试-功能用例详情
locale: 'menu.caseManagement.featureCaseDetail',
route: RouteEnum.CASE_MANAGEMENT_CASE_DETAIL,
permission: [],
level: MENU_LEVEL[2],
},
{
key: 'FEATURE_TEST_CASE_CREATE_SUCCESS', // 功能测试-功能用例创建成功页面
locale: 'menu.featureTest.featureCaseCreateSuccess',
route: RouteEnum.FEATURE_TEST_CASE_CREATE_SUCCESS,
key: 'CASE_MANAGEMENT_CASE_CREATE_SUCCESS', // 功能测试-功能用例创建成功页面
locale: 'menu.caseManagement.featureCaseCreateSuccess',
route: RouteEnum.CASE_MANAGEMENT_CASE_CREATE_SUCCESS,
permission: [],
level: MENU_LEVEL[2],
},
{
key: 'FEATURE_TEST_CASE_RECYCLE', // 功能测试-功能用例-回收站
locale: 'menu.featureTest.featureCaseRecycle',
route: RouteEnum.FEATURE_TEST_CASE_RECYCLE,
key: 'CASE_MANAGEMENT_CASE_RECYCLE', // 功能测试-功能用例-回收站
locale: 'menu.caseManagement.featureCaseRecycle',
route: RouteEnum.CASE_MANAGEMENT_CASE_RECYCLE,
permission: [],
level: MENU_LEVEL[2],
},

View File

@ -6,12 +6,16 @@ export enum BugManagementRouteEnum {
BUG_MANAGEMENT = 'bugManagement',
}
export enum FeatureTestRouteEnum {
FEATURE_TEST = 'featureTest',
FEATURE_TEST_CASE = 'featureTestCase',
FEATURE_TEST_CASE_CREATE_SUCCESS = 'featureTestCaseCreateSuccess',
FEATURE_TEST_CASE_RECYCLE = 'featureTestCaseRecycle',
FEATURE_TEST_CASE_DETAIL = 'featureTestCaseDetail',
export enum CaseManagementRouteEnum {
CASE_MANAGEMENT = 'caseManagement',
CASE_MANAGEMENT_CASE = 'caseManagementCase',
CASE_MANAGEMENT_CASE_CREATE_SUCCESS = 'caseManagementCaseCreateSuccess',
CASE_MANAGEMENT_CASE_RECYCLE = 'caseManagementCaseRecycle',
CASE_MANAGEMENT_CASE_DETAIL = 'caseManagementCaseDetail',
CASE_MANAGEMENT_REVIEW = 'caseManagementReview',
CASE_MANAGEMENT_REVIEW_CREATE = 'caseManagementReviewCreate',
CASE_MANAGEMENT_REVIEW_DETAIL = 'caseManagementReviewDetail',
CASE_MANAGEMENT_REVIEW_DETAIL_CASE_DETAIL = 'caseManagementReviewDetailCaseDetail',
}
export enum PerformanceTestRouteEnum {
@ -79,7 +83,7 @@ export const RouteEnum = {
...ApiTestRouteEnum,
...SettingRouteEnum,
...BugManagementRouteEnum,
...FeatureTestRouteEnum,
...CaseManagementRouteEnum,
...PerformanceTestRouteEnum,
...ProjectManagementRouteEnum,
...TestPlanRouteEnum,

View File

@ -33,6 +33,8 @@ export enum TableKeyEnum {
CASE_MANAGEMENT_DETAIL_TABLE = 'caseManagementDetailTable',
CASE_MANAGEMENT_ASSOCIATED_TABLE = 'caseManagementAssociatedFileTable',
BUG_MANAGEMENT = 'bugManagement',
CASE_MANAGEMENT_REVIEW = 'caseManagementReview',
CASE_MANAGEMENT_REVIEW_CASE = 'caseManagementReviewCase',
}
// 具有特殊功能的列

View File

@ -66,4 +66,11 @@ export default {
'common.batchModify': 'Batch Edit',
'common.pleaseSelect': 'please choose',
'common.quickAddMember': 'Quickly add members',
'common.filter': 'Filter',
'common.export': 'Export',
'common.collapseAll': 'Collapse all',
'common.expandAll': 'Expand all',
'common.copy': 'Copy',
'common.fork': 'Fork',
'common.more': 'More',
};

View File

@ -22,7 +22,7 @@ export default {
'menu.workbench': 'Workbench',
'menu.testPlan': 'Test Plan',
'menu.bugManagement': 'Bug',
'menu.featureTest': 'Feature Test',
'menu.caseManagement': 'Case Management',
'menu.apiTest': 'API Test',
'menu.uiTest': 'UI Test',
'menu.performanceTest': 'Performance Test',
@ -30,14 +30,18 @@ export default {
'menu.projectManagement.fileManagement': 'File Management',
'menu.projectManagement.messageManagement': 'Message Management',
'menu.projectManagement.messageManagementEdit': 'Update Template',
'menu.featureTest.featureCase': 'Feature Case',
'menu.featureTest.featureCaseRecycle': 'Recycle',
'menu.featureTest.featureCaseList': 'Case list',
'menu.featureTest.featureCaseDetail': 'Create Case',
'menu.featureTest.featureCaseCreateSuccess': 'Create Success',
'meun.workstation': 'Workstation',
'menu.caseManagement.featureCase': 'Feature Case',
'menu.caseManagement.featureCaseRecycle': 'Recycle',
'menu.caseManagement.featureCaseList': 'Case list',
'menu.caseManagement.featureCaseDetail': 'Create Case',
'menu.caseManagement.featureCaseCreateSuccess': 'Create Success',
'menu.caseManagement.caseManagementReview': 'Feature Case Review',
'menu.caseManagement.caseManagementReviewCreate': 'Create Review',
'menu.caseManagement.caseManagementReviewDetail': 'Review Detail',
'menu.caseManagement.caseManagementCaseReviewEdit': 'Update Review',
'menu.caseManagement.caseManagementCaseDetail': 'Case Detail',
'menu.workstation': 'Workstation',
'menu.loadTest': 'Performance Test',
'menu.caseManagement': 'Feature Test',
'menu.projectManagement.projectPermission': 'Project Permission',
'menu.projectManagement.log': 'Log',
'menu.settings': 'Settings',

View File

@ -67,4 +67,10 @@ export default {
'common.batchModify': '批量修改',
'common.pleaseSelect': '请选择',
'common.quickAddMember': '快速添加成员',
'common.export': '导出',
'common.collapseAll': '展开全部',
'common.expandAll': '收起全部',
'common.copy': '复制',
'common.fork': '关注',
'common.more': '更多',
};

View File

@ -21,12 +21,11 @@ export default {
'menu.workbench': '工作台',
'menu.testPlan': '测试计划',
'menu.bugManagement': '缺陷管理',
'menu.featureTest': '功能测试',
'menu.caseManagement': '功能测试',
'menu.apiTest': '接口测试',
'menu.uiTest': 'UI测试',
'menu.workstation': '工作台',
'menu.loadTest': '性能测试',
'menu.caseManagement': '功能测试',
'menu.performanceTest': '性能测试',
'menu.projectManagement': '项目管理',
'menu.projectManagement.templateManager': '模板管理',
@ -34,11 +33,16 @@ export default {
'menu.projectManagement.fileManagement': '文件管理',
'menu.projectManagement.messageManagement': '消息管理',
'menu.projectManagement.messageManagementEdit': '更新模板',
'menu.featureTest.featureCase': '功能用例',
'menu.featureTest.featureCaseRecycle': '回收站',
'menu.featureTest.featureCaseList': '用例列表',
'menu.featureTest.featureCaseDetail': '创建用例',
'menu.featureTest.featureCaseCreateSuccess': '创建用例成功',
'menu.caseManagement.featureCase': '功能用例',
'menu.caseManagement.featureCaseRecycle': '回收站',
'menu.caseManagement.featureCaseList': '用例列表',
'menu.caseManagement.featureCaseDetail': '创建用例',
'menu.caseManagement.featureCaseCreateSuccess': '创建用例成功',
'menu.caseManagement.caseManagementReview': '用例评审',
'menu.caseManagement.caseManagementReviewCreate': '创建评审',
'menu.caseManagement.caseManagementReviewDetail': '评审详情',
'menu.caseManagement.caseManagementCaseReviewEdit': '更新评审',
'menu.caseManagement.caseManagementCaseDetail': '用例详情',
'menu.projectManagement.projectPermission': '项目与权限',
'menu.settings': '系统设置',
'menu.settings.system': '系统',

View File

@ -16,6 +16,6 @@ export const NOT_FOUND = {
export const REDIRECT_ROUTE_NAME = 'Redirect';
// 首页路由
export const DEFAULT_ROUTE_NAME = 'Workbench';
export const DEFAULT_ROUTE_NAME = 'workbench';
export const WHITE_LIST_NAME = WHITE_LIST.map((el) => el.name);

View File

@ -1,15 +1,15 @@
import { FeatureTestRouteEnum } from '@/enums/routeEnum';
import { CaseManagementRouteEnum } from '@/enums/routeEnum';
import { DEFAULT_LAYOUT } from '../base';
import type { AppRouteRecordRaw } from '../types';
const FeatureTest: AppRouteRecordRaw = {
path: '/feature-test',
name: FeatureTestRouteEnum.FEATURE_TEST,
redirect: '/feature-test/featureCase',
const CaseManagement: AppRouteRecordRaw = {
path: '/case-management',
name: CaseManagementRouteEnum.CASE_MANAGEMENT,
redirect: '/case-management/featureCase',
component: DEFAULT_LAYOUT,
meta: {
locale: 'menu.featureTest',
locale: 'menu.caseManagement',
icon: 'icon-icon_functional_testing',
order: 3,
hideChildrenInMenu: true,
@ -18,10 +18,10 @@ const FeatureTest: AppRouteRecordRaw = {
// 功能用例
{
path: 'featureCase',
name: FeatureTestRouteEnum.FEATURE_TEST_CASE,
name: CaseManagementRouteEnum.CASE_MANAGEMENT_CASE,
component: () => import('@/views/case-management/caseManagementFeature/index.vue'),
meta: {
locale: 'menu.featureTest.featureCase',
locale: 'menu.caseManagement.featureCase',
roles: ['*'],
isTopMenu: true,
},
@ -29,20 +29,20 @@ const FeatureTest: AppRouteRecordRaw = {
// 创建用例&编辑用例
{
path: 'featureCaseDetail/:mode?',
name: FeatureTestRouteEnum.FEATURE_TEST_CASE_DETAIL,
name: CaseManagementRouteEnum.CASE_MANAGEMENT_CASE_DETAIL,
component: () => import('@/views/case-management/caseManagementFeature/components/caseDetail.vue'),
meta: {
locale: 'menu.featureTest.featureCaseDetail',
locale: 'menu.caseManagement.featureCaseDetail',
roles: ['*'],
breadcrumbs: [
{
name: FeatureTestRouteEnum.FEATURE_TEST_CASE,
locale: 'menu.featureTest.featureCase',
name: CaseManagementRouteEnum.CASE_MANAGEMENT_CASE,
locale: 'menu.caseManagement.featureCase',
},
{
name: FeatureTestRouteEnum.FEATURE_TEST_CASE_DETAIL,
name: CaseManagementRouteEnum.CASE_MANAGEMENT_CASE_DETAIL,
editTag: 'id',
locale: 'menu.featureTest.featureCaseDetail',
locale: 'menu.caseManagement.featureCaseDetail',
},
],
},
@ -50,29 +50,105 @@ const FeatureTest: AppRouteRecordRaw = {
// 创建用例成功
{
path: 'featureCaseCreateSuccess',
name: FeatureTestRouteEnum.FEATURE_TEST_CASE_CREATE_SUCCESS,
name: CaseManagementRouteEnum.CASE_MANAGEMENT_CASE_CREATE_SUCCESS,
component: () => import('@/views/case-management/caseManagementFeature/components/createSuccess.vue'),
meta: {
locale: 'menu.featureTest.featureCaseCreateSuccess',
locale: 'menu.caseManagement.featureCaseCreateSuccess',
roles: ['*'],
},
},
// 功能用例回收站
{
path: 'featureCaseRecycle',
name: FeatureTestRouteEnum.FEATURE_TEST_CASE_RECYCLE,
name: CaseManagementRouteEnum.CASE_MANAGEMENT_CASE_RECYCLE,
component: () => import('@/views/case-management/caseManagementFeature/components/recycleCaseTable.vue'),
meta: {
locale: 'menu.featureTest.featureCaseRecycle',
locale: 'menu.caseManagement.featureCaseRecycle',
roles: ['*'],
breadcrumbs: [
{
name: FeatureTestRouteEnum.FEATURE_TEST_CASE,
locale: 'menu.featureTest.featureCaseList',
name: CaseManagementRouteEnum.CASE_MANAGEMENT_CASE,
locale: 'menu.caseManagement.featureCaseList',
},
{
name: FeatureTestRouteEnum.FEATURE_TEST_CASE_RECYCLE,
locale: 'menu.featureTest.featureCaseRecycle',
name: CaseManagementRouteEnum.CASE_MANAGEMENT_CASE_RECYCLE,
locale: 'menu.caseManagement.featureCaseRecycle',
},
],
},
},
// 用例评审
{
path: 'caseManagementReview',
name: CaseManagementRouteEnum.CASE_MANAGEMENT_REVIEW,
component: () => import('@/views/case-management/caseReview/index.vue'),
meta: {
locale: 'menu.caseManagement.caseManagementReview',
roles: ['*'],
isTopMenu: true,
},
},
{
path: 'caseManagementReviewCreate',
name: CaseManagementRouteEnum.CASE_MANAGEMENT_REVIEW_CREATE,
component: () => import('@/views/case-management/caseReview/create.vue'),
meta: {
locale: 'menu.caseManagement.caseManagementReviewCreate',
roles: ['*'],
breadcrumbs: [
{
name: CaseManagementRouteEnum.CASE_MANAGEMENT_REVIEW,
locale: 'menu.caseManagement.caseManagementReview',
},
{
name: CaseManagementRouteEnum.CASE_MANAGEMENT_REVIEW_CREATE,
locale: 'menu.caseManagement.caseManagementReviewCreate',
editTag: 'id',
editLocale: 'menu.caseManagement.caseManagementCaseReviewEdit',
},
],
},
},
{
path: 'caseManagementReviewDetail',
name: CaseManagementRouteEnum.CASE_MANAGEMENT_REVIEW_DETAIL,
component: () => import('@/views/case-management/caseReview/detail.vue'),
meta: {
locale: 'menu.caseManagement.caseManagementReviewDetail',
roles: ['*'],
breadcrumbs: [
{
name: CaseManagementRouteEnum.CASE_MANAGEMENT_REVIEW,
locale: 'menu.caseManagement.caseManagementReview',
},
{
name: CaseManagementRouteEnum.CASE_MANAGEMENT_REVIEW_DETAIL,
locale: 'menu.caseManagement.caseManagementReviewDetail',
},
],
},
},
{
path: 'caseManagementReviewDetailCaseDetail',
name: CaseManagementRouteEnum.CASE_MANAGEMENT_REVIEW_DETAIL_CASE_DETAIL,
component: () => import('@/views/case-management/caseReview/caseDetail.vue'),
meta: {
locale: 'menu.caseManagement.caseManagementCaseDetail',
roles: ['*'],
breadcrumbs: [
{
name: CaseManagementRouteEnum.CASE_MANAGEMENT_REVIEW,
locale: 'menu.caseManagement.caseManagementReview',
},
{
name: CaseManagementRouteEnum.CASE_MANAGEMENT_REVIEW_DETAIL,
locale: 'menu.caseManagement.caseManagementReviewDetail',
isBack: true,
query: ['id'],
},
{
name: CaseManagementRouteEnum.CASE_MANAGEMENT_REVIEW_DETAIL_CASE_DETAIL,
locale: 'menu.caseManagement.caseManagementCaseDetail',
},
],
},
@ -80,4 +156,4 @@ const FeatureTest: AppRouteRecordRaw = {
],
};
export default FeatureTest;
export default CaseManagement;

View File

@ -162,6 +162,7 @@
font-size: 24px;
border-radius: var(--border-radius-large) var(--border-radius-large) 0 0;
background-color: var(--color-text-n9);
line-height: 32px;
}
.hidden-item {
margin-bottom: 24px;

View File

@ -13,6 +13,6 @@
const router = useRouter();
const back = () => {
// warning Go to the node that has the permission
router.push({ name: 'Workbench' });
router.push({ name: 'workbench' });
};
</script>

View File

@ -2,8 +2,8 @@
<MsDrawer
v-model:visible="showDrawer"
:mask="false"
:title="t('featureTest.featureCase.associatedFile')"
:ok-text="t('featureTest.featureCase.associated')"
:title="t('caseManagement.featureCase.associatedFile')"
:ok-text="t('caseManagement.featureCase.associated')"
:ok-loading="drawerLoading"
:width="960"
unmount-on-close
@ -17,7 +17,7 @@
<a-option key="" value="">{{ t('common.all') }}</a-option>
<a-option v-for="item of fileTypeList" :key="item" :value="item">{{ item }}</a-option>
<template #prefix
><span>{{ t('featureTest.featureCase.fileType') }}</span></template
><span>{{ t('caseManagement.featureCase.fileType') }}</span></template
>
</a-select></div
>
@ -81,7 +81,7 @@
const columns: MsTableColumn = [
{
title: 'featureTest.featureCase.fileName',
title: 'caseManagement.featureCase.fileName',
dataIndex: 'name',
slotName: 'name',
showInTable: true,
@ -90,20 +90,20 @@
width: 300,
},
{
title: 'featureTest.featureCase.description',
title: 'caseManagement.featureCase.description',
dataIndex: 'description',
showInTable: true,
showTooltip: true,
showDrag: true,
},
{
title: 'featureTest.featureCase.tags',
title: 'caseManagement.featureCase.tags',
dataIndex: 'tags',
isTag: true,
showDrag: true,
},
{
title: 'featureTest.featureCase.tableColumnCreateUser',
title: 'caseManagement.featureCase.tableColumnCreateUser',
dataIndex: 'createUser',
sortable: {
sortDirections: ['ascend', 'descend'],
@ -112,7 +112,7 @@
showDrag: true,
},
{
title: 'featureTest.featureCase.tableColumnUpdateUser',
title: 'caseManagement.featureCase.tableColumnUpdateUser',
dataIndex: 'updateUser',
sortable: {
sortDirections: ['ascend', 'descend'],
@ -121,7 +121,7 @@
showInTable: true,
},
{
title: 'featureTest.featureCase.tableColumnUpdateTime',
title: 'caseManagement.featureCase.tableColumnUpdateTime',
dataIndex: 'updateTime',
sortable: {
sortDirections: ['ascend', 'descend'],

View File

@ -2,13 +2,13 @@
<MsDialog
v-model:visible="isVisible"
dialog-size="small"
:title="t('featureTest.featureCase.batchEdit', { number: props.batchParams.currentSelectCount })"
:title="t('caseManagement.featureCase.batchEdit', { number: props.batchParams.currentSelectCount })"
ok-text="common.confirm"
:confirm="confirmHandler"
:close="closeHandler"
:switch-props="{
switchName: t('featureTest.featureCase.appendTag'),
switchTooltip: t('featureTest.featureCase.enableTags'),
switchName: t('caseManagement.featureCase.appendTag'),
switchTooltip: t('caseManagement.featureCase.enableTags'),
showSwitch: form.selectedAttrsId === 'systemTags' ? true : false,
enable: form.append,
}"
@ -17,27 +17,27 @@
<a-form ref="formRef" :model="form" size="large" layout="vertical">
<a-form-item
field="selectedAttrsId"
:label="t('featureTest.featureCase.selectAttrs')"
:label="t('caseManagement.featureCase.selectAttrs')"
asterisk-position="end"
:rules="[{ required: true, message: t('system.orgTemplate.stateNameNotNull') }]"
>
<a-select v-model="form.selectedAttrsId" :placeholder="t('featureTest.featureCase.PleaseSelect')">
<a-select v-model="form.selectedAttrsId" :placeholder="t('caseManagement.featureCase.PleaseSelect')">
<a-option v-for="item of totalAttrs" :key="item.fieldId" :value="item.fieldId">{{
item.fieldName
}}</a-option>
<a-option key="systemTags" value="systemTags">{{ t('featureTest.featureCase.tags') }}</a-option>
<a-option key="systemTags" value="systemTags">{{ t('caseManagement.featureCase.tags') }}</a-option>
</a-select>
</a-form-item>
<a-form-item
v-if="form.selectedAttrsId === 'systemTags'"
field="tags"
:label="t('featureTest.featureCase.batchUpdate')"
:label="t('caseManagement.featureCase.batchUpdate')"
asterisk-position="end"
:rules="[{ required: true, message: t('featureTest.featureCase.PleaseInputTags') }]"
:rules="[{ required: true, message: t('caseManagement.featureCase.PleaseInputTags') }]"
>
<a-input-tag
v-model="form.tags"
:placeholder="t('featureTest.featureCase.pleaseEnterInputTags')"
:placeholder="t('caseManagement.featureCase.pleaseEnterInputTags')"
allow-clear
/>
</a-form-item>
@ -101,7 +101,7 @@
const initDefaultForm: FormItem = {
type: 'SELECT',
name: 'name',
label: 'featureTest.featureCase.batchUpdate',
label: 'caseManagement.featureCase.batchUpdate',
value: '',
options: [],
props: {
@ -143,7 +143,7 @@
return {
type: val,
name: item.fieldId,
label: 'featureTest.featureCase.batchUpdate',
label: 'caseManagement.featureCase.batchUpdate',
value: item.defaultValue,
options: item.options,
props: {
@ -185,7 +185,7 @@
customField,
};
await batchEditAttrs(params);
Message.success(t('featureTest.featureCase.editSuccess'));
Message.success(t('caseManagement.featureCase.editSuccess'));
closeHandler();
emits('success');
} catch (e) {

View File

@ -8,7 +8,7 @@
@save-and-continue="saveHandler(true)"
>
<template #headerRight>
<a-select class="w-[240px]" :placeholder="t('featureTest.featureCase.versionPlaceholder')">
<a-select class="w-[240px]" :placeholder="t('caseManagement.featureCase.versionPlaceholder')">
<a-option v-for="template of versionOptions" :key="template.id" :value="template.id">{{
template.name
}}</a-option>
@ -31,7 +31,7 @@
import useFeatureCaseStore from '@/store/modules/case/featureCase';
import { scrollIntoView } from '@/utils/dom';
import { FeatureTestRouteEnum } from '@/enums/routeEnum';
import { CaseManagementRouteEnum } from '@/enums/routeEnum';
import Message from '@arco-design/web-vue/es/message';
@ -68,17 +68,17 @@
loading.value = true;
if (route.params.mode === 'edit') {
await updateCaseRequest(caseDetailInfo.value);
Message.success(t('featureTest.featureCase.editSuccess'));
Message.success(t('caseManagement.featureCase.editSuccess'));
} else {
await createCaseRequest(caseDetailInfo.value);
Message.success(route.params.mode === 'copy' ? t('ms.description.copySuccess') : t('common.addSuccess'));
}
router.push({ name: FeatureTestRouteEnum.FEATURE_TEST_CASE, query: { ...route.query } });
router.push({ name: CaseManagementRouteEnum.CASE_MANAGEMENT_CASE, query: { ...route.query } });
featureCaseStore.setIsAlreadySuccess(true);
isShowTip.value = !getIsVisited();
if (isShowTip.value) {
router.push({
name: FeatureTestRouteEnum.FEATURE_TEST_CASE_CREATE_SUCCESS,
name: CaseManagementRouteEnum.CASE_MANAGEMENT_CASE_CREATE_SUCCESS,
});
}
} catch (error) {
@ -112,11 +112,11 @@
watchEffect(() => {
if (route.params.mode === 'edit') {
title.value = t('featureTest.featureCase.updateCase');
title.value = t('caseManagement.featureCase.updateCase');
} else if (route.params.mode === 'copy') {
title.value = t('featureTest.featureCase.copyCase');
title.value = t('caseManagement.featureCase.copyCase');
} else {
title.value = t('featureTest.featureCase.creatingCase');
title.value = t('caseManagement.featureCase.creatingCase');
}
});
</script>

View File

@ -6,12 +6,12 @@
<span class="text-[var(--color-text-4)]"> ({{ props.modulesCount[props.activeFolder] }})</span></div
>
<div class="flex w-[80%] items-center justify-end">
<a-select class="w-[240px]" :placeholder="t('featureTest.featureCase.versionPlaceholder')">
<a-select class="w-[240px]" :placeholder="t('caseManagement.featureCase.versionPlaceholder')">
<a-option v-for="version of versionOptions" :key="version.id" :value="version.id">{{ version.name }}</a-option>
</a-select>
<a-input-search
v-model:model-value="keyword"
:placeholder="t('featureTest.featureCase.searchByNameAndId')"
:placeholder="t('caseManagement.featureCase.searchByNameAndId')"
allow-clear
class="mx-[8px] w-[240px]"
@search="searchList"
@ -25,7 +25,7 @@
>
<span :class="!isExpandFilter ? 'text-[var(--color-text-4)]' : ''" @click="isExpandFilterHandler"
><icon-filter class="mr-[4px]" :style="{ 'font-size': '16px' }" />{{
t('featureTest.featureCase.filter')
t('caseManagement.featureCase.filter')
}}</span
>
</MsTag>
@ -83,7 +83,7 @@
</template>
<template #operation="{ record }">
<MsButton @click="operateCase(record, 'edit')">{{ t('common.edit') }}</MsButton>
<MsButton @click="operateCase(record, 'copy')">{{ t('featureTest.featureCase.copy') }}</MsButton>
<MsButton @click="operateCase(record, 'copy')">{{ t('caseManagement.featureCase.copy') }}</MsButton>
<MsButton class="!mr-0" @click="deleteCase(record)">{{ t('common.delete') }}</MsButton>
</template>
</ms-base-table>
@ -96,8 +96,8 @@
:ok-text="
t(
isMove
? 'featureTest.featureCase.batchMoveSelectedModules'
: 'featureTest.featureCase.batchCopySelectedModules',
? 'caseManagement.featureCase.batchMoveSelectedModules'
: 'caseManagement.featureCase.batchCopySelectedModules',
{
number: batchParams?.currentSelectCount || batchParams?.selectedIds?.length,
}
@ -111,9 +111,9 @@
<template #title>
<div class="flex w-full items-center justify-between">
<div>
{{ isMove ? t('featureTest.featureCase.batchMoveTitle') : t('featureTest.featureCase.batchCopyTitle') }}
{{ isMove ? t('caseManagement.featureCase.batchMoveTitle') : t('caseManagement.featureCase.batchCopyTitle') }}
<span class="ml-[4px] text-[var(--color-text-4)]">
{{ t('featureTest.featureCase.batchMove', { number: batchParams.currentSelectCount }) }}
{{ t('caseManagement.featureCase.batchMove', { number: batchParams.currentSelectCount }) }}
</span>
</div>
<div class="mr-2">
@ -172,7 +172,7 @@
import type { CaseManagementTable, CaseModuleQueryParams } from '@/models/caseManagement/featureCase';
import type { TableQueryParams } from '@/models/common';
import { FeatureTestRouteEnum } from '@/enums/routeEnum';
import { CaseManagementRouteEnum } from '@/enums/routeEnum';
import { ColumnEditTypeEnum, TableKeyEnum } from '@/enums/tableEnum';
import { getReviewStatusClass, getStatusText } from './utils';
@ -276,7 +276,7 @@
const columns: MsTableColumn = [
{
title: 'featureTest.featureCase.tableColumnID',
title: 'caseManagement.featureCase.tableColumnID',
dataIndex: 'id',
width: 200,
showInTable: true,
@ -288,7 +288,7 @@
showDrag: false,
},
{
title: 'featureTest.featureCase.tableColumnName',
title: 'caseManagement.featureCase.tableColumnName',
slotName: 'name',
dataIndex: 'name',
showInTable: true,
@ -302,7 +302,7 @@
showDrag: false,
},
{
title: 'featureTest.featureCase.tableColumnLevel',
title: 'caseManagement.featureCase.tableColumnLevel',
dataIndex: 'level',
showInTable: true,
width: 200,
@ -311,7 +311,7 @@
showDrag: true,
},
{
title: 'featureTest.featureCase.tableColumnCaseState',
title: 'caseManagement.featureCase.tableColumnCaseState',
dataIndex: 'caseState',
showInTable: true,
width: 200,
@ -320,7 +320,7 @@
showDrag: true,
},
{
title: 'featureTest.featureCase.tableColumnReviewResult',
title: 'caseManagement.featureCase.tableColumnReviewResult',
dataIndex: 'reviewStatus',
slotName: 'reviewStatus',
showInTable: true,
@ -328,7 +328,7 @@
showDrag: true,
},
{
title: 'featureTest.featureCase.tableColumnExecutionResult',
title: 'caseManagement.featureCase.tableColumnExecutionResult',
dataIndex: 'lastExecuteResult',
slotName: 'lastExecuteResult',
showInTable: true,
@ -336,7 +336,7 @@
showDrag: true,
},
{
title: 'featureTest.featureCase.tableColumnVersion',
title: 'caseManagement.featureCase.tableColumnVersion',
slotName: 'versionId',
dataIndex: 'versionId',
width: 300,
@ -345,14 +345,14 @@
showDrag: true,
},
{
title: 'featureTest.featureCase.tableColumnModule',
title: 'caseManagement.featureCase.tableColumnModule',
slotName: 'moduleId',
showInTable: true,
width: 300,
showDrag: true,
},
{
title: 'featureTest.featureCase.tableColumnTag',
title: 'caseManagement.featureCase.tableColumnTag',
slotName: 'tags',
dataIndex: 'tags',
showInTable: true,
@ -360,7 +360,7 @@
showDrag: true,
},
{
title: 'featureTest.featureCase.tableColumnUpdateTime',
title: 'caseManagement.featureCase.tableColumnUpdateTime',
slotName: 'updateTime',
dataIndex: 'updateTime',
sortable: {
@ -371,14 +371,14 @@
showDrag: true,
},
{
title: 'featureTest.featureCase.tableColumnCreateUser',
title: 'caseManagement.featureCase.tableColumnCreateUser',
slotName: 'createUser',
dataIndex: 'createUser',
showInTable: true,
showDrag: true,
},
{
title: 'featureTest.featureCase.tableColumnCreateTime',
title: 'caseManagement.featureCase.tableColumnCreateTime',
slotName: 'createTime',
dataIndex: 'createTime',
showInTable: true,
@ -389,7 +389,7 @@
showDrag: true,
},
{
title: 'featureTest.featureCase.tableColumnActions',
title: 'caseManagement.featureCase.tableColumnActions',
slotName: 'operation',
dataIndex: 'operation',
fixed: 'right',
@ -401,15 +401,15 @@
const tableBatchActions = {
baseAction: [
{
label: 'featureTest.featureCase.export',
label: 'caseManagement.featureCase.export',
eventTag: 'export',
children: [
{
label: 'featureTest.featureCase.exportExcel',
label: 'caseManagement.featureCase.exportExcel',
eventTag: 'exportExcel',
},
{
label: 'featureTest.featureCase.exportXMind',
label: 'caseManagement.featureCase.exportXMind',
eventTag: 'exportXMind',
},
],
@ -419,25 +419,25 @@
eventTag: 'batchEdit',
},
{
label: 'featureTest.featureCase.moveTo',
label: 'caseManagement.featureCase.moveTo',
eventTag: 'batchMoveTo',
},
{
label: 'featureTest.featureCase.copyTo',
label: 'caseManagement.featureCase.copyTo',
eventTag: 'batchCopyTo',
},
],
moreAction: [
{
label: 'featureTest.featureCase.associatedDemand',
label: 'caseManagement.featureCase.associatedDemand',
eventTag: 'associatedDemand',
},
{
label: 'featureTest.featureCase.generatingDependencies',
label: 'caseManagement.featureCase.generatingDependencies',
eventTag: 'generatingDependencies',
},
{
label: 'featureTest.featureCase.addToPublic',
label: 'caseManagement.featureCase.addToPublic',
eventTag: 'addToPublic',
},
{
@ -554,7 +554,7 @@
// &
function operateCase(record: CaseManagementTable, mode: string) {
router.push({
name: FeatureTestRouteEnum.FEATURE_TEST_CASE_DETAIL,
name: CaseManagementRouteEnum.CASE_MANAGEMENT_CASE_DETAIL,
query: {
id: record.id,
},
@ -568,8 +568,8 @@
function deleteCase(record: CaseManagementTable) {
openModal({
type: 'error',
title: t('featureTest.featureCase.deleteCaseTitle', { name: characterLimit(record.name) }),
content: t('featureTest.featureCase.beforeDeleteCase'),
title: t('caseManagement.featureCase.deleteCaseTitle', { name: characterLimit(record.name) }),
content: t('caseManagement.featureCase.beforeDeleteCase'),
okText: t('common.confirmDelete'),
cancelText: t('common.cancel'),
okButtonProps: {
@ -640,10 +640,10 @@
};
if (isMove.value) {
await batchMoveToModules(params);
Message.success(t('featureTest.featureCase.batchMoveSuccess'));
Message.success(t('caseManagement.featureCase.batchMoveSuccess'));
} else {
await batchCopyToModules(params);
Message.success(t('featureTest.featureCase.batchCopySuccess'));
Message.success(t('caseManagement.featureCase.batchCopySuccess'));
}
isMove.value = false;
emitTableParams();
@ -672,7 +672,7 @@
const moduleNamePath = computed(() => {
return props.activeFolder === 'all'
? t('featureTest.featureCase.allCase')
? t('caseManagement.featureCase.allCase')
: findNodeByKey<Record<string, any>>(caseTreeData.value, featureCaseStore.moduleId[0], 'id')?.name;
});
// name
@ -689,8 +689,8 @@
async function batchDelete() {
openModal({
type: 'error',
title: t('featureTest.featureCase.batchDelete', { number: (selectData.value || []).length }),
content: t('featureTest.featureCase.beforeDeleteCase'),
title: t('caseManagement.featureCase.batchDelete', { number: (selectData.value || []).length }),
content: t('caseManagement.featureCase.beforeDeleteCase'),
okText: t('common.confirmDelete'),
cancelText: t('common.cancel'),
okButtonProps: {

View File

@ -116,14 +116,14 @@
<a-form-item
v-if="form.caseEditType === 'TEXT'"
field="remark"
:label="t('featureTest.featureCase.expectedResult')"
:label="t('caseManagement.featureCase.expectedResult')"
>
<MsRichText v-model:modelValue="form.expectedResult" />
</a-form-item>
<a-form-item field="remark" :label="t('featureTest.featureCase.remark')">
<a-form-item field="remark" :label="t('caseManagement.featureCase.remark')">
<MsRichText v-model:modelValue="form.description" />
</a-form-item>
<a-form-item field="attachment" :label="t('featureTest.featureCase.addAttachment')">
<a-form-item field="attachment" :label="t('caseManagement.featureCase.addAttachment')">
<div class="flex flex-col">
<div class="mb-1">
<a-dropdown position="tr" trigger="hover">
@ -142,13 +142,13 @@
>
<template #upload-button>
<a-button type="text" class="!text-[var(--color-text-1)]">
<icon-upload />{{ t('featureTest.featureCase.uploadFile') }}</a-button
<icon-upload />{{ t('caseManagement.featureCase.uploadFile') }}</a-button
>
</template>
</a-upload>
<a-button type="text" class="!text-[var(--color-text-1)]" @click="associatedFile">
<MsIcon type="icon-icon_link-copy_outlined" size="16" />{{
t('featureTest.featureCase.associatedFile')
t('caseManagement.featureCase.associatedFile')
}}</a-button
>
</template>
@ -167,19 +167,19 @@
<!-- 本地文件 -->
<div v-if="item.local || item.status === 'init'" class="flex flex-nowrap">
<MsButton type="button" status="danger" class="!mr-[4px]" @click="transferFile(item)">
{{ t('featureTest.featureCase.storage') }}
{{ t('caseManagement.featureCase.storage') }}
</MsButton>
<MsButton type="button" status="primary" class="!mr-[4px]" @click="downloadFile(item)">
{{ t('featureTest.featureCase.download') }}
{{ t('caseManagement.featureCase.download') }}
</MsButton>
</div>
<!-- 关联文件 -->
<div v-else class="flex flex-nowrap">
<MsButton type="button" status="primary" class="!mr-[4px]" @click="cancelAssociated(item)">
{{ t('featureTest.featureCase.cancelLink') }}
{{ t('caseManagement.featureCase.cancelLink') }}
</MsButton>
<MsButton type="button" status="primary" class="!mr-[4px]" @click="downloadFile(item)">
{{ t('featureTest.featureCase.download') }}
{{ t('caseManagement.featureCase.download') }}
</MsButton>
</div>
</template>
@ -348,15 +348,15 @@
const moreActions: ActionsItem[] = [
{
label: 'featureTest.featureCase.copyStep',
label: 'caseManagement.featureCase.copyStep',
eventTag: 'copyStep',
},
{
label: 'featureTest.featureCase.InsertStepsBefore',
label: 'caseManagement.featureCase.InsertStepsBefore',
eventTag: 'InsertStepsBefore',
},
{
label: 'featureTest.featureCase.afterInsertingSteps',
label: 'caseManagement.featureCase.afterInsertingSteps',
eventTag: 'afterInsertingSteps',
},
{

View File

@ -1,7 +1,7 @@
<template>
<a-input-search
v-model:model-value="groupKeyword"
:placeholder="t('featureTest.featureCase.searchTip')"
:placeholder="t('caseManagement.featureCase.searchTip')"
allow-clear
class="mb-[16px]"
></a-input-search>
@ -13,7 +13,7 @@
:keyword="groupKeyword"
:node-more-actions="caseMoreActions"
:expand-all="props.isExpandAll"
:empty-text="t('featureTest.featureCase.caseEmptyContent')"
:empty-text="t('caseManagement.featureCase.caseEmptyContent')"
draggable
:virtual-list-props="virtualListProps"
block-node
@ -40,10 +40,10 @@
:visible="addSubVisible"
:is-delete="false"
:all-names="[]"
:title="t('featureTest.featureCase.addSubModule')"
:title="t('caseManagement.featureCase.addSubModule')"
:ok-text="t('common.confirm')"
:field-config="{
placeholder: t('featureTest.featureCase.addGroupTip'),
placeholder: t('caseManagement.featureCase.addGroupTip'),
}"
:loading="confirmLoading"
@confirm="addSubModule"
@ -54,7 +54,7 @@
</MsButton>
</MsPopConfirm>
<MsPopConfirm
:title="t('featureTest.featureCase.rename')"
:title="t('caseManagement.featureCase.rename')"
:all-names="[]"
:is-delete="false"
:ok-text="t('common.confirm')"
@ -125,11 +125,11 @@
const caseMoreActions: ActionsItem[] = [
{
label: 'featureTest.featureCase.rename',
label: 'caseManagement.featureCase.rename',
eventTag: 'rename',
},
{
label: 'featureTest.featureCase.delete',
label: 'caseManagement.featureCase.delete',
eventTag: 'delete',
danger: true,
},
@ -188,9 +188,9 @@
const deleteHandler = (node: MsTreeNodeData) => {
openModal({
type: 'error',
title: t('featureTest.featureCase.deleteTipTitle', { name: node.name }),
content: t('featureTest.featureCase.deleteCaseTipContent'),
okText: t('featureTest.featureCase.deleteConfirm'),
title: t('caseManagement.featureCase.deleteTipTitle', { name: node.name }),
content: t('caseManagement.featureCase.deleteCaseTipContent'),
okText: t('caseManagement.featureCase.deleteConfirm'),
okButtonProps: {
status: 'danger',
},
@ -198,7 +198,7 @@
onBeforeOk: async () => {
try {
await deleteCaseModuleTree(node.id);
Message.success(t('featureTest.featureCase.deleteSuccess'));
Message.success(t('caseManagement.featureCase.deleteSuccess'));
initModules(selectedNodeKeys.value[0] === node.id);
} catch (error) {
console.log(error);
@ -264,7 +264,7 @@
dropNodeId: dropNode.id || '',
dropPosition,
});
Message.success(t('featureTest.featureCase.moduleMoveSuccess'));
Message.success(t('caseManagement.featureCase.moduleMoveSuccess'));
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
@ -293,7 +293,7 @@
parentId: focusNodeKey.value,
};
await createCaseModuleTree(params);
Message.success(t('featureTest.featureCase.addSuccess'));
Message.success(t('caseManagement.featureCase.addSuccess'));
if (cancel) {
cancel();
}
@ -314,7 +314,7 @@
name: formValue?.field as string,
};
await updateCaseModuleTree(params);
Message.success(t('featureTest.featureCase.addSuccess'));
Message.success(t('caseManagement.featureCase.addSuccess'));
if (cancel) {
cancel();
}

View File

@ -3,22 +3,24 @@
<div class="h-full">
<div class="mt-8 text-center">
<div class="flex justify-center"><svg-icon :width="'60px'" :height="'60px'" :name="'success'" /></div>
<div class="mb-2 mt-6 text-[20px] font-medium"> {{ t('featureTest.featureCase.editSuccess') }} </div>
<div class="mb-2 mt-6 text-[20px] font-medium"> {{ t('caseManagement.featureCase.editSuccess') }} </div>
<div
><span class="mr-1 text-[rgb(var(--primary-5))]">{{ countDown }}</span
><span class="text-[var(--color-text-4)]">{{ t('featureTest.featureCase.countDownTip') }}</span></div
><span class="text-[var(--color-text-4)]">{{ t('caseManagement.featureCase.countDownTip') }}</span></div
>
<div class="my-6">
<a-button type="primary"> {{ t('featureTest.featureCase.caseDetail') }} </a-button>
<a-button type="primary"> {{ t('caseManagement.featureCase.caseDetail') }} </a-button>
<a-button class="mx-3" type="outline" @click="continueCreate">
{{ t('featureTest.featureCase.addContinueCreate') }}
{{ t('caseManagement.featureCase.addContinueCreate') }}
</a-button>
<a-button type="secondary" @click="backCaseList">
{{ t('caseManagement.featureCase.backCaseList') }}
</a-button>
<a-button type="secondary" @click="backCaseList"> {{ t('featureTest.featureCase.backCaseList') }} </a-button>
</div>
<a-checkbox v-model="isNextTip" class="mb-6">{{ t('featureTest.featureCase.notNextTip') }}</a-checkbox>
<a-checkbox v-model="isNextTip" class="mb-6">{{ t('caseManagement.featureCase.notNextTip') }}</a-checkbox>
</div>
<div>
<div class="mb-4 font-medium">{{ t('featureTest.featureCase.mightWantTo') }}</div>
<div class="mb-4 font-medium">{{ t('caseManagement.featureCase.mightWantTo') }}</div>
<MsCardList
mode="static"
:card-min-width="569"
@ -39,7 +41,7 @@
<div class="ml-2"> {{ item.name }} </div>
</div>
<a-button type="outline"> {{ t('featureTest.featureCase.addContinueCreate') }} </a-button>
<a-button type="outline"> {{ t('caseManagement.featureCase.addContinueCreate') }} </a-button>
</div>
</div>
</template>
@ -59,7 +61,7 @@
import { useI18n } from '@/hooks/useI18n';
import useVisit from '@/hooks/useVisit';
import { FeatureTestRouteEnum } from '@/enums/routeEnum';
import { CaseManagementRouteEnum } from '@/enums/routeEnum';
const { t } = useI18n();
@ -70,11 +72,11 @@
const cardList = ref([
{
key: 'testPlanTemplate',
name: t('featureTest.featureCase.createTestPlan'),
name: t('caseManagement.featureCase.createTestPlan'),
},
{
key: 'caseReview',
name: t('featureTest.featureCase.createCaseReview'),
name: t('caseManagement.featureCase.createCaseReview'),
},
]);
@ -88,7 +90,7 @@
} else {
clearInterval(timer.value);
router.push({
name: FeatureTestRouteEnum.FEATURE_TEST_CASE,
name: CaseManagementRouteEnum.CASE_MANAGEMENT_CASE,
});
}
}, 1000);
@ -103,14 +105,14 @@
//
function backCaseList() {
router.push({
name: FeatureTestRouteEnum.FEATURE_TEST_CASE,
name: CaseManagementRouteEnum.CASE_MANAGEMENT_CASE,
});
}
//
function continueCreate() {
router.push({
name: FeatureTestRouteEnum.FEATURE_TEST_CASE_DETAIL,
name: CaseManagementRouteEnum.CASE_MANAGEMENT_CASE_DETAIL,
});
}

View File

@ -2,8 +2,8 @@
<MsDrawer
v-model:visible="showDrawer"
:mask="false"
:title="t('featureTest.featureCase.associatedFile')"
:ok-text="t('featureTest.featureCase.associated')"
:title="t('caseManagement.featureCase.associatedFile')"
:ok-text="t('caseManagement.featureCase.associated')"
:ok-loading="drawerLoading"
:width="480"
unmount-on-close
@ -12,13 +12,13 @@
@cancel="handleDrawerCancel"
>
<div class="header mb-6 flex justify-between">
<span class="font-medium">{{ t('featureTest.featureCase.SelectExportRange') }}</span>
<span class="text-[rgb(var(--primary-5))]">{{ t('featureTest.featureCase.clear') }}</span>
<span class="font-medium">{{ t('caseManagement.featureCase.SelectExportRange') }}</span>
<span class="text-[rgb(var(--primary-5))]">{{ t('caseManagement.featureCase.clear') }}</span>
</div>
<div>
<a-checkbox class="mb-4" :model-value="checkedAll" :indeterminate="indeterminate" @change="handleChangeAll"
><div class="flex items-center">
<span class="mr-1">{{ t('featureTest.featureCase.baseField') }}</span
<span class="mr-1">{{ t('caseManagement.featureCase.baseField') }}</span
><span
><icon-up
v-if="foldBaseFields"
@ -52,7 +52,7 @@
<div>
<a-checkbox class="mb-4" :model-value="checkedAll" :indeterminate="indeterminate" @change="handleChangeAll"
><div class="flex items-center">
<span class="mr-1">{{ t('featureTest.featureCase.customField') }}</span
<span class="mr-1">{{ t('caseManagement.featureCase.customField') }}</span
><span
><icon-up
v-if="foldCustomFields"
@ -87,9 +87,9 @@
<a-checkbox class="mb-4" :model-value="checkedAll" :indeterminate="indeterminate" @change="handleChangeAll"
><div class="flex items-center">
<span class="mr-1 flex items-center"
>{{ t('featureTest.featureCase.otherFields') }}<span></span>
>{{ t('caseManagement.featureCase.otherFields') }}<span></span>
<a-tooltip
:content="t('featureTest.featureCase.otherFieldsToolTip')"
:content="t('caseManagement.featureCase.otherFieldsToolTip')"
position="top"
:mouse-enter-delay="500"
mini

View File

@ -5,7 +5,7 @@
<div class="p-[24px]">
<a-input-search
v-model:model-value="groupKeyword"
:placeholder="t('featureTest.featureCase.searchTip')"
:placeholder="t('caseManagement.featureCase.searchTip')"
allow-clear
class="mb-[16px]"
></a-input-search>
@ -13,7 +13,7 @@
<div class="case h-[38px]">
<div class="flex items-center" :class="getActiveClass('all')" @click="setActiveFolder('all')">
<MsIcon type="icon-icon_folder_filled1" class="folder-icon" />
<div class="folder-name mx-[4px]">{{ t('featureTest.featureCase.allCase') }}</div>
<div class="folder-name mx-[4px]">{{ t('caseManagement.featureCase.allCase') }}</div>
<div class="folder-count">({{ recycleModulesCount.all }})</div></div
>
<div class="ml-auto flex items-center">
@ -36,7 +36,7 @@
:data="caseTree"
:keyword="groupKeyword"
:expand-all="isExpandAll"
:empty-text="t('featureTest.featureCase.caseEmptyRecycle')"
:empty-text="t('caseManagement.featureCase.caseEmptyRecycle')"
draggable
:virtual-list-props="virtualListProps"
block-node
@ -68,14 +68,14 @@
<span class="text-[var(--color-text-4)]"> ({{ recycleModulesCount[activeFolder] }})</span></div
>
<div class="flex w-[80%] items-center justify-end">
<a-select class="w-[240px]" :placeholder="t('featureTest.featureCase.versionPlaceholder')">
<a-select class="w-[240px]" :placeholder="t('caseManagement.featureCase.versionPlaceholder')">
<a-option v-for="version of versionOptions" :key="version.id" :value="version.id">{{
version.name
}}</a-option>
</a-select>
<a-input-search
v-model="keyword"
:placeholder="t('featureTest.featureCase.searchByNameAndId')"
:placeholder="t('caseManagement.featureCase.searchByNameAndId')"
allow-clear
class="mx-[8px] w-[240px]"
@search="searchList"
@ -112,9 +112,9 @@
</a-tooltip>
</template>
<template #operation="{ record }">
<MsButton @click="recoverCase(record.id)">{{ t('featureTest.featureCase.batchRecover') }}</MsButton>
<MsButton @click="recoverCase(record.id)">{{ t('caseManagement.featureCase.batchRecover') }}</MsButton>
<MsButton class="!mr-0" @click="handleBatchCleanOut(record)">{{
t('featureTest.featureCase.batchCleanOut')
t('caseManagement.featureCase.batchCleanOut')
}}</MsButton>
</template>
</ms-base-table>
@ -209,7 +209,7 @@
const columns: MsTableColumn = [
{
title: 'featureTest.featureCase.tableColumnID',
title: 'caseManagement.featureCase.tableColumnID',
dataIndex: 'id',
width: 200,
showInTable: true,
@ -221,7 +221,7 @@
showDrag: false,
},
{
title: 'featureTest.featureCase.tableColumnName',
title: 'caseManagement.featureCase.tableColumnName',
slotName: 'name',
dataIndex: 'name',
showInTable: true,
@ -234,7 +234,7 @@
showDrag: false,
},
{
title: 'featureTest.featureCase.tableColumnLevel',
title: 'caseManagement.featureCase.tableColumnLevel',
dataIndex: 'level',
showInTable: true,
width: 200,
@ -243,7 +243,7 @@
showDrag: true,
},
{
title: 'featureTest.featureCase.tableColumnCaseState',
title: 'caseManagement.featureCase.tableColumnCaseState',
dataIndex: 'caseState',
showInTable: true,
width: 200,
@ -252,7 +252,7 @@
showDrag: true,
},
{
title: 'featureTest.featureCase.tableColumnReviewResult',
title: 'caseManagement.featureCase.tableColumnReviewResult',
dataIndex: 'reviewStatus',
slotName: 'reviewStatus',
showInTable: true,
@ -260,7 +260,7 @@
showDrag: true,
},
{
title: 'featureTest.featureCase.tableColumnExecutionResult',
title: 'caseManagement.featureCase.tableColumnExecutionResult',
dataIndex: 'lastExecuteResult',
slotName: 'lastExecuteResult',
showInTable: true,
@ -268,7 +268,7 @@
showDrag: true,
},
{
title: 'featureTest.featureCase.tableColumnVersion',
title: 'caseManagement.featureCase.tableColumnVersion',
slotName: 'versionId',
dataIndex: 'versionId',
width: 300,
@ -277,14 +277,14 @@
showDrag: true,
},
{
title: 'featureTest.featureCase.tableColumnModule',
title: 'caseManagement.featureCase.tableColumnModule',
slotName: 'moduleId',
showInTable: true,
width: 300,
showDrag: true,
},
{
title: 'featureTest.featureCase.tableColumnTag',
title: 'caseManagement.featureCase.tableColumnTag',
slotName: 'tags',
dataIndex: 'tags',
showInTable: true,
@ -292,14 +292,14 @@
showDrag: true,
},
{
title: 'featureTest.featureCase.tableColumnCreateUser',
title: 'caseManagement.featureCase.tableColumnCreateUser',
slotName: 'createUser',
dataIndex: 'createUser',
showInTable: true,
showDrag: true,
},
{
title: 'featureTest.featureCase.tableColumnCreateTime',
title: 'caseManagement.featureCase.tableColumnCreateTime',
slotName: 'createTime',
dataIndex: 'createTime',
showInTable: true,
@ -310,7 +310,7 @@
showDrag: true,
},
{
title: 'featureTest.featureCase.tableColumnUpdateUser',
title: 'caseManagement.featureCase.tableColumnUpdateUser',
slotName: 'updateUser',
dataIndex: 'updateUser',
showInTable: true,
@ -318,7 +318,7 @@
showDrag: true,
},
{
title: 'featureTest.featureCase.tableColumnUpdateTime',
title: 'caseManagement.featureCase.tableColumnUpdateTime',
slotName: 'updateTime',
dataIndex: 'updateTime',
sortable: {
@ -329,7 +329,7 @@
showDrag: true,
},
{
title: 'featureTest.featureCase.tableColumnActions',
title: 'caseManagement.featureCase.tableColumnActions',
slotName: 'operation',
dataIndex: 'operation',
fixed: 'right',
@ -342,11 +342,11 @@
const tableBatchActions = {
baseAction: [
{
label: 'featureTest.featureCase.batchRecover',
label: 'caseManagement.featureCase.batchRecover',
eventTag: 'batchRecover',
},
{
label: 'featureTest.featureCase.batchCleanOut',
label: 'caseManagement.featureCase.batchCleanOut',
eventTag: 'batchCleanOut',
danger: true,
},
@ -445,7 +445,7 @@
const currentModuleName = computed(() => {
return activeFolder.value === 'all'
? t('featureTest.featureCase.allCase')
? t('caseManagement.featureCase.allCase')
: findNodeByKey<Record<string, any>>(caseTree.value, activeFolder.value, 'id')?.name;
});
@ -495,7 +495,7 @@
async function handleBatchRecover() {
try {
await restoreCaseList(getBatchParams());
Message.success(t('featureTest.featureCase.recoveredSuccessfully'));
Message.success(t('caseManagement.featureCase.recoveredSuccessfully'));
loadList();
resetSelector();
initRecycleModulesCount();
@ -507,8 +507,8 @@
async function handleBatchDelete() {
openModal({
type: 'error',
title: t('featureTest.featureCase.batchDelete', { number: batchParams.value.currentSelectCount }),
content: t('featureTest.featureCase.cleanOutDeleteTip'),
title: t('caseManagement.featureCase.batchDelete', { number: batchParams.value.currentSelectCount }),
content: t('caseManagement.featureCase.cleanOutDeleteTip'),
okText: t('common.confirmDelete'),
cancelText: t('common.cancel'),
okButtonProps: {
@ -580,7 +580,7 @@
async function recoverCase(id: string) {
try {
await recoverRecycleCase(id);
Message.success(t('featureTest.featureCase.recoveredSuccessfully'));
Message.success(t('caseManagement.featureCase.recoveredSuccessfully'));
loadList();
resetSelector();
initRecycleModulesCount();
@ -593,8 +593,8 @@
function handleBatchCleanOut(record: CaseManagementTable) {
openModal({
type: 'error',
title: t('featureTest.featureCase.deleteCaseTitle', { name: characterLimit(record.name) }),
content: t('featureTest.featureCase.cleanOutDeleteTip'),
title: t('caseManagement.featureCase.deleteCaseTitle', { name: characterLimit(record.name) }),
content: t('caseManagement.featureCase.cleanOutDeleteTip'),
okText: t('common.confirmDelete'),
cancelText: t('common.cancel'),
okButtonProps: {

View File

@ -9,52 +9,52 @@ const statusIconMap = [
{
key: 'UN_REVIEWED',
icon: StatusType.UN_REVIEWED,
statusText: t('featureTest.featureCase.notReviewed'),
statusText: t('caseManagement.featureCase.notReviewed'),
},
{
key: 'UNDER_REVIEWED',
icon: StatusType.UNDER_REVIEWED,
statusText: t('featureTest.featureCase.reviewing'),
statusText: t('caseManagement.featureCase.reviewing'),
},
{
key: 'PASS',
icon: StatusType.PASS,
statusText: t('featureTest.featureCase.passed'),
statusText: t('caseManagement.featureCase.passed'),
},
{
key: 'UN_PASS',
icon: StatusType.UN_PASS,
statusText: t('featureTest.featureCase.notPass'),
statusText: t('caseManagement.featureCase.notPass'),
},
{
key: 'RE_REVIEWED',
icon: StatusType.RE_REVIEWED,
statusText: t('featureTest.featureCase.retrial'),
statusText: t('caseManagement.featureCase.retrial'),
},
{
key: 'UN_EXECUTED',
icon: StatusType.UN_EXECUTED,
statusText: t('featureTest.featureCase.nonExecution'),
statusText: t('caseManagement.featureCase.nonExecution'),
},
{
key: 'PASSED',
icon: StatusType.PASSED,
statusText: t('featureTest.featureCase.passed'),
statusText: t('caseManagement.featureCase.passed'),
},
{
key: 'FAILED',
icon: StatusType.FAILED,
statusText: t('featureTest.featureCase.failure'),
statusText: t('caseManagement.featureCase.failure'),
},
{
key: 'BLOCKED',
icon: StatusType.BLOCKED,
statusText: t('featureTest.featureCase.chokeUp'),
statusText: t('caseManagement.featureCase.chokeUp'),
},
{
key: 'SKIPPED',
icon: StatusType.SKIPPED,
statusText: t('featureTest.featureCase.skip'),
statusText: t('caseManagement.featureCase.skip'),
},
];

View File

@ -1,10 +1,10 @@
<template>
<div class="mb-[16px]">
<a-button type="primary" @click="caseDetail">
{{ t('featureTest.featureCase.creatingCase') }}
{{ t('caseManagement.featureCase.creatingCase') }}
</a-button>
<a-button class="mx-3" type="outline"> {{ t('featureTest.featureCase.importExcel') }} </a-button>
<a-button type="outline"> {{ t('featureTest.featureCase.importXmind') }} </a-button>
<a-button class="mx-3" type="outline"> {{ t('caseManagement.featureCase.importExcel') }} </a-button>
<a-button type="outline"> {{ t('caseManagement.featureCase.importXmind') }} </a-button>
</div>
<div class="pageWrap">
<MsSplitBox>
@ -14,7 +14,7 @@
<div class="case h-[38px]">
<div class="flex items-center" :class="getActiveClass('all')" @click="setActiveFolder('all')">
<MsIcon type="icon-icon_folder_filled1" class="folder-icon" />
<div class="folder-name mx-[4px]">{{ t('featureTest.featureCase.allCase') }}</div>
<div class="folder-name mx-[4px]">{{ t('caseManagement.featureCase.allCase') }}</div>
<div class="folder-count">({{ modulesCount.all }})</div></div
>
<div class="ml-auto flex items-center">
@ -31,12 +31,12 @@
ref="confirmRef"
v-model:visible="addSubVisible"
:is-delete="false"
:title="t('featureTest.featureCase.addSubModule')"
:title="t('caseManagement.featureCase.addSubModule')"
:all-names="rootModulesName"
:loading="confirmLoading"
:ok-text="t('common.confirm')"
:field-config="{
placeholder: t('featureTest.featureCase.addGroupTip'),
placeholder: t('caseManagement.featureCase.addGroupTip'),
}"
@confirm="confirmHandler"
>
@ -66,7 +66,7 @@
<div class="case h-[38px]">
<div class="flex items-center" :class="getActiveClass('recycle')" @click="setActiveFolder('recycle')">
<MsIcon type="icon-icon_delete-trash_outlined" class="folder-icon" />
<div class="folder-name mx-[4px]">{{ t('featureTest.featureCase.recycle') }}</div>
<div class="folder-name mx-[4px]">{{ t('caseManagement.featureCase.recycle') }}</div>
<div class="folder-count">({{ recycleModulesCount.all }})</div></div
>
</div>
@ -109,7 +109,7 @@
import useFeatureCaseStore from '@/store/modules/case/featureCase';
import type { CaseModuleQueryParams, CreateOrUpdateModule } from '@/models/caseManagement/featureCase';
import { FeatureTestRouteEnum } from '@/enums/routeEnum';
import { CaseManagementRouteEnum } from '@/enums/routeEnum';
import Message from '@arco-design/web-vue/es/message';
@ -148,7 +148,7 @@
}
if (type === 'recycle') {
router.push({
name: FeatureTestRouteEnum.FEATURE_TEST_CASE_RECYCLE,
name: CaseManagementRouteEnum.CASE_MANAGEMENT_CASE_RECYCLE,
});
}
};
@ -186,7 +186,7 @@
parentId: 'NONE',
};
await createCaseModuleTree(params);
Message.success(t('featureTest.featureCase.addSuccess'));
Message.success(t('caseManagement.featureCase.addSuccess'));
caseTreeRef.value.initModules();
addSubVisible.value = false;
} catch (error) {
@ -230,19 +230,19 @@
//
function caseDetail() {
router.push({
name: FeatureTestRouteEnum.FEATURE_TEST_CASE_DETAIL,
name: CaseManagementRouteEnum.CASE_MANAGEMENT_CASE_DETAIL,
});
}
function test() {
router.push({
name: FeatureTestRouteEnum.FEATURE_TEST_CASE_CREATE_SUCCESS,
name: CaseManagementRouteEnum.CASE_MANAGEMENT_CASE_CREATE_SUCCESS,
});
}
//
router.beforeEach((to: any, from: any, next) => {
const routeEnumValues = Object.values(FeatureTestRouteEnum);
const routeEnumValues = Object.values(CaseManagementRouteEnum);
if (!routeEnumValues.includes(to.name)) {
//
featureCaseStore.setIsAlreadySuccess(false);

View File

@ -1,121 +1,122 @@
export default {
'featureTest.featureCase.creatingCase': 'Create Case',
'featureTest.featureCase.importCase': 'Import Case',
'featureTest.featureCase.importExcel': 'Import Excel',
'featureTest.featureCase.importXmind': 'Import Xmind',
'featureTest.featureCase.publicCase': 'Public of Cases',
'featureTest.featureCase.allCase': 'All of Cases',
'featureTest.featureCase.searchTip': 'Please enter a group name',
'featureTest.featureCase.caseEmptyContent': 'No use case data yet, please click the button above to create or import',
'featureTest.featureCase.addSubModule': 'Add submodules',
'featureTest.featureCase.rename': 'rename',
'featureTest.featureCase.recycle': 'Recycle',
'featureTest.featureCase.versionPlaceholder': 'The default is the latest version',
'featureTest.featureCase.searchByNameAndId': 'Search by ID or name',
'featureTest.featureCase.filter': 'filter',
'featureTest.featureCase.setFilterCondition': 'Set filters',
'featureTest.featureCase.followingCondition': 'Conform to the following',
'featureTest.featureCase.condition': 'Condition',
'featureTest.featureCase.delete': 'delete',
'featureTest.featureCase.addSubModuleSuccess': 'Add submodule successfully',
'featureTest.featureCase.renameSuccess': 'Rename successful',
'featureTest.featureCase.nameNotNullTip': 'The name can not be null',
'featureTest.featureCase.deleteTipTitle': 'Do you want to delete: {name} use case?',
'featureTest.featureCase.deleteCaseTipContent':
'caseManagement.featureCase.creatingCase': 'Create Case',
'caseManagement.featureCase.importCase': 'Import Case',
'caseManagement.featureCase.importExcel': 'Import Excel',
'caseManagement.featureCase.importXmind': 'Import Xmind',
'caseManagement.featureCase.publicCase': 'Public of Cases',
'caseManagement.featureCase.allCase': 'All of Cases',
'caseManagement.featureCase.searchTip': 'Please enter a group name',
'caseManagement.featureCase.caseEmptyContent':
'No use case data yet, please click the button above to create or import',
'caseManagement.featureCase.addSubModule': 'Add submodules',
'caseManagement.featureCase.rename': 'rename',
'caseManagement.featureCase.recycle': 'Recycle',
'caseManagement.featureCase.versionPlaceholder': 'The default is the latest version',
'caseManagement.featureCase.searchByNameAndId': 'Search by ID or name',
'caseManagement.featureCase.filter': 'filter',
'caseManagement.featureCase.setFilterCondition': 'Set filters',
'caseManagement.featureCase.followingCondition': 'Conform to the following',
'caseManagement.featureCase.condition': 'Condition',
'caseManagement.featureCase.delete': 'delete',
'caseManagement.featureCase.addSubModuleSuccess': 'Add submodule successfully',
'caseManagement.featureCase.renameSuccess': 'Rename successful',
'caseManagement.featureCase.nameNotNullTip': 'The name can not be null',
'caseManagement.featureCase.deleteTipTitle': 'Do you want to delete: {name} use case?',
'caseManagement.featureCase.deleteCaseTipContent':
'After the node is deleted, all resources under the node will be deleted. Exercise caution when performing this operation.',
'featureTest.featureCase.deleteConfirm': 'Confirm',
'featureTest.featureCase.deleteSuccess': 'Delete Successfully',
'featureTest.featureCase.addSuccess': 'Add Successfully',
'featureTest.featureCase.addGroupTip': 'Please enter the group name and press enter to save',
'featureTest.featureCase.moduleMoveSuccess': 'Move successfully',
'featureTest.featureCase.tableColumnID': 'ID',
'featureTest.featureCase.tableColumnName': 'Case Name',
'featureTest.featureCase.tableColumnLevel': 'Case Level',
'featureTest.featureCase.tableColumnCaseState': 'Case State',
'featureTest.featureCase.tableColumnReviewResult': 'Review Result',
'featureTest.featureCase.tableColumnExecutionResult': 'Execution Result',
'featureTest.featureCase.tableColumnVersion': 'version',
'featureTest.featureCase.tableColumnModule': 'Module',
'featureTest.featureCase.tableColumnTag': 'Tag',
'featureTest.featureCase.tableColumnCreateUser': 'CreateUser',
'featureTest.featureCase.tableColumnCreateTime': 'CreateTime',
'featureTest.featureCase.tableColumnUpdateUser': 'UpdateUser',
'featureTest.featureCase.tableColumnUpdateTime': 'UpdateTime',
'featureTest.featureCase.tableColumnActions': 'operation',
'featureTest.featureCase.beforeDeleteCase':
'caseManagement.featureCase.deleteConfirm': 'Confirm',
'caseManagement.featureCase.deleteSuccess': 'Delete Successfully',
'caseManagement.featureCase.addSuccess': 'Add Successfully',
'caseManagement.featureCase.addGroupTip': 'Please enter the group name and press enter to save',
'caseManagement.featureCase.moduleMoveSuccess': 'Move successfully',
'caseManagement.featureCase.tableColumnID': 'ID',
'caseManagement.featureCase.tableColumnName': 'Case Name',
'caseManagement.featureCase.tableColumnLevel': 'Case Level',
'caseManagement.featureCase.tableColumnCaseState': 'Case State',
'caseManagement.featureCase.tableColumnReviewResult': 'Review Result',
'caseManagement.featureCase.tableColumnExecutionResult': 'Execution Result',
'caseManagement.featureCase.tableColumnVersion': 'version',
'caseManagement.featureCase.tableColumnModule': 'Module',
'caseManagement.featureCase.tableColumnTag': 'Tag',
'caseManagement.featureCase.tableColumnCreateUser': 'CreateUser',
'caseManagement.featureCase.tableColumnCreateTime': 'CreateTime',
'caseManagement.featureCase.tableColumnUpdateUser': 'UpdateUser',
'caseManagement.featureCase.tableColumnUpdateTime': 'UpdateTime',
'caseManagement.featureCase.tableColumnActions': 'operation',
'caseManagement.featureCase.beforeDeleteCase':
'The deleted content will be put into the recycle bin, where data can be recovered',
'featureTest.featureCase.deleteCaseTitle': 'Are you sure to delete the {name} use case?',
'featureTest.featureCase.export': 'Export',
'featureTest.featureCase.exportExcel': 'Export spreadsheet (xlsx)',
'featureTest.featureCase.exportXMind': 'Exporting Mind (xmind)',
'featureTest.featureCase.moveTo': 'Move to',
'featureTest.featureCase.copyTo': 'Copy to',
'featureTest.featureCase.associatedDemand': 'Associated demand',
'featureTest.featureCase.generatingDependencies': 'Generative dependency',
'featureTest.featureCase.addToPublic': 'Add to public case',
'featureTest.featureCase.updateCase': 'Update Case',
'featureTest.featureCase.latestTemplate': 'The default is the latest template',
'featureTest.featureCase.copyStep': 'Copy Step',
'featureTest.featureCase.InsertStepsBefore': 'Insert steps before',
'featureTest.featureCase.afterInsertingSteps': 'After inserting steps',
'featureTest.featureCase.associatedFile': 'Associated File',
'featureTest.featureCase.associated': 'Associated',
'featureTest.featureCase.fileType': 'File Type',
'featureTest.featureCase.fileName': 'fileName',
'featureTest.featureCase.description': 'Description',
'featureTest.featureCase.tags': 'Tags',
'featureTest.featureCase.enableTags': `On: adds a label`,
'featureTest.featureCase.closeTags': 'Off: overwrites an existing label',
'featureTest.featureCase.appendTag': 'appendTag',
'featureTest.featureCase.batchEdit': 'Batch editing ({number} use cases selected)',
'featureTest.featureCase.selectAttrs': 'select attributes',
'featureTest.featureCase.batchUpdate': 'Batch update to',
'featureTest.featureCase.batchDelete': 'Are you sure to delete the use case {number} ?',
'featureTest.featureCase.batchMoveTitle': 'Batch Move',
'featureTest.featureCase.batchMove': '({number} selected use cases)',
'featureTest.featureCase.batchMoveSelectedModules': 'Batch Move',
'featureTest.featureCase.batchCopyTitle': 'Batch Copy',
'featureTest.featureCase.batchCopySelectedModules': 'Batch Copy',
'featureTest.featureCase.batchCopy': 'Copy Successfully!',
'featureTest.featureCase.editSuccess': 'update Successfully',
'featureTest.featureCase.PleaseSelect': 'Please select',
'featureTest.featureCase.PleaseInputTags': 'Please enter the update tag to add',
'featureTest.featureCase.expectedResult': 'Expected Result',
'featureTest.featureCase.remark': 'Remark',
'featureTest.featureCase.addAttachment': 'Add attachment',
'featureTest.featureCase.uploadFile': 'Upload File',
'featureTest.featureCase.storage': 'storage',
'featureTest.featureCase.download': 'download',
'featureTest.featureCase.cancelLink': 'Cancel link',
'featureTest.featureCase.SelectExportRange': 'Select export range',
'featureTest.featureCase.clear': 'Clear',
'featureTest.featureCase.baseField': 'Base Field',
'featureTest.featureCase.customField': 'Custom Field',
'featureTest.featureCase.otherFields': 'Other Fields',
'featureTest.featureCase.otherFieldsToolTip': 'Other fields do not support import after export',
'featureTest.featureCase.notReviewed': 'Not reviewed',
'featureTest.featureCase.reviewing': 'In the review',
'featureTest.featureCase.passed': 'Have passed',
'featureTest.featureCase.notPass': 'Not pass',
'featureTest.featureCase.retrial': 'retrial',
'featureTest.featureCase.nonExecution': 'non-execution',
'featureTest.featureCase.failure': 'Failure',
'featureTest.featureCase.chokeUp': 'Choke up',
'featureTest.featureCase.skip': 'skip',
'featureTest.featureCase.batchRecover': 'recover',
'featureTest.featureCase.batchCleanOut': 'Clean out',
'featureTest.featureCase.recoveredSuccessfully': 'Recovered successfully',
'featureTest.featureCase.cleanOutDeleteTip':
'caseManagement.featureCase.deleteCaseTitle': 'Are you sure to delete the {name} use case?',
'caseManagement.featureCase.export': 'Export',
'caseManagement.featureCase.exportExcel': 'Export spreadsheet (xlsx)',
'caseManagement.featureCase.exportXMind': 'Exporting Mind (xmind)',
'caseManagement.featureCase.moveTo': 'Move to',
'caseManagement.featureCase.copyTo': 'Copy to',
'caseManagement.featureCase.associatedDemand': 'Associated demand',
'caseManagement.featureCase.generatingDependencies': 'Generative dependency',
'caseManagement.featureCase.addToPublic': 'Add to public case',
'caseManagement.featureCase.updateCase': 'Update Case',
'caseManagement.featureCase.latestTemplate': 'The default is the latest template',
'caseManagement.featureCase.copyStep': 'Copy Step',
'caseManagement.featureCase.InsertStepsBefore': 'Insert steps before',
'caseManagement.featureCase.afterInsertingSteps': 'After inserting steps',
'caseManagement.featureCase.associatedFile': 'Associated File',
'caseManagement.featureCase.associated': 'Associated',
'caseManagement.featureCase.fileType': 'File Type',
'caseManagement.featureCase.fileName': 'fileName',
'caseManagement.featureCase.description': 'Description',
'caseManagement.featureCase.tags': 'Tags',
'caseManagement.featureCase.enableTags': `On: adds a label`,
'caseManagement.featureCase.closeTags': 'Off: overwrites an existing label',
'caseManagement.featureCase.appendTag': 'appendTag',
'caseManagement.featureCase.batchEdit': 'Batch editing ({number} use cases selected)',
'caseManagement.featureCase.selectAttrs': 'select attributes',
'caseManagement.featureCase.batchUpdate': 'Batch update to',
'caseManagement.featureCase.batchDelete': 'Are you sure to delete the use case {number} ?',
'caseManagement.featureCase.batchMoveTitle': 'Batch Move',
'caseManagement.featureCase.batchMove': '({number} selected use cases)',
'caseManagement.featureCase.batchMoveSelectedModules': 'Batch Move',
'caseManagement.featureCase.batchCopyTitle': 'Batch Copy',
'caseManagement.featureCase.batchCopySelectedModules': 'Batch Copy',
'caseManagement.featureCase.batchCopy': 'Copy Successfully!',
'caseManagement.featureCase.editSuccess': 'update Successfully',
'caseManagement.featureCase.PleaseSelect': 'Please select',
'caseManagement.featureCase.PleaseInputTags': 'Please enter the update tag to add',
'caseManagement.featureCase.expectedResult': 'Expected Result',
'caseManagement.featureCase.remark': 'Remark',
'caseManagement.featureCase.addAttachment': 'Add attachment',
'caseManagement.featureCase.uploadFile': 'Upload File',
'caseManagement.featureCase.storage': 'storage',
'caseManagement.featureCase.download': 'download',
'caseManagement.featureCase.cancelLink': 'Cancel link',
'caseManagement.featureCase.SelectExportRange': 'Select export range',
'caseManagement.featureCase.clear': 'Clear',
'caseManagement.featureCase.baseField': 'Base Field',
'caseManagement.featureCase.customField': 'Custom Field',
'caseManagement.featureCase.otherFields': 'Other Fields',
'caseManagement.featureCase.otherFieldsToolTip': 'Other fields do not support import after export',
'caseManagement.featureCase.notReviewed': 'Not reviewed',
'caseManagement.featureCase.reviewing': 'In the review',
'caseManagement.featureCase.passed': 'Have passed',
'caseManagement.featureCase.notPass': 'Not pass',
'caseManagement.featureCase.retrial': 'retrial',
'caseManagement.featureCase.nonExecution': 'non-execution',
'caseManagement.featureCase.failure': 'Failure',
'caseManagement.featureCase.chokeUp': 'Choke up',
'caseManagement.featureCase.skip': 'skip',
'caseManagement.featureCase.batchRecover': 'recover',
'caseManagement.featureCase.batchCleanOut': 'Clean out',
'caseManagement.featureCase.recoveredSuccessfully': 'Recovered successfully',
'caseManagement.featureCase.cleanOutDeleteTip':
'After deletion, the data will not be recovered, please operate with caution!',
'featureTest.featureCase.pleaseEnterInputTags': 'Please enter content Enter add label',
'featureTest.featureCase.copy': 'Copy',
'featureTest.featureCase.copyCase': 'Copy case',
'featureTest.featureCase.countDownTip': 'Seconds after back in case list, also can manually back in case list',
'featureTest.featureCase.caseDetail': 'Case details',
'featureTest.featureCase.addContinueCreate': 'Continue to create',
'featureTest.featureCase.backCaseList': 'Back',
'featureTest.featureCase.notNextTip': 'Next time no longer remind',
'featureTest.featureCase.mightWantTo': 'You might want to',
'featureTest.featureCase.createTestPlan': 'Create a test plan',
'featureTest.featureCase.createCaseReview': 'Create use case reviews',
'caseManagement.featureCase.pleaseEnterInputTags': 'Please enter content Enter add label',
'caseManagement.featureCase.copy': 'Copy',
'caseManagement.featureCase.copyCase': 'Copy case',
'caseManagement.featureCase.countDownTip': 'Seconds after back in case list, also can manually back in case list',
'caseManagement.featureCase.caseDetail': 'Case details',
'caseManagement.featureCase.addContinueCreate': 'Continue to create',
'caseManagement.featureCase.backCaseList': 'Back',
'caseManagement.featureCase.notNextTip': 'Next time no longer remind',
'caseManagement.featureCase.mightWantTo': 'You might want to',
'caseManagement.featureCase.createTestPlan': 'Create a test plan',
'caseManagement.featureCase.createCaseReview': 'Create use case reviews',
};

View File

@ -1,120 +1,120 @@
export default {
'featureTest.featureCase.creatingCase': '创建用例',
'featureTest.featureCase.importCase': '导入用例',
'featureTest.featureCase.importExcel': 'Excel导入',
'featureTest.featureCase.importXmind': 'Xmind导入',
'featureTest.featureCase.publicCase': '公共用例库',
'featureTest.featureCase.allCase': '全部用例',
'featureTest.featureCase.searchTip': '请输入分组名称',
'featureTest.featureCase.caseEmptyContent': '暂无用例数据,请点击上方按钮创建或导入',
'featureTest.featureCase.caseEmptyRecycle': '暂无用例数据',
'featureTest.featureCase.addSubModule': '添加子模块',
'featureTest.featureCase.rename': '重命名',
'featureTest.featureCase.recycle': '回收站',
'featureTest.featureCase.versionPlaceholder': '默认为最新版本',
'featureTest.featureCase.searchByNameAndId': '通过 ID 或名称搜索',
'featureTest.featureCase.filter': '筛选',
'featureTest.featureCase.setFilterCondition': '设置筛选条件',
'featureTest.featureCase.followingCondition': '符合以下',
'featureTest.featureCase.condition': '条件',
'featureTest.featureCase.delete': '删除',
'featureTest.featureCase.addSubModuleSuccess': '添加子模块成功',
'featureTest.featureCase.renameSuccess': '重命名成功',
'featureTest.featureCase.nameNotNullTip': '名称不能为空',
'featureTest.featureCase.deleteTipTitle': '是否删除 {name} 用例 ',
'featureTest.featureCase.deleteCaseTipContent': '删除后,此节点下的所有资源都会被删除,请谨慎操作。',
'featureTest.featureCase.deleteConfirm': '确认删除',
'featureTest.featureCase.deleteSuccess': '删除成功',
'featureTest.featureCase.addSuccess': '添加成功',
'featureTest.featureCase.addGroupTip': '请输入分组名称,按回车键保存',
'featureTest.featureCase.moduleMoveSuccess': '移动成功',
'featureTest.featureCase.tableColumnID': 'ID',
'featureTest.featureCase.tableColumnName': '用例名称',
'featureTest.featureCase.tableColumnLevel': '用例等级',
'featureTest.featureCase.tableColumnCaseState': '用例状态',
'featureTest.featureCase.tableColumnReviewResult': '评审结果',
'featureTest.featureCase.tableColumnExecutionResult': '执行结果',
'featureTest.featureCase.tableColumnVersion': '版本',
'featureTest.featureCase.tableColumnModule': '所属模块',
'featureTest.featureCase.tableColumnTag': '标签',
'featureTest.featureCase.tableColumnCreateUser': '创建人',
'featureTest.featureCase.tableColumnCreateTime': '创建时间',
'featureTest.featureCase.tableColumnUpdateUser': '更新人',
'featureTest.featureCase.tableColumnUpdateTime': '更新时间',
'featureTest.featureCase.tableColumnActions': '操作',
'featureTest.featureCase.beforeDeleteCase': '删除后的内容将放入回收站,可在回收站内进行恢复数据',
'featureTest.featureCase.deleteCaseTitle': '确认删除 {name} 用例 ',
'featureTest.featureCase.export': '导出',
'featureTest.featureCase.exportExcel': '导出 Excel 表格 (xlsx)',
'featureTest.featureCase.exportXMind': '导出思维导图 (xmind)',
'featureTest.featureCase.moveTo': '移动到',
'featureTest.featureCase.copyTo': '复制到',
'featureTest.featureCase.associatedDemand': '关联需求',
'featureTest.featureCase.generatingDependencies': '生成依赖关系',
'featureTest.featureCase.addToPublic': '添加到公共用例库',
'featureTest.featureCase.updateCase': '更新用例',
'featureTest.featureCase.latestTemplate': '默认为最新模版',
'featureTest.featureCase.copyStep': '复制该步骤',
'featureTest.featureCase.InsertStepsBefore': '在之前插入步骤',
'featureTest.featureCase.afterInsertingSteps': '在之后插入步骤',
'featureTest.featureCase.associatedFile': '关联文件',
'featureTest.featureCase.associated': '关联',
'featureTest.featureCase.fileType': '文件类型',
'featureTest.featureCase.fileName': '文件名',
'featureTest.featureCase.description': '描述',
'featureTest.featureCase.tags': '标签',
'featureTest.featureCase.enableTags': `开启:新增标签,关闭:覆盖原有标签`,
'featureTest.featureCase.closeTags': '关闭:覆盖原有标签',
'featureTest.featureCase.appendTag': '追加标签',
'featureTest.featureCase.batchEdit': '批量编辑 (已选 { number } 条用例)',
'featureTest.featureCase.selectAttrs': '选择属性',
'featureTest.featureCase.batchUpdate': '批量更新为',
'featureTest.featureCase.batchDelete': '确认删除 {number} 条用例吗?',
'featureTest.featureCase.batchMoveTitle': '批量移动',
'featureTest.featureCase.batchMove': '(已选 { number } 条用例)',
'featureTest.featureCase.batchMoveSelectedModules': '移动 { number } 个用例至已选模块',
'featureTest.featureCase.batchCopyTitle': '批量复制',
'featureTest.featureCase.batchCopySelectedModules': '复制 { number } 个用例至已选模块',
'featureTest.featureCase.batchCopySuccess': '复制成功',
'featureTest.featureCase.batchMoveSuccess': '移动成功',
'featureTest.featureCase.editSuccess': '更新成功',
'featureTest.featureCase.PleaseSelect': '请选择',
'featureTest.featureCase.PleaseInputTags': '请输入更新标签回车添加',
'featureTest.featureCase.expectedResult': '预期结果',
'featureTest.featureCase.remark': '备注',
'featureTest.featureCase.addAttachment': '添加附件',
'featureTest.featureCase.uploadFile': '上传文件',
'featureTest.featureCase.storage': '转存',
'featureTest.featureCase.download': '下载',
'featureTest.featureCase.cancelLink': '取消关联',
'featureTest.featureCase.SelectExportRange': '选择导出范围',
'featureTest.featureCase.clear': '清空',
'featureTest.featureCase.baseField': '基础字段',
'featureTest.featureCase.customField': '自定义字段',
'featureTest.featureCase.otherFields': '其他字段',
'featureTest.featureCase.otherFieldsToolTip': '其他字段 导出后不支持导入',
'featureTest.featureCase.notReviewed': '未评审',
'featureTest.featureCase.reviewing': '评审中',
'featureTest.featureCase.passed': '已通过',
'featureTest.featureCase.notPass': '未通过',
'featureTest.featureCase.retrial': '重新提审',
'featureTest.featureCase.nonExecution': '未执行',
'featureTest.featureCase.failure': '失败',
'featureTest.featureCase.chokeUp': '阻塞',
'featureTest.featureCase.skip': '跳过',
'featureTest.featureCase.batchRecover': '恢复',
'featureTest.featureCase.batchCleanOut': '彻底删除',
'featureTest.featureCase.recoveredSuccessfully': '恢复成功',
'featureTest.featureCase.cleanOutDeleteTip': '删除后,数据将无法恢复,请谨慎操作!',
'featureTest.featureCase.pleaseEnterInputTags': '请输入内容回车添加标签',
'featureTest.featureCase.copy': '复制',
'featureTest.featureCase.copyCase': '复制用例',
'featureTest.featureCase.countDownTip': '秒后回到用例列表,也可以手动回到用例列表',
'featureTest.featureCase.caseDetail': '用例详情',
'featureTest.featureCase.addContinueCreate': '继续创建',
'featureTest.featureCase.backCaseList': '回到用例列表',
'featureTest.featureCase.notNextTip': '下次不再提醒',
'featureTest.featureCase.mightWantTo': '你可能还想',
'featureTest.featureCase.createTestPlan': '创建测试计划',
'featureTest.featureCase.createCaseReview': '创建用例评审',
'caseManagement.featureCase.creatingCase': '创建用例',
'caseManagement.featureCase.importCase': '导入用例',
'caseManagement.featureCase.importExcel': 'Excel导入',
'caseManagement.featureCase.importXmind': 'Xmind导入',
'caseManagement.featureCase.publicCase': '公共用例库',
'caseManagement.featureCase.allCase': '全部用例',
'caseManagement.featureCase.searchTip': '请输入分组名称',
'caseManagement.featureCase.caseEmptyContent': '暂无用例数据,请点击上方按钮创建或导入',
'caseManagement.featureCase.caseEmptyRecycle': '暂无用例数据',
'caseManagement.featureCase.addSubModule': '添加子模块',
'caseManagement.featureCase.rename': '重命名',
'caseManagement.featureCase.recycle': '回收站',
'caseManagement.featureCase.versionPlaceholder': '默认为最新版本',
'caseManagement.featureCase.searchByNameAndId': '通过 ID 或名称搜索',
'caseManagement.featureCase.filter': '筛选',
'caseManagement.featureCase.setFilterCondition': '设置筛选条件',
'caseManagement.featureCase.followingCondition': '符合以下',
'caseManagement.featureCase.condition': '条件',
'caseManagement.featureCase.delete': '删除',
'caseManagement.featureCase.addSubModuleSuccess': '添加子模块成功',
'caseManagement.featureCase.renameSuccess': '重命名成功',
'caseManagement.featureCase.nameNotNullTip': '名称不能为空',
'caseManagement.featureCase.deleteTipTitle': '是否删除 {name} 用例 ',
'caseManagement.featureCase.deleteCaseTipContent': '删除后,此节点下的所有资源都会被删除,请谨慎操作。',
'caseManagement.featureCase.deleteConfirm': '确认删除',
'caseManagement.featureCase.deleteSuccess': '删除成功',
'caseManagement.featureCase.addSuccess': '添加成功',
'caseManagement.featureCase.addGroupTip': '请输入分组名称,按回车键保存',
'caseManagement.featureCase.moduleMoveSuccess': '移动成功',
'caseManagement.featureCase.tableColumnID': 'ID',
'caseManagement.featureCase.tableColumnName': '用例名称',
'caseManagement.featureCase.tableColumnLevel': '用例等级',
'caseManagement.featureCase.tableColumnCaseState': '用例状态',
'caseManagement.featureCase.tableColumnReviewResult': '评审结果',
'caseManagement.featureCase.tableColumnExecutionResult': '执行结果',
'caseManagement.featureCase.tableColumnVersion': '版本',
'caseManagement.featureCase.tableColumnModule': '所属模块',
'caseManagement.featureCase.tableColumnTag': '标签',
'caseManagement.featureCase.tableColumnCreateUser': '创建人',
'caseManagement.featureCase.tableColumnCreateTime': '创建时间',
'caseManagement.featureCase.tableColumnUpdateUser': '更新人',
'caseManagement.featureCase.tableColumnUpdateTime': '更新时间',
'caseManagement.featureCase.tableColumnActions': '操作',
'caseManagement.featureCase.beforeDeleteCase': '删除后的内容将放入回收站,可在回收站内进行恢复数据',
'caseManagement.featureCase.deleteCaseTitle': '确认删除 {name} 用例 ',
'caseManagement.featureCase.export': '导出',
'caseManagement.featureCase.exportExcel': '导出 Excel 表格 (xlsx)',
'caseManagement.featureCase.exportXMind': '导出思维导图 (xmind)',
'caseManagement.featureCase.moveTo': '移动到',
'caseManagement.featureCase.copyTo': '复制到',
'caseManagement.featureCase.associatedDemand': '关联需求',
'caseManagement.featureCase.generatingDependencies': '生成依赖关系',
'caseManagement.featureCase.addToPublic': '添加到公共用例库',
'caseManagement.featureCase.updateCase': '更新用例',
'caseManagement.featureCase.latestTemplate': '默认为最新模版',
'caseManagement.featureCase.copyStep': '复制该步骤',
'caseManagement.featureCase.InsertStepsBefore': '在之前插入步骤',
'caseManagement.featureCase.afterInsertingSteps': '在之后插入步骤',
'caseManagement.featureCase.associatedFile': '关联文件',
'caseManagement.featureCase.associated': '关联',
'caseManagement.featureCase.fileType': '文件类型',
'caseManagement.featureCase.fileName': '文件名',
'caseManagement.featureCase.description': '描述',
'caseManagement.featureCase.tags': '标签',
'caseManagement.featureCase.enableTags': `开启:新增标签,关闭:覆盖原有标签`,
'caseManagement.featureCase.closeTags': '关闭:覆盖原有标签',
'caseManagement.featureCase.appendTag': '追加标签',
'caseManagement.featureCase.batchEdit': '批量编辑 (已选 { number } 条用例)',
'caseManagement.featureCase.selectAttrs': '选择属性',
'caseManagement.featureCase.batchUpdate': '批量更新为',
'caseManagement.featureCase.batchDelete': '确认删除 {number} 条用例吗?',
'caseManagement.featureCase.batchMoveTitle': '批量移动',
'caseManagement.featureCase.batchMove': '(已选 { number } 条用例)',
'caseManagement.featureCase.batchMoveSelectedModules': '移动 { number } 个用例至已选模块',
'caseManagement.featureCase.batchCopyTitle': '批量复制',
'caseManagement.featureCase.batchCopySelectedModules': '复制 { number } 个用例至已选模块',
'caseManagement.featureCase.batchCopySuccess': '复制成功',
'caseManagement.featureCase.batchMoveSuccess': '移动成功',
'caseManagement.featureCase.editSuccess': '更新成功',
'caseManagement.featureCase.PleaseSelect': '请选择',
'caseManagement.featureCase.PleaseInputTags': '请输入更新标签回车添加',
'caseManagement.featureCase.expectedResult': '预期结果',
'caseManagement.featureCase.remark': '备注',
'caseManagement.featureCase.addAttachment': '添加附件',
'caseManagement.featureCase.uploadFile': '上传文件',
'caseManagement.featureCase.storage': '转存',
'caseManagement.featureCase.download': '下载',
'caseManagement.featureCase.cancelLink': '取消关联',
'caseManagement.featureCase.SelectExportRange': '选择导出范围',
'caseManagement.featureCase.clear': '清空',
'caseManagement.featureCase.baseField': '基础字段',
'caseManagement.featureCase.customField': '自定义字段',
'caseManagement.featureCase.otherFields': '其他字段',
'caseManagement.featureCase.otherFieldsToolTip': '其他字段 导出后不支持导入',
'caseManagement.featureCase.notReviewed': '未评审',
'caseManagement.featureCase.reviewing': '评审中',
'caseManagement.featureCase.passed': '已通过',
'caseManagement.featureCase.notPass': '未通过',
'caseManagement.featureCase.retrial': '重新提审',
'caseManagement.featureCase.nonExecution': '未执行',
'caseManagement.featureCase.failure': '失败',
'caseManagement.featureCase.chokeUp': '阻塞',
'caseManagement.featureCase.skip': '跳过',
'caseManagement.featureCase.batchRecover': '恢复',
'caseManagement.featureCase.batchCleanOut': '彻底删除',
'caseManagement.featureCase.recoveredSuccessfully': '恢复成功',
'caseManagement.featureCase.cleanOutDeleteTip': '删除后,数据将无法恢复,请谨慎操作!',
'caseManagement.featureCase.pleaseEnterInputTags': '请输入内容回车添加标签',
'caseManagement.featureCase.copy': '复制',
'caseManagement.featureCase.copyCase': '复制用例',
'caseManagement.featureCase.countDownTip': '秒后回到用例列表,也可以手动回到用例列表',
'caseManagement.featureCase.caseDetail': '用例详情',
'caseManagement.featureCase.addContinueCreate': '继续创建',
'caseManagement.featureCase.backCaseList': '回到用例列表',
'caseManagement.featureCase.notNextTip': '下次不再提醒',
'caseManagement.featureCase.mightWantTo': '你可能还想',
'caseManagement.featureCase.createTestPlan': '创建测试计划',
'caseManagement.featureCase.createCaseReview': '创建用例评审',
};

View File

@ -0,0 +1,472 @@
<template>
<MsCard :min-width="1100" has-breadcrumb hide-footer no-content-padding hide-divider>
<template #headerLeft>
<a-tooltip :content="reviewName">
<div class="one-line-text mr-[8px] max-w-[260px] font-medium text-[var(--color-text-000)]">
{{ reviewName }}
</div>
</a-tooltip>
<div
class="rounded-[0_999px_999px_0] border border-solid border-[text-[rgb(var(--primary-5))]] px-[8px] py-[2px] text-[12px] leading-[16px] text-[rgb(var(--primary-5))]"
>
<MsIcon type="icon-icon-contacts" size="13" />
{{ t('caseManagement.caseReview.single') }}
</div>
<div class="ml-[16px] flex items-center">
<a-switch v-model:model-value="onlyMine" size="small" class="mr-[8px]" />
{{ t('caseManagement.caseReview.myReview') }}
</div>
</template>
<div class="h-full px-[24px]">
<a-divider class="my-0" />
<div class="flex h-[calc(100%-1px)]">
<div class="h-full w-[356px] border-r border-[var(--color-text-n8)] pr-[16px] pt-[16px]">
<div class="mb-[16px] flex">
<a-input
v-model:model-value="keyword"
:placeholder="t('caseManagement.caseReview.searchPlaceholder')"
allow-clear
class="mr-[8px] w-[240px]"
/>
<a-select v-model:model-value="type" :options="typeOptions" class="w-[92px]"></a-select>
</div>
<div class="case-list">
<div
v-for="item of caseList"
:key="item.id"
:class="['case-item', activeCase.id === item.id ? 'case-item--active' : '']"
@click="changeActiveCase(item)"
>
<div class="mb-[4px] flex items-center justify-between">
<div>{{ item.id }}</div>
<div class="flex items-center gap-[4px]">
<MsIcon
:type="resultMap[item.result as ResultMap].icon"
:style="{color: resultMap[item.result as ResultMap].color}"
/>
{{ t(resultMap[item.result as ResultMap].label) }}
</div>
</div>
<a-tooltip :content="item.name">
<div class="one-line-text">{{ item.name }}</div>
</a-tooltip>
</div>
</div>
<MsPagination :total="total" :page-size="pageSize" :current="pageCurrent" size="mini" simple />
</div>
<div class="relative flex flex-1 flex-col">
<div class="pl-[16px] pt-[16px]">
<div class="rounded-[var(--border-radius-small)] bg-[var(--color-text-n9)] p-[16px]">
<div class="mb-[12px] flex items-center justify-between">
<a-tooltip :content="activeCase.module">
<div class="one-line-text cursor-pointer font-medium text-[rgb(var(--primary-5))]">
{{ activeCase.id }}{{ activeCase.name }}
</div>
</a-tooltip>
<a-button type="outline" size="mini" class="arco-btn-outline--secondary">
{{ t('common.edit') }}
</a-button>
</div>
<div class="flex items-center">
<MsIcon type="icon-icon_folder_filled1" class="mr-[4px] text-[var(--color-text-4)]" />
<a-tooltip :content="activeCase.module">
<div class="one-line-text mr-[8px] max-w-[260px] font-medium text-[var(--color-text-000)]">
{{ activeCase.module }}
</div>
</a-tooltip>
<div class="case-detail-label">
{{ t('caseManagement.caseReview.caseLevel') }}
</div>
<div class="case-detail-value">
<caseLevel :case-level="activeCase.level" />
</div>
<div class="case-detail-label">
{{ t('caseManagement.caseReview.caseVersion') }}
</div>
<div class="case-detail-value">
<MsIcon type="icon-icon_version" size="13" class="mr-[4px]" />
{{ activeCase.version }}
</div>
<div class="case-detail-label">
{{ t('caseManagement.caseReview.reviewResult') }}
</div>
<div class="case-detail-value">
<div class="flex items-center gap-[4px]">
<MsIcon
:type="resultMap[activeCase.result].icon"
:style="{
color: resultMap[activeCase.result].color,
}"
/>
{{ t(resultMap[activeCase.result].label) }}
</div>
</div>
</div>
</div>
<a-tabs v-model:active-key="showTab" class="no-content">
<a-tab-pane v-for="item of tabList" :key="item.key" :title="item.title" />
</a-tabs>
</div>
<a-divider class="my-0" />
<div class="content-center">
<MsDescription v-if="showTab === 'baseInfo'" :descriptions="descriptions" label-width="90px" />
<div v-if="showTab === 'detail'" class="h-full">
<MsSplitBox :size="0.8" direction="vertical" min="0" :max="0.99">
<template #top>
<div> toptop </div>
</template>
<template #bottom>
<div class="flex h-full flex-col overflow-hidden">
<div class="mb-[8px] font-medium text-[var(--color-text-1)]">
{{ t('caseManagement.caseReview.reviewHistory') }}
</div>
<div class="review-history-list">
<div v-for="item of reviewHistoryList" :key="item.id" class="mb-[16px]">
<div class="flex items-center">
<a-avatar>A</a-avatar>
<div class="ml-[8px] flex items-center">
<div class="font-medium text-[var(--color-text-1)]">{{ item.reviewer }}</div>
<a-divider direction="vertical" margin="8px"></a-divider>
<div v-if="item.result === 1" class="flex items-center">
<MsIcon type="icon-icon_succeed_filled" class="mr-[4px] text-[rgb(var(--success-6))]" />
{{ t('caseManagement.caseReview.pass') }}
</div>
<div v-else-if="item.result === 2" class="flex items-center">
<MsIcon type="icon-icon_close_filled" class="mr-[4px] text-[rgb(var(--danger-6))]" />
{{ t('caseManagement.caseReview.fail') }}
</div>
<div v-else-if="item.result === 3" class="flex items-center">
<MsIcon type="icon-icon_warning_filled" class="mr-[4px] text-[rgb(var(--warning-6))]" />
{{ t('caseManagement.caseReview.suggestion') }}
</div>
<div v-else-if="item.result === 4" class="flex items-center">
<MsIcon type="icon-icon_resubmit_filled" class="mr-[4px] text-[rgb(var(--warning-6))]" />
{{ t('caseManagement.caseReview.reReview') }}
</div>
</div>
</div>
<div class="ml-[48px] text-[var(--color-text-2)]">{{ item.reason }}</div>
<div class="ml-[48px] mt-[8px] text-[var(--color-text-4)]">{{ item.time }}</div>
</div>
</div>
</div>
</template>
</MsSplitBox>
</div>
</div>
<div class="content-footer">
<div class="mb-[16px] flex items-center">
<div class="font-medium text-[var(--color-text-1)]">
{{ t('caseManagement.caseReview.startReview') }}
</div>
<a-switch v-model:model-value="autoNext" class="mx-[8px]" size="small" />
<div class="text-[var(--color-text-4)]">{{ t('caseManagement.caseReview.autoNext') }}</div>
<a-tooltip position="right">
<template #content>
<div>{{ t('caseManagement.caseReview.autoNextTip1') }}</div>
<div>{{ t('caseManagement.caseReview.autoNextTip2') }}</div>
</template>
<icon-question-circle
class="mb-[2px] ml-[4px] text-[var(--color-text-4)] hover:text-[rgb(var(--primary-5))]"
size="16"
/>
</a-tooltip>
</div>
<a-form ref="dialogFormRef" :model="caseResultForm" layout="vertical">
<a-form-item field="reason" :label="t('caseManagement.caseReview.reviewResult')" class="mb-[8px]">
<a-radio-group v-model:model-value="caseResultForm.result" @change="() => dialogFormRef?.resetFields()">
<a-radio value="pass">
<div class="inline-flex items-center">
<MsIcon type="icon-icon_succeed_filled" class="mr-[4px] text-[rgb(var(--success-6))]" />
{{ t('caseManagement.caseReview.pass') }}
</div>
</a-radio>
<a-radio value="fail">
<div class="inline-flex items-center">
<MsIcon type="icon-icon_close_filled" class="mr-[4px] text-[rgb(var(--danger-6))]" />
{{ t('caseManagement.caseReview.fail') }}
</div>
</a-radio>
<a-radio value="suggestion">
<div class="inline-flex items-center">
<MsIcon type="icon-icon_warning_filled" class="mr-[4px] text-[rgb(var(--warning-6))]" />
{{ t('caseManagement.caseReview.suggestion') }}
</div>
<a-tooltip :content="t('caseManagement.caseReview.suggestionTip')" position="right">
<icon-question-circle
class="ml-[4px] mt-[2px] text-[var(--color-text-4)] hover:text-[rgb(var(--primary-5))]"
size="16"
/>
</a-tooltip>
</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item
field="reason"
:label="t('caseManagement.caseReview.reason')"
:rules="
caseResultForm.result === 'fail'
? [{ required: true, message: t('caseManagement.caseReview.reasonRequired') }]
: []
"
asterisk-position="end"
class="mb-0"
>
<a-input
v-model:model-value="caseResultForm.reason"
:placeholder="t('caseManagement.caseReview.reasonPlaceholder')"
/>
</a-form-item>
</a-form>
<a-button type="primary" class="mt-[16px]">
{{ t('caseManagement.caseReview.submitReview') }}
</a-button>
</div>
</div>
</div>
</div>
</MsCard>
</template>
<script setup lang="ts">
import { FormInstance } from '@arco-design/web-vue';
import dayjs from 'dayjs';
import MsCard from '@/components/pure/ms-card/index.vue';
import MsDescription from '@/components/pure/ms-description/index.vue';
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
import MsPagination from '@/components/pure/ms-pagination/index';
import MsSplitBox from '@/components/pure/ms-split-box/index.vue';
import caseLevel from '@/components/business/ms-case-associate/caseLevel.vue';
import type { CaseLevel } from '@/components/business/ms-case-associate/types';
import { useI18n } from '@/hooks/useI18n';
const { t } = useI18n();
const reviewName = ref('打算肯定还是觉得还是觉得还是计划的');
const caseDetail = ref({});
const onlyMine = ref(false);
const keyword = ref('');
type ResultMap = 0 | 1 | 2 | 3;
const resultMap = {
0: {
label: t('caseManagement.caseReview.unReview'),
color: 'var(--color-text-input-border)',
icon: 'icon-icon_block_filled',
},
1: {
label: t('caseManagement.caseReview.reviewPass'),
color: 'rgb(var(--success-6))',
icon: 'icon-icon_succeed_filled',
},
2: {
label: t('caseManagement.caseReview.fail'),
color: 'rgb(var(--danger-6))',
icon: 'icon-icon_close_filled',
},
3: {
label: t('caseManagement.caseReview.reReview'),
color: 'rgb(var(--warning-6))',
icon: 'icon-icon_resubmit_filled',
},
} as const;
const type = ref('');
const typeOptions = ref([
{ label: '全部', value: '' },
{ label: resultMap[0].label, value: 'unReview' },
{ label: resultMap[1].label, value: 'reviewPass' },
{ label: resultMap[2].label, value: 'fail' },
{ label: resultMap[3].label, value: 'reReview' },
]);
const caseList = ref([
{
id: 'g4ggtrgrtg',
name: '打算肯定还是觉得还是觉得还是计划的',
module: '模块名称模块名称模块名称模块名称模块名称模块名称模块名称模块名称模块名称',
level: 0 as CaseLevel,
result: 0 as ResultMap,
version: '1.0.0',
},
{
id: 2,
name: '打算肯定还是觉得还是觉得还是计划的',
result: 1,
module: '模块名称模块名称模块名称模块名称模块名称模块名称模块名称模块名称模块名称',
level: 0 as CaseLevel,
version: '1.0.0',
},
{
id: 3,
name: '打算肯定还是觉得还是觉得还是计划的',
result: 2,
module: '模块名称模块名称模块名称模块名称模块名称模块名称模块名称模块名称模块名称',
level: 0 as CaseLevel,
version: '1.0.0',
},
{
id: 4,
name: '打算肯定还是觉得还是觉得还是计划的',
result: 3,
module: '模块名称模块名称模块名称模块名称模块名称模块名称模块名称模块名称模块名称',
level: 0 as CaseLevel,
version: '1.0.0',
},
]);
const total = ref(10);
const pageSize = ref(10);
const pageCurrent = ref(1);
const activeCase = ref({
id: 'g4ggtrgrtg',
name: '打算肯定还是觉得还是觉得还是计划的打撒打扫打扫',
module: '模块名称模块名称模块名称模块名称模块名称模块名称模块名称模块名称模块名称',
level: 0 as CaseLevel,
result: 0 as ResultMap,
version: '1.0.0',
});
function changeActiveCase(item: any) {
if (activeCase.value.id !== item.id) {
activeCase.value = item;
}
}
const showTab = ref('detail');
const tabList = ref([
{
key: 'baseInfo',
title: t('caseManagement.caseReview.caseBaseInfo'),
},
{
key: 'detail',
title: t('caseManagement.caseReview.caseDetail'),
},
{
key: 'demand',
title: t('caseManagement.caseReview.caseDemand'),
},
]);
const descriptions = ref([
{
label: t('caseManagement.caseReview.belongModule'),
value: '模块模块',
},
{
label: t('caseManagement.caseReview.caseStatus'),
value: '未开始',
},
{
label: t('caseManagement.caseReview.responsiblePerson'),
value: '张三',
},
{
label: t('caseManagement.caseReview.creator'),
value: '李四',
},
{
label: t('caseManagement.caseReview.createTime'),
value: dayjs().format('YYYY-MM-DD HH:mm:ss'),
},
]);
const reviewHistoryList = ref([
{
id: 1,
reviewer: '张三',
avatar: '',
result: 1,
reason: '',
time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
},
{
id: 2,
reviewer: '李四',
avatar: '',
result: 2,
reason: '不通过',
time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
},
{
id: 3,
reviewer: '王五',
avatar: '',
result: 3,
reason: '建议修改',
time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
},
{
id: 4,
reviewer: '李六',
avatar: '',
result: 4,
reason: '重新提',
time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
},
]);
const autoNext = ref(false);
const caseResultForm = ref({
result: 'pass',
reason: '',
});
const dialogFormRef = ref<FormInstance>();
</script>
<style lang="less" scoped>
.case-list {
.ms-scroll-bar();
margin-bottom: 16px;
padding: 16px;
border-radius: var(--border-radius-small);
background: var(--color-text-n9);
.case-item {
@apply cursor-pointer;
margin-bottom: 8px;
padding: 16px;
border-radius: var(--border-radius-small);
background-color: white;
}
.case-item--active {
@apply relative;
background-color: rgb(var(--primary-1));
box-shadow: inset 0 0 0.5px 0.5px rgb(var(--primary-5));
}
}
.case-detail-label {
margin-right: 8px;
color: var(--color-text-4);
}
.case-detail-value {
@apply flex items-center;
margin-right: 16px;
}
:deep(.arco-tabs-content) {
@apply hidden;
}
.content-center {
@apply flex-1 overflow-auto;
.ms-scroll-bar();
padding: 16px 0 16px 16px;
.review-history-list {
@apply overflow-auto;
.ms-scroll-bar();
padding: 16px 0 16px 16px;
}
}
.content-footer {
padding: 16px;
width: calc(100% + 32px);
box-shadow: 0 -1px 4px 0 rgb(31 35 41 / 10%);
:deep(.arco-radio-label) {
@apply inline-flex;
}
}
</style>

View File

@ -0,0 +1,148 @@
<template>
<MsCaseAssociate
v-model:visible="innerVisible"
v-model:project="innerProject"
:ok-button-disabled="associateForm.reviewers.length === 0"
@success="writeAssociateCases"
@close="emit('close')"
>
<template #footerLeft>
<a-form ref="associateFormRef" :model="associateForm">
<a-form-item
field="reviewers"
:rules="[{ required: true, message: t('caseManagement.caseReview.reviewerRequired') }]"
class="mb-0"
>
<template #label>
<div class="inline-flex items-center">
{{ t('caseManagement.caseReview.reviewer') }}
<a-tooltip position="right">
<template #content>
<div>{{ t('caseManagement.caseReview.switchProject') }}</div>
<div>{{ t('caseManagement.caseReview.resetReviews') }}</div>
<div>
{{ t('caseManagement.caseReview.reviewsTip') }}
<span class="cursor-pointer text-[rgb(var(--primary-4))]" @click="goProjectManagement">
{{ t('menu.projectManagement') }}
</span>
{{ t('caseManagement.caseReview.reviewsTip2') }}
</div>
</template>
<icon-question-circle
class="ml-[4px] text-[var(--color-text-4)] hover:text-[rgb(var(--primary-5))]"
size="16"
/>
</a-tooltip>
</div>
</template>
<MsSelect
v-model:modelValue="associateForm.reviewers"
mode="static"
:placeholder="t('caseManagement.caseReview.reviewerPlaceholder')"
:options="reviewersOptions"
:search-keys="['label']"
allow-search
allow-clear
multiple
class="w-[300px]"
>
</MsSelect>
</a-form-item>
</a-form>
</template>
</MsCaseAssociate>
</template>
<script setup lang="ts">
import { useRouter } from 'vue-router';
import { FormInstance } from '@arco-design/web-vue';
import MsCaseAssociate from '@/components/business/ms-case-associate/index.vue';
import MsSelect from '@/components/business/ms-select';
import { useI18n } from '@/hooks/useI18n';
import { ProjectManagementRouteEnum } from '@/enums/routeEnum';
const props = defineProps<{
visible: boolean;
project: string;
}>();
const emit = defineEmits<{
(e: 'update:visible', val: boolean): void;
(e: 'update:project', val: string): void;
(e: 'success', val: string[]): void;
(e: 'close'): void;
}>();
const router = useRouter();
const { t } = useI18n();
const innerVisible = ref(false);
watch(
() => props.visible,
(val) => {
innerVisible.value = val;
}
);
watch(
() => innerVisible.value,
(val) => {
if (!val) {
emit('update:visible', false);
}
}
);
const innerProject = ref('');
watch(
() => props.project,
(val) => {
innerProject.value = val;
}
);
watch(
() => innerProject.value,
(val) => {
emit('update:project', val);
}
);
const associateForm = ref({
reviewers: [],
});
const associateFormRef = ref<FormInstance>();
function goProjectManagement() {
window.open(
`${window.location.origin}#${
router.resolve({ name: ProjectManagementRouteEnum.PROJECT_MANAGEMENT_PERMISSION_USER_GROUP }).fullPath
}`
);
}
const reviewersOptions = ref([
{
label: '张三',
value: '1',
},
{
label: '李四',
value: '2',
},
{
label: '王五',
value: '3',
},
]);
function writeAssociateCases(ids: string[]) {
emit('success', ids);
}
</script>
<style lang="less" scoped></style>

View File

@ -0,0 +1,639 @@
<template>
<div class="px-[24px] py-[16px]">
<div class="mb-[16px] flex items-center justify-between">
<div class="flex items-center">
<a-button type="primary" class="mr-[12px]" @click="associateDrawerVisible = true">
{{ t('ms.case.associate.title') }}
</a-button>
<a-button type="outline" @click="createCase">{{ t('caseManagement.caseReview.createCase') }}</a-button>
</div>
<div class="flex w-[70%] items-center justify-end gap-[8px]">
<a-input-search
v-model="keyword"
:placeholder="t('caseManagement.caseReview.searchPlaceholder')"
allow-clear
class="w-[200px]"
@press-enter="searchReview"
@search="searchReview"
/>
<a-button type="outline" class="arco-btn-outline--secondary px-[8px]">
<MsIcon type="icon-icon-filter" class="mr-[4px] text-[var(--color-text-4)]" />
<div class="text-[var(--color-text-4)]">{{ t('common.filter') }}</div>
</a-button>
<a-radio-group v-model:model-value="showType" type="button" class="case-show-type">
<a-radio value="list" class="show-type-icon p-[2px]"><MsIcon type="icon-icon_view-list_outlined" /></a-radio>
<a-radio value="mind" class="show-type-icon p-[2px]"><MsIcon type="icon-icon_mindnote_outlined" /></a-radio>
</a-radio-group>
<a-button type="outline" class="arco-btn-outline--secondary p-[10px]">
<icon-refresh class="text-[var(--color-text-4)]" />
</a-button>
</div>
</div>
<ms-base-table
v-bind="propsRes"
:action-config="batchActions"
no-disable
filter-icon-align-left
v-on="propsEvent"
@selected-change="handleTableSelect"
@batch-action="handleTableBatch"
>
<template #resultColumn>
<div class="flex items-center text-[var(--color-text-3)]">
{{ t('caseManagement.caseReview.reviewResult') }}
<a-tooltip :content="t('caseManagement.caseReview.reviewResultTip')" position="right">
<icon-question-circle
class="ml-[4px] text-[var(--color-text-4)] hover:text-[rgb(var(--primary-5))]"
size="16"
/>
</a-tooltip>
</div>
</template>
<template #name="{ record }">
<a-tooltip :content="record.name">
<a-button type="text" class="px-0" @click="openDetail(record.id)">
<div class="one-line-text max-w-[168px]">{{ record.name }}</div>
</a-button>
</a-tooltip>
</template>
<template #result="{ record }">
<div class="flex items-center gap-[4px]">
<MsIcon
:type="resultMap[record.result as ResultMap].icon"
:style="{
color: resultMap[record.result as ResultMap].color
}"
/>
{{ t(resultMap[record.result as ResultMap].label) }}
</div>
</template>
<template #action="{ record }">
<MsButton type="text" class="!mr-0" @click="review(record)">
{{ t('caseManagement.caseReview.review') }}
</MsButton>
<a-divider direction="vertical" :margin="8"></a-divider>
<MsPopconfirm
:title="t('caseManagement.caseReview.disassociateTip')"
:sub-title-tip="t('caseManagement.caseReview.disassociateTipContent')"
:ok-text="t('common.confirm')"
type="error"
>
<MsButton type="text" class="!mr-0">
{{ t('caseManagement.caseReview.disassociate') }}
</MsButton>
</MsPopconfirm>
</template>
<template v-if="keyword.trim() === ''" #empty>
<div class="flex items-center justify-center p-[8px] text-[var(--color-text-4)]">
{{ t('caseManagement.caseReview.tableNoData') }}
<MsButton class="ml-[8px]" @click="handleAddClick">
{{ t('caseManagement.caseReview.create') }}
</MsButton>
</div>
</template>
</ms-base-table>
<a-modal
v-model:visible="dialogVisible"
:on-before-ok="handleDeleteConfirm"
class="p-[4px]"
title-align="start"
body-class="p-0"
:mask-closable="false"
@close="handleDialogCancel"
>
<template #title>
<div class="flex items-center justify-start">
<div class="text-[var(--color-text-1)]">
{{ dialogTitle }}
</div>
<a-tooltip
v-if="dialogShowType === 'review'"
:content="t('caseManagement.caseReview.batchReviewTip')"
position="right"
>
<icon-question-circle
class="ml-[4px] text-[var(--color-text-4)] hover:text-[rgb(var(--primary-5))]"
size="16"
/>
</a-tooltip>
<div class="ml-[8px] font-normal text-[var(--color-text-4)]">
({{ t('caseManagement.caseReview.selectedCase', { count: tableSelected.length }) }})
</div>
</div>
</template>
<a-form ref="dialogFormRef" :model="dialogForm" layout="vertical">
<a-form-item
v-if="dialogShowType === 'review'"
field="reason"
:label="t('caseManagement.caseReview.reviewResult')"
class="mb-[16px]"
>
<a-radio-group v-model:model-value="dialogForm.result" @change="() => dialogFormRef?.resetFields()">
<a-radio value="pass">
<div class="inline-flex items-center">
<MsIcon type="icon-icon_succeed_filled" class="mr-[4px] text-[rgb(var(--success-6))]" />
{{ t('caseManagement.caseReview.pass') }}
</div>
</a-radio>
<a-radio value="fail">
<div class="inline-flex items-center">
<MsIcon type="icon-icon_close_filled" class="mr-[4px] text-[rgb(var(--danger-6))]" />
{{ t('caseManagement.caseReview.fail') }}
</div>
</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item
v-if="dialogShowType === 'review' || dialogShowType === 'reReview'"
field="reason"
:label="t('caseManagement.caseReview.reason')"
:rules="
dialogForm.result === 'fail' && dialogShowType !== 'reReview'
? [{ required: true, message: t('caseManagement.caseReview.reasonRequired') }]
: []
"
asterisk-position="end"
class="mb-0"
>
<a-input
v-model:model-value="dialogForm.reason"
:placeholder="t('caseManagement.caseReview.reasonPlaceholder')"
/>
</a-form-item>
<a-form-item
v-if="dialogShowType === 'changeReviewer'"
field="reviewer"
:label="t('caseManagement.caseReview.chooseReviewer')"
:rules="[{ required: true, message: t('caseManagement.caseReview.reviewerRequired') }]"
asterisk-position="end"
class="mb-0"
>
<MsSelect
v-model:modelValue="dialogForm.reviewer"
mode="static"
:placeholder="t('caseManagement.caseReview.reviewerPlaceholder')"
:options="reviewersOptions"
:search-keys="['label']"
allow-search
multiple
/>
</a-form-item>
</a-form>
<template #footer>
<div class="flex items-center justify-end">
<div v-if="dialogShowType === 'changeReviewer'" class="mr-auto flex items-center">
<a-switch v-model:model-value="dialogForm.isAppend" size="small" class="mr-[4px]"></a-switch>
{{ t('caseManagement.caseReview.append') }}
<a-tooltip :content="t('caseManagement.caseReview.reviewResultTip')" position="right">
<template #content>
<div>{{ t('caseManagement.caseReview.appendTip1') }}</div>
<div>{{ t('caseManagement.caseReview.appendTip2') }}</div>
</template>
<icon-question-circle
class="ml-[4px] text-[var(--color-text-4)] hover:text-[rgb(var(--primary-5))]"
size="16"
/>
</a-tooltip>
</div>
<a-button type="secondary" @click="handleDialogCancel">{{ t('common.cancel') }}</a-button>
<a-button v-if="dialogShowType === 'review'" type="primary" class="ml-[12px]" @click="commitResult">
{{ t('caseManagement.caseReview.commitResult') }}
</a-button>
<a-button v-if="dialogShowType === 'changeReviewer'" type="primary" class="ml-[12px]" @click="changeReviewer">
{{ t('common.update') }}
</a-button>
<a-button v-if="dialogShowType === 'reReview'" type="primary" class="ml-[12px]" @click="reReview">
{{ t('caseManagement.caseReview.reReview') }}
</a-button>
</div>
</template>
</a-modal>
<AssociateDrawer
v-model:visible="associateDrawerVisible"
v-model:project="associateDrawerProject"
@success="writeAssociateCases"
/>
</div>
</template>
<script setup lang="ts">
import { useRoute, useRouter } from 'vue-router';
import { FormInstance, Message } from '@arco-design/web-vue';
import MsButton from '@/components/pure/ms-button/index.vue';
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
import MsPopconfirm from '@/components/pure/ms-popconfirm/index.vue';
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
import type { BatchActionParams, BatchActionQueryParams, MsTableColumn } from '@/components/pure/ms-table/type';
import useTable from '@/components/pure/ms-table/useTable';
import MsSelect from '@/components/business/ms-select';
import AssociateDrawer from '../create/associateDrawer.vue';
import { getCaseList } from '@/api/modules/case-management/caseReview';
import { useI18n } from '@/hooks/useI18n';
import useModal from '@/hooks/useModal';
import useTableStore from '@/hooks/useTableStore';
import { CaseManagementRouteEnum } from '@/enums/routeEnum';
import { TableKeyEnum } from '@/enums/tableEnum';
const props = defineProps<{
activeFolder: string | number;
}>();
const router = useRouter();
const route = useRoute();
const { t } = useI18n();
const { openModal } = useModal();
const keyword = ref('');
const showType = ref<'list' | 'mind'>('list');
type ResultMap = 0 | 1 | 2 | 3 | 4;
const resultMap = {
0: {
label: 'caseManagement.caseReview.unReview',
color: 'var(--color-text-input-border)',
icon: 'icon-icon_block_filled',
},
1: {
label: 'caseManagement.caseReview.reviewing',
color: 'rgb(var(--link-6))',
icon: 'icon-icon_testing',
},
2: {
label: 'caseManagement.caseReview.reviewPass',
color: 'rgb(var(--success-6))',
icon: 'icon-icon_succeed_filled',
},
3: {
label: 'caseManagement.caseReview.fail',
color: 'rgb(var(--danger-6))',
icon: 'icon-icon_close_filled',
},
4: {
label: 'caseManagement.caseReview.reReview',
color: 'rgb(var(--warning-6))',
icon: 'icon-icon_resubmit_filled',
},
} as const;
const columns: MsTableColumn = [
{
title: 'ID',
dataIndex: 'id',
sortIndex: 1,
showTooltip: true,
width: 100,
},
{
title: 'caseManagement.caseReview.caseName',
slotName: 'name',
dataIndex: 'name',
sortable: {
sortDirections: ['ascend', 'descend'],
},
width: 200,
},
{
title: 'caseManagement.caseReview.reviewer',
dataIndex: 'reviewer',
showTooltip: true,
sortable: {
sortDirections: ['ascend', 'descend'],
},
width: 150,
},
{
title: 'caseManagement.caseReview.reviewResult',
dataIndex: 'result',
slotName: 'result',
titleSlotName: 'resultColumn',
width: 110,
},
{
title: 'caseManagement.caseReview.version',
dataIndex: 'version',
width: 90,
},
{
title: 'caseManagement.caseReview.creator',
dataIndex: 'creator',
width: 150,
},
{
title: 'common.operation',
slotName: 'action',
dataIndex: 'operation',
fixed: 'right',
width: 140,
},
];
const tableStore = useTableStore();
tableStore.initColumn(TableKeyEnum.CASE_MANAGEMENT_REVIEW_CASE, columns, 'drawer');
const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector } = useTable(getCaseList, {
scroll: { x: '100%' },
tableKey: TableKeyEnum.CASE_MANAGEMENT_REVIEW_CASE,
showSetting: true,
selectable: true,
showSelectAll: true,
draggable: { type: 'handle', width: 32 },
});
const batchActions = {
baseAction: [
{
label: 'caseManagement.caseReview.review',
eventTag: 'review',
},
{
label: 'caseManagement.caseReview.changeReviewer',
eventTag: 'changeReviewer',
},
{
label: 'caseManagement.caseReview.disassociate',
eventTag: 'disassociate',
},
{
label: 'caseManagement.caseReview.reReview',
eventTag: 'reReview',
},
],
};
function searchReview() {
setLoadListParams({
keyword: keyword.value,
});
loadList();
}
onBeforeMount(() => {
loadList();
});
const tableSelected = ref<(string | number)[]>([]);
const batchParams = ref<BatchActionQueryParams>({
selectedIds: [],
selectAll: false,
excludeIds: [],
currentSelectCount: 0,
});
/**
* 处理表格选中
*/
function handleTableSelect(arr: (string | number)[]) {
tableSelected.value = arr;
}
const dialogVisible = ref<boolean>(false);
const activeRecord = ref({
id: '',
name: '',
status: 0,
});
const defaultDialogForm = {
result: 'pass',
reason: '',
reviewer: [],
isAppend: false,
};
const dialogForm = ref({ ...defaultDialogForm });
const dialogFormRef = ref<FormInstance>();
const dialogShowType = ref<'review' | 'changeReviewer' | 'reReview'>('review');
const dialogTitle = computed(() => {
switch (dialogShowType.value) {
case 'review':
return t('caseManagement.caseReview.batchReview');
case 'changeReviewer':
return t('caseManagement.caseReview.changeReviewer');
case 'reReview':
return t('caseManagement.caseReview.reReview');
default:
return '';
}
});
const reviewersOptions = ref([
{
label: '张三',
value: '1',
},
{
label: '李四',
value: '2',
},
{
label: '王五',
value: '3',
},
]);
function handleDialogCancel() {
dialogVisible.value = false;
dialogFormRef.value?.resetFields();
dialogForm.value = { ...defaultDialogForm };
}
/**
* 拦截切换最新版确认
* @param done 关闭弹窗
*/
async function handleDeleteConfirm(done: (closed: boolean) => void) {
try {
// if (replaceVersion.value !== '') {
// await useLatestVersion(replaceVersion.value);
// }
// await toggleVersionStatus(activeRecord.value.id);
// Message.success(t('caseManagement.caseReview.close', { name: activeRecord.value.name }));
loadList();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
done(false);
} finally {
done(true);
}
}
function handleArchive(record: any) {
openModal({
type: 'warning',
title: t('caseManagement.caseReview.archivedTitle', { name: record.name }),
content: t('caseManagement.caseReview.archivedContent'),
okText: t('caseManagement.caseReview.archive'),
cancelText: t('common.cancel'),
onBeforeOk: async () => {
try {
// await resetUserPassword({
// selectIds,
// selectAll: !!params?.selectAll,
// excludeIds: params?.excludeIds || [],
// condition: { keyword: keyword.value },
// });
Message.success(t('caseManagement.caseReview.archiveSuccess'));
resetSelector();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
},
hideCancel: false,
});
}
const selectedModuleKeys = ref<(string | number)[]>([]);
/**
* 处理文件夹树节点选中事件
*/
function folderNodeSelect(keys: (string | number)[]) {
selectedModuleKeys.value = keys;
}
function disassociate() {
openModal({
type: 'warning',
title: t('caseManagement.caseReview.disassociateConfirmTitle', { count: tableSelected.value.length }),
content: t('caseManagement.caseReview.disassociateTipContent'),
okText: t('caseManagement.caseReview.disassociate'),
cancelText: t('common.cancel'),
onBeforeOk: async () => {
try {
// await resetUserPassword({
// selectIds,
// selectAll: !!params?.selectAll,
// excludeIds: params?.excludeIds || [],
// condition: { keyword: keyword.value },
// });
Message.success(t('common.updateSuccess'));
resetSelector();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
},
hideCancel: false,
});
}
function reReview() {
try {
Message.success(t('common.updateSuccess'));
dialogVisible.value = false;
resetSelector();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
}
function changeReviewer() {
dialogFormRef.value?.validate(async (errors) => {
if (!errors) {
try {
Message.success(t('common.updateSuccess'));
dialogVisible.value = false;
resetSelector();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
}
});
}
function commitResult() {
dialogFormRef.value?.validate(async (errors) => {
if (!errors) {
try {
Message.success(t('common.updateSuccess'));
dialogVisible.value = false;
resetSelector();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
}
});
}
/**
* 处理表格选中后批量操作
* @param event 批量操作事件对象
*/
function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) {
tableSelected.value = params?.selectedIds || [];
batchParams.value = params;
switch (event.eventTag) {
case 'review':
dialogVisible.value = true;
dialogShowType.value = 'review';
break;
case 'changeReviewer':
dialogVisible.value = true;
dialogShowType.value = 'changeReviewer';
break;
case 'disassociate':
disassociate();
break;
case 'reReview':
dialogVisible.value = true;
dialogShowType.value = 'reReview';
break;
default:
break;
}
}
function handleAddClick() {
console.log('handleAddClick');
}
function openDetail(id: string) {
router.push({
name: CaseManagementRouteEnum.CASE_MANAGEMENT_REVIEW_DETAIL_CASE_DETAIL,
query: {
...route.query,
caseId: id,
},
});
}
function review(record: any) {
console.log('review');
}
function createCase() {
router.push({
name: CaseManagementRouteEnum.CASE_MANAGEMENT_REVIEW_CREATE,
query: {
reviewId: route.query.id,
},
});
}
const associateDrawerVisible = ref(false);
const associateDrawerProject = ref('');
function writeAssociateCases(ids: string[]) {
console.log('writeAssociateCases', ids);
}
</script>
<style lang="less" scoped>
.case-show-type {
@apply grid grid-cols-2;
.show-type-icon {
:deep(.arco-radio-button-content) {
@apply flex;
padding: 4px;
line-height: 20px;
}
}
}
:deep(.arco-radio-label) {
@apply inline-flex;
}
</style>

View File

@ -0,0 +1,203 @@
<template>
<div>
<a-input
v-model:model-value="moduleKeyword"
:placeholder="t('caseManagement.caseReview.folderSearchPlaceholder')"
allow-clear
class="mb-[16px]"
/>
<div class="folder">
<div :class="getFolderClass('all')" @click="setActiveFolder('all')">
<MsIcon type="icon-icon_folder_filled1" class="folder-icon" />
<div class="folder-name">{{ t('caseManagement.caseReview.allCases') }}</div>
<div class="folder-count">({{ allFileCount }})</div>
</div>
</div>
<a-divider class="my-[8px]" />
<a-spin class="min-h-[200px] w-full" :loading="loading">
<MsTree
:selected-keys="selectedKeys"
:data="folderTree"
:keyword="moduleKeyword"
:default-expand-all="isExpandAll"
:expand-all="isExpandAll"
:empty-text="t('caseManagement.caseReview.noCases')"
:draggable="false"
:virtual-list-props="virtualListProps"
:field-names="{
title: 'name',
key: 'id',
children: 'children',
count: 'count',
}"
block-node
title-tooltip-position="left"
@select="folderNodeSelect"
>
<template #title="nodeData">
<div class="inline-flex w-full">
<div class="one-line-text w-[calc(100%-32px)] text-[var(--color-text-1)]">{{ nodeData.name }}</div>
<div class="ml-[4px] text-[var(--color-text-4)]">({{ nodeData.count || 0 }})</div>
</div>
</template>
</MsTree>
</a-spin>
</div>
</template>
<script setup lang="ts">
import { computed, onBeforeMount, ref, watch } from 'vue';
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
import MsTree from '@/components/business/ms-tree/index.vue';
import type { MsTreeNodeData } from '@/components/business/ms-tree/types';
import { getModules } from '@/api/modules/project-management/fileManagement';
import { useI18n } from '@/hooks/useI18n';
import useAppStore from '@/store/modules/app';
import { mapTree } from '@/utils';
import { ModuleTreeNode } from '@/models/projectManagement/file';
const props = defineProps<{
modulesCount?: Record<string, number>; //
showType?: string; //
isExpandAll?: boolean; //
}>();
const emit = defineEmits(['init', 'folderNodeSelect']);
const appStore = useAppStore();
const { t } = useI18n();
const virtualListProps = computed(() => {
return {
height: 'calc(100vh - 460px)',
};
});
const activeFolder = ref<string>('all');
const allFileCount = ref(0);
const isExpandAll = ref(props.isExpandAll);
watch(
() => props.isExpandAll,
(val) => {
isExpandAll.value = val;
}
);
function getFolderClass(id: string) {
return activeFolder.value === id ? 'folder-text folder-text--active' : 'folder-text';
}
function setActiveFolder(id: string) {
activeFolder.value = id;
emit('folderNodeSelect', [id], []);
}
const moduleKeyword = ref('');
const folderTree = ref<ModuleTreeNode[]>([]);
const loading = ref(false);
const selectedKeys = ref<string[]>([]);
/**
* 初始化模块树
* @param isSetDefaultKey 是否设置第一个节点为选中节点
*/
async function initModules(isSetDefaultKey = false) {
try {
loading.value = true;
const res = await getModules(appStore.currentProjectId);
folderTree.value = res;
if (isSetDefaultKey) {
selectedKeys.value = [folderTree.value[0].id];
const offspringIds: string[] = [];
mapTree(folderTree.value[0].children || [], (e) => {
offspringIds.push(e.id);
return e;
});
emit('folderNodeSelect', selectedKeys.value, offspringIds);
}
emit(
'init',
folderTree.value.map((e) => e.name)
);
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
} finally {
loading.value = false;
}
}
/**
* 处理文件夹树节点选中事件
*/
function folderNodeSelect(_selectedKeys: (string | number)[], node: MsTreeNodeData) {
const offspringIds: string[] = [];
mapTree(node.children || [], (e) => {
offspringIds.push(e.id);
return e;
});
emit('folderNodeSelect', _selectedKeys, offspringIds);
}
onBeforeMount(() => {
initModules();
});
/**
* 初始化模块文件数量
*/
watch(
() => props.modulesCount,
(obj) => {
folderTree.value = mapTree<ModuleTreeNode>(folderTree.value, (node) => {
return {
...node,
count: obj?.[node.id] || 0,
};
});
}
);
defineExpose({
initModules,
});
</script>
<style lang="less" scoped>
.folder {
@apply flex cursor-pointer items-center justify-between;
padding: 8px 4px;
border-radius: var(--border-radius-small);
&:hover {
background-color: rgb(var(--primary-1));
}
.folder-text {
@apply flex cursor-pointer items-center;
.folder-icon {
margin-right: 4px;
color: var(--color-text-4);
}
.folder-name {
color: var(--color-text-1);
}
.folder-count {
margin-left: 4px;
color: var(--color-text-4);
}
}
.folder-text--active {
.folder-icon,
.folder-name,
.folder-count {
color: rgb(var(--primary-5));
}
}
}
</style>

View File

@ -0,0 +1,386 @@
<template>
<div>
<a-input
v-model:model-value="moduleKeyword"
:placeholder="t('caseManagement.caseReview.folderSearchPlaceholder')"
allow-clear
class="mb-[16px]"
/>
<div v-if="!props.isModal" class="folder">
<div :class="getFolderClass('all')" @click="setActiveFolder('all')">
<MsIcon type="icon-icon_folder_filled1" class="folder-icon" />
<div class="folder-name">{{ t('caseManagement.caseReview.allReviews') }}</div>
<div class="folder-count">({{ allFileCount }})</div>
</div>
<div class="ml-auto flex items-center">
<a-tooltip :content="isExpandAll ? t('common.collapseAll') : t('common.expandAll')">
<MsButton type="icon" status="secondary" class="!mr-0 p-[4px]" @click="changeExpand">
<MsIcon :type="isExpandAll ? 'icon-icon_folder_collapse1' : 'icon-icon_folder_expansion1'" />
</MsButton>
</a-tooltip>
<popConfirm mode="add" :all-names="rootModulesName" parent-id="none" @add-finish="initModules">
<MsButton type="icon" class="!mr-0 p-[2px]">
<MsIcon
type="icon-icon_create_planarity"
size="18"
class="text-[rgb(var(--primary-5))] hover:text-[rgb(var(--primary-4))]"
/>
</MsButton>
</popConfirm>
</div>
</div>
<a-divider v-if="!props.isModal" class="my-[8px]" />
<a-spin class="min-h-[400px] w-full" :loading="loading">
<MsTree
v-model:focus-node-key="focusNodeKey"
:selected-keys="selectedKeys"
:data="folderTree"
:keyword="moduleKeyword"
:node-more-actions="folderMoreActions"
:default-expand-all="isExpandAll"
:expand-all="isExpandAll"
:empty-text="t('caseManagement.caseReview.noReviews')"
:draggable="!props.isModal"
:virtual-list-props="virtualListProps"
:field-names="{
title: 'name',
key: 'id',
children: 'children',
count: 'count',
}"
block-node
title-tooltip-position="left"
@select="folderNodeSelect"
@more-action-select="handleFolderMoreSelect"
@more-actions-close="moreActionsClose"
@drop="handleDrop"
>
<template #title="nodeData">
<div class="inline-flex w-full">
<div class="one-line-text w-[calc(100%-32px)] text-[var(--color-text-1)]">{{ nodeData.name }}</div>
<div v-if="!props.isModal" class="ml-[4px] text-[var(--color-text-4)]">({{ nodeData.count || 0 }})</div>
</div>
</template>
<template v-if="!props.isModal" #extra="nodeData">
<!-- 默认模块的 id 是root默认模块不可编辑不可添加子模块 -->
<popConfirm
v-if="nodeData.id !== 'root'"
mode="add"
:all-names="(nodeData.children || []).map((e: ModuleTreeNode) => e.name || '')"
:parent-id="nodeData.id"
@close="resetFocusNodeKey"
@add-finish="() => initModules()"
>
<MsButton type="icon" size="mini" class="ms-tree-node-extra__btn !mr-0" @click="setFocusNodeKey(nodeData)">
<MsIcon type="icon-icon_add_outlined" size="14" class="text-[var(--color-text-4)]" />
</MsButton>
</popConfirm>
<popConfirm
v-if="nodeData.id !== 'root'"
mode="rename"
:parent-id="nodeData.id"
:node-id="nodeData.id"
:field-config="{ field: renameFolderTitle }"
:all-names="(nodeData.children || []).map((e: ModuleTreeNode) => e.name || '')"
@close="resetFocusNodeKey"
@rename-finish="(val) => (nodeData.name = val)"
>
<span :id="`renameSpan${nodeData.id}`" class="relative"></span>
</popConfirm>
</template>
</MsTree>
</a-spin>
</div>
</template>
<script setup lang="ts">
import { computed, onBeforeMount, ref, watch } from 'vue';
import { Message } from '@arco-design/web-vue';
import MsButton from '@/components/pure/ms-button/index.vue';
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
import type { ActionsItem } from '@/components/pure/ms-table-more-action/types';
import MsTree from '@/components/business/ms-tree/index.vue';
import type { MsTreeNodeData } from '@/components/business/ms-tree/types';
import popConfirm from './popConfirm.vue';
import { deleteModule, getModules, moveModule } from '@/api/modules/project-management/fileManagement';
import { useI18n } from '@/hooks/useI18n';
import useModal from '@/hooks/useModal';
import useAppStore from '@/store/modules/app';
import { mapTree } from '@/utils';
import { ModuleTreeNode } from '@/models/projectManagement/file';
const props = defineProps<{
isModal?: boolean; //
modulesCount?: Record<string, number>; //
showType?: string; //
isExpandAll?: boolean; //
}>();
const emit = defineEmits(['init', 'folderNodeSelect']);
const appStore = useAppStore();
const { t } = useI18n();
const { openModal } = useModal();
const virtualListProps = computed(() => {
if (props.isModal) {
return {
height: 'calc(60vh - 190px)',
};
}
return {
height: 'calc(100vh - 325px)',
};
});
const activeFolder = ref<string>('all');
const allFileCount = ref(0);
const isExpandAll = ref(props.isExpandAll);
const rootModulesName = ref<string[]>([]); //
watch(
() => props.isExpandAll,
(val) => {
isExpandAll.value = val;
}
);
function changeExpand() {
isExpandAll.value = !isExpandAll.value;
}
function getFolderClass(id: string) {
return activeFolder.value === id ? 'folder-text folder-text--active' : 'folder-text';
}
function setActiveFolder(id: string) {
activeFolder.value = id;
emit('folderNodeSelect', [id], []);
}
const moduleKeyword = ref('');
const folderTree = ref<ModuleTreeNode[]>([]);
const focusNodeKey = ref<string | number>('');
const loading = ref(false);
function setFocusNodeKey(node: MsTreeNodeData) {
focusNodeKey.value = node.id || '';
}
const folderMoreActions: ActionsItem[] = [
{
label: 'common.rename',
eventTag: 'rename',
},
{
label: 'common.delete',
eventTag: 'delete',
danger: true,
},
];
const renamePopVisible = ref(false);
const selectedKeys = ref<string[]>([]);
/**
* 初始化模块树
* @param isSetDefaultKey 是否设置第一个节点为选中节点
*/
async function initModules(isSetDefaultKey = false) {
try {
loading.value = true;
const res = await getModules(appStore.currentProjectId);
folderTree.value = mapTree<ModuleTreeNode>(res, (e) => {
return {
...e,
hideMoreAction: e.id === 'root',
draggable: e.id !== 'root' && !props.isModal,
disabled: e.id === activeFolder.value && props.isModal,
};
});
if (isSetDefaultKey) {
selectedKeys.value = [folderTree.value[0].id];
const offspringIds: string[] = [];
mapTree(folderTree.value[0].children || [], (e) => {
offspringIds.push(e.id);
return e;
});
emit('folderNodeSelect', selectedKeys.value, offspringIds);
}
emit(
'init',
folderTree.value.map((e) => e.name)
);
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
} finally {
loading.value = false;
}
}
/**
* 删除文件夹
* @param node 节点信息
*/
function deleteFolder(node: MsTreeNodeData) {
openModal({
type: 'error',
title: t('caseManagement.caseReview.deleteFolderTipTitle', { name: node.name }),
content: t('caseManagement.caseReview.deleteFolderTipContent'),
okText: t('caseManagement.caseReview.deleteConfirm'),
okButtonProps: {
status: 'danger',
},
maskClosable: false,
onBeforeOk: async () => {
try {
await deleteModule(node.id);
Message.success(t('caseManagement.caseReview.deleteSuccess'));
initModules(selectedKeys.value[0] === node.id);
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
},
hideCancel: false,
});
}
const renameFolderTitle = ref(''); //
function resetFocusNodeKey() {
focusNodeKey.value = '';
renamePopVisible.value = false;
renameFolderTitle.value = '';
}
/**
* 处理文件夹树节点选中事件
*/
function folderNodeSelect(_selectedKeys: (string | number)[], node: MsTreeNodeData) {
const offspringIds: string[] = [];
mapTree(node.children || [], (e) => {
offspringIds.push(e.id);
return e;
});
emit('folderNodeSelect', _selectedKeys, offspringIds);
}
/**
* 处理树节点更多按钮事件
* @param item
*/
function handleFolderMoreSelect(item: ActionsItem, node: MsTreeNodeData) {
switch (item.eventTag) {
case 'delete':
deleteFolder(node);
resetFocusNodeKey();
break;
case 'rename':
renameFolderTitle.value = node.name || '';
renamePopVisible.value = true;
document.querySelector(`#renameSpan${node.id}`)?.dispatchEvent(new Event('click'));
break;
default:
break;
}
}
/**
* 处理文件夹树节点拖拽事件
* @param tree 树数据
* @param dragNode 拖拽节点
* @param dropNode 释放节点
* @param dropPosition 释放位置
*/
async function handleDrop(
tree: MsTreeNodeData[],
dragNode: MsTreeNodeData,
dropNode: MsTreeNodeData,
dropPosition: number
) {
try {
loading.value = true;
await moveModule({
dragNodeId: dragNode.id as string,
dropNodeId: dropNode.id || '',
dropPosition,
});
Message.success(t('caseManagement.caseReview.moduleMoveSuccess'));
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
} finally {
loading.value = false;
initModules();
}
}
function moreActionsClose() {
if (!renamePopVisible.value) {
// key
resetFocusNodeKey();
}
}
onBeforeMount(() => {
initModules();
});
/**
* 初始化模块文件数量
*/
watch(
() => props.modulesCount,
(obj) => {
folderTree.value = mapTree<ModuleTreeNode>(folderTree.value, (node) => {
return {
...node,
count: obj?.[node.id] || 0,
};
});
}
);
defineExpose({
initModules,
});
</script>
<style lang="less" scoped>
.folder {
@apply flex cursor-pointer items-center justify-between;
padding: 8px 4px;
border-radius: var(--border-radius-small);
&:hover {
background-color: rgb(var(--primary-1));
}
.folder-text {
@apply flex cursor-pointer items-center;
.folder-icon {
margin-right: 4px;
color: var(--color-text-4);
}
.folder-name {
color: var(--color-text-1);
}
.folder-count {
margin-left: 4px;
color: var(--color-text-4);
}
}
.folder-text--active {
.folder-icon,
.folder-name,
.folder-count {
color: rgb(var(--primary-5));
}
}
}
</style>

View File

@ -0,0 +1,204 @@
<template>
<a-popconfirm
v-model:popup-visible="innerVisible"
class="ms-pop-confirm--hidden-icon"
position="bottom"
:ok-loading="loading"
:cancel-button-props="{ disabled: loading }"
:on-before-ok="beforeConfirm"
:popup-container="props.popupContainer || 'body'"
@popup-visible-change="reset"
>
<template #content>
<div class="mb-[8px] font-medium">
{{
props.title ||
(props.mode === 'add' ? t('project.fileManagement.addSubModule') : t('project.fileManagement.rename'))
}}
</div>
<a-form ref="formRef" :model="form" layout="vertical">
<a-form-item
class="hidden-item"
field="field"
:rules="[{ required: true, message: t('project.fileManagement.nameNotNull') }, { validator: validateName }]"
>
<a-textarea
v-if="props.fieldConfig?.isTextArea"
v-model:model-value="form.field"
:max-length="props.fieldConfig?.maxLength"
:auto-size="{ maxRows: 4 }"
:placeholder="props.fieldConfig?.placeholder || t('project.fileManagement.namePlaceholder')"
class="w-[245px]"
@press-enter="beforeConfirm(undefined)"
>
</a-textarea>
<a-input
v-else
v-model:model-value="form.field"
:max-length="props.fieldConfig?.maxLength || 50"
:placeholder="props.fieldConfig?.placeholder || t('project.fileManagement.namePlaceholder')"
class="w-[245px]"
@press-enter="beforeConfirm(undefined)"
/>
</a-form-item>
</a-form>
</template>
<slot></slot>
</a-popconfirm>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue';
import { Message } from '@arco-design/web-vue';
import {
addModule,
updateFile,
updateModule,
updateRepository,
} from '@/api/modules/project-management/fileManagement';
import { useI18n } from '@/hooks/useI18n';
import useAppStore from '@/store/modules/app';
import type { FieldRule, FormInstance } from '@arco-design/web-vue';
interface FieldConfig {
field?: string;
rules?: FieldRule[];
placeholder?: string;
maxLength?: number;
isTextArea?: boolean;
}
const props = defineProps<{
mode: 'add' | 'rename' | 'fileRename' | 'fileUpdateDesc' | 'repositoryRename';
visible?: boolean;
title?: string;
allNames: string[];
popupContainer?: string;
fieldConfig?: FieldConfig;
parentId?: string; // id
nodeId?: string; // id
}>();
const emit = defineEmits(['update:visible', 'close', 'addFinish', 'renameFinish', 'updateDescFinish']);
const appStore = useAppStore();
const { t } = useI18n();
const innerVisible = ref(props.visible || false);
const form = ref({
field: props.fieldConfig?.field || '',
});
const formRef = ref<FormInstance>();
const loading = ref(false);
watch(
() => props.fieldConfig?.field,
(val) => {
form.value.field = val || '';
},
{
deep: true,
}
);
watch(
() => props.visible,
(val) => {
innerVisible.value = val;
}
);
watch(
() => innerVisible.value,
(val) => {
if (!val) {
emit('close');
}
emit('update:visible', val);
}
);
function beforeConfirm(done?: (closed: boolean) => void) {
formRef.value?.validate(async (errors) => {
if (!errors) {
try {
loading.value = true;
if (props.mode === 'add') {
//
await addModule({
projectId: appStore.currentProjectId,
parentId: props.parentId || '',
name: form.value.field,
});
Message.success(t('project.fileManagement.addSubModuleSuccess'));
emit('addFinish', form.value.field);
} else if (props.mode === 'rename') {
//
await updateModule({
id: props.nodeId || '',
name: form.value.field,
});
Message.success(t('project.fileManagement.renameSuccess'));
emit('renameFinish', form.value.field);
} else if (props.mode === 'fileRename') {
//
await updateFile({
id: props.nodeId || '',
name: form.value.field,
});
Message.success(t('project.fileManagement.renameSuccess'));
emit('renameFinish', form.value.field);
} else if (props.mode === 'fileUpdateDesc') {
//
await updateFile({
id: props.nodeId || '',
description: form.value.field,
});
Message.success(t('project.fileManagement.updateDescSuccess'));
emit('updateDescFinish', form.value.field);
} else if (props.mode === 'repositoryRename') {
//
await updateRepository({
id: props.nodeId || '',
name: form.value.field,
});
Message.success(t('project.fileManagement.renameSuccess'));
emit('renameFinish', form.value.field);
}
if (done) {
done(true);
} else {
innerVisible.value = false;
}
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
if (done) {
done(false);
}
} finally {
loading.value = false;
}
} else if (done) {
done(false);
}
});
}
function validateName(value: any, callback: (error?: string | undefined) => void) {
if (props.allNames.includes(value)) {
callback(t('project.fileManagement.nameExist'));
}
}
function reset(val: boolean) {
if (!val) {
form.value.field = '';
formRef.value?.resetFields();
}
}
</script>
<style lang="less" scoped></style>

View File

@ -0,0 +1,570 @@
<template>
<div class="px-[24px] py-[16px]">
<div class="mb-[16px] flex items-center justify-between">
<div class="flex items-center">
<div class="mr-[4px] text-[var(--color-text-1)]">全部评审</div>
<div class="text-[var(--color-text-4)]">(2)</div>
</div>
<div class="flex items-center gap-[8px]">
<a-input-search
v-model="keyword"
:placeholder="t('caseManagement.caseReview.searchPlaceholder')"
allow-clear
@press-enter="searchReview"
@search="searchReview"
/>
<a-button type="outline" class="arco-btn-outline--secondary px-[8px]">
<MsIcon type="icon-icon-filter" class="mr-[4px] text-[var(--color-text-4)]" />
<div class="text-[var(--color-text-4)]">{{ t('common.filter') }}</div>
</a-button>
<a-button type="outline" class="arco-btn-outline--secondary p-[10px]">
<icon-refresh class="text-[var(--color-text-4)]" />
</a-button>
</div>
</div>
<ms-base-table
v-bind="propsRes"
:action-config="batchActions"
no-disable
filter-icon-align-left
v-on="propsEvent"
@selected-change="handleTableSelect"
@batch-action="handleTableBatch"
>
<!-- <template #status-filter>
<a-checkbox-group>
<a-checkbox :value="0">
<a-tag :color="statusMap[0].color" :class="statusMap[0].class">
{{ t(statusMap[0].label) }}
</a-tag>
</a-checkbox>
<a-checkbox :value="1">
<a-tag :color="statusMap[1].color" :class="statusMap[1].class">
{{ t(statusMap[1].label) }}
</a-tag>
</a-checkbox>
<a-checkbox :value="2">
<a-tag :color="statusMap[2].color" :class="statusMap[2].class">
{{ t(statusMap[2].label) }}
</a-tag>
</a-checkbox>
<a-checkbox :value="3">
<a-tag :color="statusMap[3].color" :class="statusMap[3].class">
{{ t(statusMap[3].label) }}
</a-tag>
</a-checkbox>
</a-checkbox-group>
</template> -->
<template #passRateColumn>
<div class="flex items-center text-[var(--color-text-3)]">
{{ t('caseManagement.caseReview.passRate') }}
<a-tooltip :content="t('caseManagement.caseReview.passRateTip')" position="right">
<icon-question-circle
class="ml-[4px] text-[var(--color-text-4)] hover:text-[rgb(var(--primary-5))]"
size="16"
/>
</a-tooltip>
</div>
</template>
<template #name="{ record }">
<a-tooltip :content="record.name">
<a-button type="text" class="px-0" @click="openDetail(record.id)">
<div class="one-line-text max-w-[168px]">{{ record.name }}</div>
</a-button>
</a-tooltip>
</template>
<template #status="{ record }">
<statusTag :status="record.status" />
</template>
<template #passRate="{ record }">
<div class="mr-[8px] w-[100px]">
<passRateLine :review-detail="record" height="5px" />
</div>
<div class="text-[var(--color-text-1)]">
{{ `${(((record.passCount + record.failCount) / record.caseCount) * 100).toFixed(2)}%` }}
</div>
</template>
<template #action="{ record }">
<MsButton type="text" class="!mr-0">
{{ t('common.edit') }}
</MsButton>
<a-divider direction="vertical" :margin="8"></a-divider>
<MsButton type="text" class="!mr-0">
{{ t('common.export') }}
</MsButton>
<a-divider direction="vertical" :margin="8"></a-divider>
<MsTableMoreAction :list="getMoreAction(record.status)" @select="handleMoreActionSelect($event, record)" />
</template>
<template v-if="keyword.trim() === ''" #empty>
<div class="flex items-center justify-center p-[8px] text-[var(--color-text-4)]">
{{ t('caseManagement.caseReview.tableNoData') }}
<MsButton class="ml-[8px]" @click="handleAddClick">
{{ t('caseManagement.caseReview.create') }}
</MsButton>
</div>
</template>
</ms-base-table>
<a-modal
v-model:visible="dialogVisible"
:on-before-ok="handleDeleteConfirm"
class="p-[4px]"
title-align="start"
body-class="p-0"
:mask-closable="false"
>
<template #title>
<div class="flex items-center justify-start">
<icon-exclamation-circle-fill size="20" class="mr-[8px] text-[rgb(var(--danger-6))]" />
<div class="text-[var(--color-text-1)]">
{{ t('caseManagement.caseReview.deleteReviewTitle', { name: activeRecord.name }) }}
</div>
</div>
</template>
<div v-if="activeRecord.status === 2" class="mb-[10px]">
<div>{{ t('caseManagement.caseReview.deleteFinishedReviewContent1') }}</div>
<div>{{ t('caseManagement.caseReview.deleteFinishedReviewContent2') }}</div>
</div>
<div v-else class="mb-[10px]">
{{
activeRecord.status === 1
? t('caseManagement.caseReview.deleteReviewingContent')
: t('caseManagement.caseReview.deleteReviewContent', {
status: t(statusMap[activeRecord.status as StatusMap].label),
})
}}
</div>
<a-input
v-model:model-value="confirmReviewName"
:placeholder="t('caseManagement.caseReview.deleteReviewPlaceholder')"
/>
<template #footer>
<div class="flex items-center justify-end">
<a-button type="secondary" @click="handleDialogCancel">{{ t('common.cancel') }}</a-button>
<a-button
type="primary"
status="danger"
:disabled="confirmReviewName !== activeRecord.name"
class="ml-[12px]"
@click="handleDialogCancel"
>
{{ t('common.confirmDelete') }}
</a-button>
<a-button v-if="activeRecord.status === 2" type="primary" class="ml-[12px]" @click="handleDialogCancel">
{{ t('caseManagement.caseReview.archive') }}
</a-button>
</div>
</template>
</a-modal>
<a-modal
v-model:visible="moveModalVisible"
title-align="start"
class="ms-modal-no-padding ms-modal-small"
:mask-closable="false"
:ok-text="t('caseManagement.caseReview.batchMoveConfirm', { count: tableSelected.length })"
:ok-button-props="{ disabled: selectedModuleKeys.length === 0 }"
:cancel-button-props="{ disabled: batchMoveFileLoading }"
:on-before-ok="handleReviewMove"
@close="handleMoveModalCancel"
>
<template #title>
<div class="flex items-center">
{{ t('caseManagement.caseReview.batchMove') }}
<div class="ml-[4px] text-[var(--color-text-4)]">
{{ t('caseManagement.caseReview.batchMoveTitleSub', { count: tableSelected.length }) }}
</div>
</div>
</template>
<ModuleTree
v-if="moveModalVisible"
v-model:selected-keys="selectedModuleKeys"
:is-expand-all="true"
:active-folder="props.activeFolder"
is-modal
@folder-node-select="folderNodeSelect"
/>
</a-modal>
</div>
</template>
<script setup lang="ts">
import { useRouter } from 'vue-router';
import { Message } from '@arco-design/web-vue';
import dayjs from 'dayjs';
import MsButton from '@/components/pure/ms-button/index.vue';
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
import type { BatchActionParams, BatchActionQueryParams, MsTableColumn } from '@/components/pure/ms-table/type';
import useTable from '@/components/pure/ms-table/useTable';
import MsTableMoreAction from '@/components/pure/ms-table-more-action/index.vue';
import type { ActionsItem } from '@/components/pure/ms-table-more-action/types';
import passRateLine from '../passRateLine.vue';
import statusTag from '../statusTag.vue';
import ModuleTree from './moduleTree.vue';
import { getCaseList } from '@/api/modules/case-management/caseReview';
import { useI18n } from '@/hooks/useI18n';
import useModal from '@/hooks/useModal';
import useTableStore from '@/hooks/useTableStore';
import { CaseManagementRouteEnum } from '@/enums/routeEnum';
import { TableKeyEnum } from '@/enums/tableEnum';
const props = defineProps<{
activeFolder: string | number;
}>();
const router = useRouter();
const { t } = useI18n();
const { openModal } = useModal();
const keyword = ref('');
type StatusMap = 0 | 1 | 2 | 3;
const statusMap = {
0: {
label: 'caseManagement.caseReview.unStart',
color: 'var(--color-text-n8)',
class: '!text-[var(--color-text-1)]',
},
1: {
label: 'caseManagement.caseReview.going',
color: 'rgb(var(--link-2))',
class: '!text-[rgb(var(--link-6))]',
},
2: {
label: 'caseManagement.caseReview.finished',
color: 'rgb(var(--success-2))',
class: '!text-[rgb(var(--success-6))]',
},
3: {
label: 'caseManagement.caseReview.archived',
color: 'var(--color-text-n8)',
class: '!text-[var(--color-text-4)]',
},
} as const;
const typeMap = {
single: 'caseManagement.caseReview.single',
multi: 'caseManagement.caseReview.multi',
};
const columns: MsTableColumn = [
{
title: 'ID',
dataIndex: 'id',
sortIndex: 1,
showTooltip: true,
width: 90,
},
{
title: 'caseManagement.caseReview.name',
slotName: 'name',
dataIndex: 'name',
sortable: {
sortDirections: ['ascend', 'descend'],
},
width: 200,
},
{
title: 'caseManagement.caseReview.caseCount',
dataIndex: 'caseCount',
width: 90,
},
{
title: 'caseManagement.caseReview.status',
dataIndex: 'status',
slotName: 'status',
width: 150,
},
{
title: 'caseManagement.caseReview.passRate',
slotName: 'passRate',
titleSlotName: 'passRateColumn',
width: 200,
},
{
title: 'caseManagement.caseReview.type',
dataIndex: 'type',
width: 90,
},
{
title: 'caseManagement.caseReview.reviewer',
dataIndex: 'reviewer',
showTooltip: true,
sortable: {
sortDirections: ['ascend', 'descend'],
},
width: 150,
},
{
title: 'caseManagement.caseReview.creator',
dataIndex: 'creator',
width: 90,
},
{
title: 'caseManagement.caseReview.module',
dataIndex: 'module',
width: 90,
},
{
title: 'caseManagement.caseReview.tag',
dataIndex: 'tags',
isTag: true,
width: 150,
},
{
title: 'caseManagement.caseReview.desc',
dataIndex: 'desc',
width: 150,
showTooltip: true,
},
{
title: 'caseManagement.caseReview.cycle',
dataIndex: 'cycle',
width: 340,
},
{
title: 'common.operation',
slotName: 'action',
dataIndex: 'operation',
fixed: 'right',
width: 140,
},
];
const tableStore = useTableStore();
tableStore.initColumn(TableKeyEnum.CASE_MANAGEMENT_REVIEW, columns, 'drawer');
const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector } = useTable(
getCaseList,
{
tableKey: TableKeyEnum.CASE_MANAGEMENT_REVIEW,
showSetting: true,
selectable: true,
showSelectAll: true,
},
(item) => {
return {
...item,
type: t(typeMap[item.type as keyof typeof typeMap]),
tags: item.tags?.map((e: string) => ({ id: e, name: e })) || [],
cycle: `${dayjs(item.cycle[0]).format('YYYY-MM-DD HH:mm:ss')} - ${dayjs(item.cycle[1]).format(
'YYYY-MM-DD HH:mm:ss'
)}`,
};
}
);
const batchActions = {
baseAction: [
{
label: 'caseManagement.caseReview.move',
eventTag: 'move',
},
],
};
function searchReview() {
setLoadListParams({
keyword: keyword.value,
});
loadList();
}
onBeforeMount(() => {
loadList();
});
const tableSelected = ref<(string | number)[]>([]);
const batchParams = ref<BatchActionQueryParams>({
selectedIds: [],
selectAll: false,
excludeIds: [],
currentSelectCount: 0,
});
/**
* 处理表格选中
*/
function handleTableSelect(arr: (string | number)[]) {
tableSelected.value = arr;
}
const dialogVisible = ref<boolean>(false);
const activeRecord = ref({
id: '',
name: '',
status: 0,
});
const confirmReviewName = ref('');
function handleDialogCancel() {
dialogVisible.value = false;
}
/**
* 拦截切换最新版确认
* @param done 关闭弹窗
*/
async function handleDeleteConfirm(done: (closed: boolean) => void) {
try {
// if (replaceVersion.value !== '') {
// await useLatestVersion(replaceVersion.value);
// }
// await toggleVersionStatus(activeRecord.value.id);
// Message.success(t('caseManagement.caseReview.close', { name: activeRecord.value.name }));
loadList();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
done(false);
} finally {
done(true);
}
}
/**
* 根据评审状态获取更多按钮列表
* @param status 评审状态
*/
function getMoreAction(status: number) {
if (status === 2) {
return [
{
label: 'caseManagement.caseReview.archive',
eventTag: 'archive',
},
{
isDivider: true,
},
{
label: 'common.delete',
eventTag: 'delete',
danger: true,
},
];
}
return [
{
label: 'common.delete',
eventTag: 'delete',
danger: true,
},
];
}
function handleArchive(record: any) {
openModal({
type: 'warning',
title: t('caseManagement.caseReview.archivedTitle', { name: record.name }),
content: t('caseManagement.caseReview.archivedContent'),
okText: t('caseManagement.caseReview.archive'),
cancelText: t('common.cancel'),
onBeforeOk: async () => {
try {
// await resetUserPassword({
// selectIds,
// selectAll: !!params?.selectAll,
// excludeIds: params?.excludeIds || [],
// condition: { keyword: keyword.value },
// });
Message.success(t('caseManagement.caseReview.archiveSuccess'));
resetSelector();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
},
hideCancel: false,
});
}
const moveModalVisible = ref(false);
const selectedModuleKeys = ref<(string | number)[]>([]);
const batchMoveFileLoading = ref(false);
async function handleReviewMove() {
try {
batchMoveFileLoading.value = true;
// await batchMoveFile({
// selectIds: isBatchMove.value ? batchParams.value?.selectedIds || [] : [activeFile.value?.id || ''],
// selectAll: !!batchParams.value?.selectAll,
// excludeIds: batchParams.value?.excludeIds || [],
// condition: { keyword: keyword.value, combine: combine.value },
// projectId: appStore.currentProjectId,
// fileType: tableFileType.value,
// moduleIds: isMyOrAllFolder.value ? [] : [props.activeFolder],
// moveModuleId: selectedModuleKeys.value[0],
// });
Message.success(t('caseManagement.caseReview.batchMoveSuccess'));
tableSelected.value = [];
loadList();
resetSelector();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
} finally {
batchMoveFileLoading.value = false;
}
}
function handleMoveModalCancel() {
moveModalVisible.value = false;
selectedModuleKeys.value = [];
}
/**
* 处理文件夹树节点选中事件
*/
function folderNodeSelect(keys: (string | number)[]) {
selectedModuleKeys.value = keys;
}
/**
* 处理表格选中后批量操作
* @param event 批量操作事件对象
*/
function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) {
tableSelected.value = params?.selectedIds || [];
batchParams.value = params;
switch (event.eventTag) {
case 'move':
moveModalVisible.value = true;
break;
default:
break;
}
}
/**
* 处理表格更多按钮事件
* @param item
*/
function handleMoreActionSelect(item: ActionsItem, record: any) {
switch (item.eventTag) {
case 'delete':
activeRecord.value = record;
confirmReviewName.value = '';
dialogVisible.value = true;
break;
case 'archive':
handleArchive(record);
break;
default:
break;
}
}
function handleAddClick() {
console.log('handleAddClick');
}
function openDetail(id: string) {
router.push({
name: CaseManagementRouteEnum.CASE_MANAGEMENT_REVIEW_DETAIL,
query: {
id,
},
});
}
</script>
<style lang="less" scoped></style>

View File

@ -0,0 +1,116 @@
<template>
<MsColorLine
:color-data="[
{
percentage: (props.reviewDetail.passCount / props.reviewDetail.caseCount) * 100,
color: 'rgb(var(--success-6))',
},
{
percentage: (props.reviewDetail.failCount / props.reviewDetail.caseCount) * 100,
color: 'rgb(var(--danger-6))',
},
{
percentage: (props.reviewDetail.reviewCount / props.reviewDetail.caseCount) * 100,
color: 'rgb(var(--warning-6))',
},
{
percentage: (props.reviewDetail.reviewingCount / props.reviewDetail.caseCount) * 100,
color: 'rgb(var(--link-6))',
},
]"
:height="props.height"
:radius="props.radius"
>
<template #popoverContent>
<table>
<tr>
<td class="pr-[8px] text-[var(--color-text-4)]">{{ t('caseManagement.caseReview.progress') }}</td>
<td class="font-medium text-[var(--color-text-1)]">
{{
`${(
((props.reviewDetail.passCount + props.reviewDetail.failCount) / props.reviewDetail.caseCount) *
100
).toFixed(2)}%`
}}
<span
>({{
`${props.reviewDetail.passCount + props.reviewDetail.failCount}/${props.reviewDetail.caseCount}`
}})</span
>
</td>
</tr>
<tr>
<td class="popover-label-td">
<div class="mb-[2px] mr-[4px] h-[6px] w-[6px] rounded-full bg-[rgb(var(--success-6))]"></div>
<div>{{ t('caseManagement.caseReview.pass') }}</div>
</td>
<td class="popover-value-td">
{{ props.reviewDetail.passCount }}
</td>
</tr>
<tr>
<td class="popover-label-td">
<div class="mb-[2px] mr-[4px] h-[6px] w-[6px] rounded-full bg-[rgb(var(--danger-6))]"></div>
<div>{{ t('caseManagement.caseReview.fail') }}</div>
</td>
<td class="popover-value-td">
{{ props.reviewDetail.failCount }}
</td>
</tr>
<tr>
<td class="popover-label-td">
<div class="mb-[2px] mr-[4px] h-[6px] w-[6px] rounded-full bg-[rgb(var(--warning-6))]"></div>
<div>{{ t('caseManagement.caseReview.reReview') }}</div>
</td>
<td class="popover-value-td">
{{ props.reviewDetail.reviewCount }}
</td>
</tr>
<tr>
<td class="popover-label-td">
<div class="mb-[2px] mr-[4px] h-[6px] w-[6px] rounded-full bg-[rgb(var(--link-6))]"></div>
<div>{{ t('caseManagement.caseReview.reviewing') }}</div>
</td>
<td class="popover-value-td">
{{ props.reviewDetail.reviewingCount }}
</td>
</tr>
</table>
</template>
</MsColorLine>
</template>
<script setup lang="ts">
import MsColorLine from '@/components/pure/ms-color-line/index.vue';
import { useI18n } from '@/hooks/useI18n';
const props = defineProps<{
reviewDetail: {
passCount: number;
failCount: number;
reviewCount: number;
reviewingCount: number;
caseCount: number;
[key: string]: any;
};
height: string;
radius?: string;
}>();
const { t } = useI18n();
</script>
<style lang="less" scoped>
.popover-label-td {
@apply flex items-center;
padding: 8px 8px 0 0;
color: var(--color-text-4);
}
.popover-value-td {
@apply font-medium;
padding-top: 8px;
color: var(--color-text-1);
}
</style>

View File

@ -0,0 +1,41 @@
<template>
<a-tag :color="statusMap[props.status]?.color" :class="statusMap[props.status]?.class">
{{ t(statusMap[props.status]?.label) }}
</a-tag>
</template>
<script setup lang="ts">
import { useI18n } from '@/hooks/useI18n';
export type StatusMap = 0 | 1 | 2 | 3;
const props = defineProps<{
status: StatusMap;
}>();
const { t } = useI18n();
const statusMap = {
0: {
label: 'caseManagement.caseReview.unStart',
color: 'var(--color-text-n8)',
class: '!text-[var(--color-text-1)]',
},
1: {
label: 'caseManagement.caseReview.going',
color: 'rgb(var(--link-2))',
class: '!text-[rgb(var(--link-6))]',
},
2: {
label: 'caseManagement.caseReview.finished',
color: 'rgb(var(--success-2))',
class: '!text-[rgb(var(--success-6))]',
},
3: {
label: 'caseManagement.caseReview.archived',
color: 'var(--color-text-n8)',
class: '!text-[var(--color-text-4)]',
},
} as const;
</script>
<style lang="less" scoped></style>

View File

@ -0,0 +1,317 @@
<!-- eslint-disable vue/no-v-html -->
<template>
<MsCard
:title="isEdit ? t('menu.caseManagement.caseManagementCaseReviewEdit') : t('caseManagement.caseReview.create')"
>
<a-form ref="reviewFormRef" class="w-[732px]" :model="reviewForm" layout="vertical">
<a-form-item
field="name"
:label="t('caseManagement.caseReview.reviewName')"
:rules="[{ required: true, message: t('caseManagement.caseReview.reviewNameRequired') }]"
asterisk-position="end"
>
<a-input
v-model:modelValue="reviewForm.name"
:placeholder="t('caseManagement.caseReview.reviewNamePlaceholder')"
:max-length="255"
show-word-limit
/>
</a-form-item>
<a-form-item field="desc" :label="t('caseManagement.caseReview.desc')">
<a-textarea
v-model:modelValue="reviewForm.desc"
:placeholder="t('caseManagement.caseReview.descPlaceholder')"
:max-length="1000"
show-word-limit
/>
</a-form-item>
<a-form-item field="folderId" :label="t('caseManagement.caseReview.belongModule')">
<a-select
v-model:modelValue="reviewForm.folderId"
:placeholder="t('caseManagement.caseReview.belongModulePlaceholder')"
:options="moduleOptions"
class="w-[436px]"
allow-search
multiple
/>
</a-form-item>
<a-form-item field="type" :label="t('caseManagement.caseReview.type')">
<a-radio-group v-model:modelValue="reviewForm.type">
<a-radio value="single">
<div class="flex items-center">
{{ t('caseManagement.caseReview.single') }}
<a-tooltip :content="t('caseManagement.caseReview.singleTip')" position="right">
<icon-question-circle
class="ml-[4px] text-[var(--color-text-4)] hover:text-[rgb(var(--primary-5))]"
size="16"
/>
</a-tooltip>
</div>
</a-radio>
<a-radio value="multi">
<div class="flex items-center">
{{ t('caseManagement.caseReview.multi') }}
<a-tooltip :content="t('caseManagement.caseReview.multiTip')" position="right">
<icon-question-circle
class="ml-[4px] text-[var(--color-text-4)] hover:text-[rgb(var(--primary-5))]"
size="16"
/>
</a-tooltip>
</div>
</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item
field="reviewers"
:rules="[{ required: true, message: t('caseManagement.caseReview.defaultReviewerRequired') }]"
asterisk-position="end"
>
<template #label>
<div class="inline-flex items-center">
{{ t('caseManagement.caseReview.defaultReviewer') }}
<a-tooltip :content="t('caseManagement.caseReview.defaultReviewerTip')" position="right">
<icon-question-circle
class="ml-[4px] text-[var(--color-text-4)] hover:text-[rgb(var(--primary-5))]"
size="16"
/>
</a-tooltip>
</div>
</template>
<MsSelect
v-model:modelValue="reviewForm.reviewers"
mode="static"
:placeholder="t('caseManagement.caseReview.reviewerPlaceholder')"
:options="reviewersOptions"
:search-keys="['label']"
allow-search
multiple
/>
</a-form-item>
<a-form-item field="tags" :label="t('caseManagement.caseReview.tag')">
<MsTagsInput v-model:model-value="reviewForm.tags" />
</a-form-item>
<a-form-item field="cycle" :label="t('caseManagement.caseReview.cycle')">
<a-range-picker
v-model:model-value="reviewForm.cycle"
show-time
:time-picker-props="{
defaultValue: ['00:00:00', '00:00:00'],
}"
class="w-[436px]"
/>
</a-form-item>
<a-form-item v-if="!isEdit">
<template #label>
<div class="flex items-center">
<div>{{ t('caseManagement.caseReview.pickCases') }}</div>
<a-divider margin="4px" direction="vertical" />
<MsButton type="text" :disabled="selectedAssociateCases.length === 0" @click="clearSelectedCases">
{{ t('caseManagement.caseReview.clearSelectedCases') }}
</MsButton>
</div>
</template>
<div class="bg-[var(--color-text-n9)] p-[12px]">
<div class="flex items-center">
<div class="text-[var(--color-text-2)]">
{{ t('caseManagement.caseReview.selectedCases', { count: selectedAssociateCases.length }) }}
</div>
<a-divider margin="8px" direction="vertical" />
<MsButton type="text" class="font-medium" @click="caseAssociateVisible = true">
{{ t('ms.case.associate.title') }}
</MsButton>
</div>
</div>
</a-form-item>
</a-form>
<template #footerRight>
<div class="flex items-center">
<a-button type="secondary" @click="cancelCreate">{{ t('common.cancel') }}</a-button>
<a-button v-if="isEdit" type="primary" class="ml-[16px]" @click="updateReview">
{{ t('common.update') }}
</a-button>
<template v-else>
<a-button type="secondary" class="mx-[16px]" @click="() => saveReview()">{{ t('common.save') }}</a-button>
<a-button type="primary" @click="() => saveReview(true)">
{{ t('caseManagement.caseReview.review') }}
</a-button>
</template>
</div>
</template>
</MsCard>
<MsCaseAssociate
v-model:visible="caseAssociateVisible"
v-model:project="caseAssociateProject"
:ok-button-disabled="associateForm.reviewers.length === 0"
@success="writeAssociateCases"
>
<template #footerLeft>
<a-form ref="associateFormRef" :model="associateForm">
<a-form-item
field="reviewers"
:rules="[{ required: true, message: t('caseManagement.caseReview.reviewerRequired') }]"
class="mb-0"
>
<template #label>
<div class="inline-flex items-center">
{{ t('caseManagement.caseReview.reviewer') }}
<a-tooltip position="right">
<template #content>
<div>{{ t('caseManagement.caseReview.switchProject') }}</div>
<div>{{ t('caseManagement.caseReview.resetReviews') }}</div>
<div>
{{ t('caseManagement.caseReview.reviewsTip') }}
<span class="cursor-pointer text-[rgb(var(--primary-4))]" @click="goProjectManagement">
{{ t('menu.projectManagement') }}
</span>
{{ t('caseManagement.caseReview.reviewsTip2') }}
</div>
</template>
<icon-question-circle
class="ml-[4px] text-[var(--color-text-4)] hover:text-[rgb(var(--primary-5))]"
size="16"
/>
</a-tooltip>
</div>
</template>
<MsSelect
v-model:modelValue="associateForm.reviewers"
mode="static"
:placeholder="t('caseManagement.caseReview.reviewerPlaceholder')"
:options="reviewersOptions"
:search-keys="['label']"
allow-search
allow-clear
multiple
class="w-[300px]"
>
</MsSelect>
</a-form-item>
</a-form>
</template>
</MsCaseAssociate>
</template>
<script setup lang="ts">
import { useRoute, useRouter } from 'vue-router';
import { Message } from '@arco-design/web-vue';
import MsButton from '@/components/pure/ms-button/index.vue';
import MsCard from '@/components/pure/ms-card/index.vue';
import MsTagsInput from '@/components/pure/ms-tags-input/index.vue';
import MsCaseAssociate from '@/components/business/ms-case-associate/index.vue';
import MsSelect from '@/components/business/ms-select';
import { useI18n } from '@/hooks/useI18n';
import { CaseManagementRouteEnum, ProjectManagementRouteEnum } from '@/enums/routeEnum';
import type { FormInstance } from '@arco-design/web-vue';
const route = useRoute();
const router = useRouter();
const { t } = useI18n();
const isEdit = ref(!!route.query.id);
const reviewFormRef = ref<FormInstance>();
const reviewForm = ref({
name: '',
desc: '',
folderId: '',
type: 'single',
reviewers: [],
tags: [],
cycle: [],
});
const moduleOptions = ref([
{
label: '全部',
value: 'all',
},
{
label: '模块1',
value: '1',
},
{
label: '模块2',
value: '2',
},
]);
const reviewersOptions = ref([
{
label: '张三',
value: '1',
},
{
label: '李四',
value: '2',
},
{
label: '王五',
value: '3',
},
]);
const selectedAssociateCases = ref<string[]>([]);
function writeAssociateCases(ids: string[]) {
selectedAssociateCases.value = [...ids];
}
function clearSelectedCases() {
selectedAssociateCases.value = [];
}
function cancelCreate() {
router.back();
}
function saveReview(isGoReview = false) {
reviewFormRef.value?.validate(async (errors) => {
if (!errors) {
Message.success(t('common.createSuccess'));
if (isGoReview) {
//
router.replace({
name: CaseManagementRouteEnum.CASE_MANAGEMENT_REVIEW,
});
} else {
router.replace({
name: CaseManagementRouteEnum.CASE_MANAGEMENT_REVIEW,
});
}
}
});
}
function updateReview() {
reviewFormRef.value?.validate(async (errors) => {
if (!errors) {
Message.success(t('common.updateSuccess'));
router.replace({
name: CaseManagementRouteEnum.CASE_MANAGEMENT_REVIEW,
});
}
});
}
const caseAssociateVisible = ref<boolean>(false);
const caseAssociateProject = ref('');
const associateForm = ref({
reviewers: [],
});
const associateFormRef = ref<FormInstance>();
function goProjectManagement() {
window.open(
`${window.location.origin}#${
router.resolve({ name: ProjectManagementRouteEnum.PROJECT_MANAGEMENT_PERMISSION_USER_GROUP }).fullPath
}`
);
}
</script>
<style lang="less" scoped>
:deep(.arco-form-item-label-col) {
@apply w-auto flex-none;
}
</style>

View File

@ -0,0 +1,213 @@
<template>
<MsCard :min-width="1100" auto-height hide-footer no-bottom-radius no-content-padding hide-divider>
<template #headerLeft>
<a-tooltip :content="reviewDetail.name">
<div class="one-line-text mr-[8px] max-w-[260px] font-medium text-[var(--color-text-000)]">
{{ reviewDetail.name }}
</div>
</a-tooltip>
<div
class="rounded-[0_999px_999px_0] border border-solid border-[text-[rgb(var(--primary-5))]] px-[8px] py-[2px] text-[12px] leading-[16px] text-[rgb(var(--primary-5))]"
>
<MsIcon type="icon-icon-contacts" size="13" />
{{ t('caseManagement.caseReview.single') }}
</div>
<statusTag :status="(reviewDetail.status as StatusMap)" class="mx-[16px]" />
<MsPrevNextButton
ref="prevNextButtonRef"
v-model:loading="loading"
:page-change="pageChange"
:pagination="pagination"
:get-detail-func="getDetailFunc"
:detail-id="route.query.id as string"
:detail-index="detailIndex"
:table-data="tableData"
@loaded="loaded"
/>
</template>
<template #headerRight>
<div class="mr-[16px] flex items-center">
<a-switch v-model:model-value="onlyMine" size="small" class="mr-[8px]" />
{{ t('caseManagement.caseReview.onlyMine') }}
</div>
<MsButton type="button" status="default">
<MsIcon type="icon-icon_link-record_outlined1" class="mr-[8px]" />
{{ t('ms.case.associate.title') }}
</MsButton>
<MsButton type="button" status="default">
<MsIcon type="icon-icon_edit_outlined" class="mr-[8px]" />
{{ t('common.edit') }}
</MsButton>
<MsButton type="button" status="default">
<MsIcon type="icon-icon_copy_outlined" class="mr-[8px]" />
{{ t('common.copy') }}
</MsButton>
<MsButton type="button" status="default">
<MsIcon type="icon-icon_collection_outlined" class="mr-[8px]" />
{{ t('common.fork') }}
</MsButton>
<MsTableMoreAction :list="moreAction">
<MsButton type="button" status="default">
<MsIcon type="icon-icon_more_outlined" class="mr-[8px]" />
{{ t('common.more') }}
</MsButton>
</MsTableMoreAction>
</template>
<template #subHeader>
<div class="mt-[16px] w-[476px]">
<div class="mb-[4px] flex items-center gap-[24px]">
<div class="text-[var(--color-text-4)]">
<span class="mr-[8px]">{{ t('caseManagement.caseReview.reviewedCase') }}</span>
<span v-if="reviewDetail.status === 0" class="text-[var(--color-text-1)]">-</span>
<span v-else>
<span class="text-[var(--color-text-1)]">{{ reviewDetail.reviewCount }}/</span
>{{ reviewDetail.caseCount }}
</span>
</div>
<div class="text-[var(--color-text-4)]">
<span class="mr-[8px]">{{ t('caseManagement.caseReview.passRate') }}</span>
<span v-if="reviewDetail.status === 0" class="text-[var(--color-text-1)]">-</span>
<span v-else>
<span class="text-[var(--color-text-1)]">
{{ ((reviewDetail.reviewCount / reviewDetail.caseCount) * 100).toFixed(2) }}%
</span>
</span>
</div>
</div>
<passRateLine :review-detail="reviewDetail" height="8px" radius="var(--border-radius-mini)" />
</div>
</template>
<div class="px-[24px]">
<a-divider class="my-0" />
<a-tabs v-model:active-key="showTab" class="no-content">
<a-tab-pane v-for="item of tabList" :key="item.key" :title="item.title" />
</a-tabs>
</div>
</MsCard>
<MsCard class="mt-[16px]" :special-height="180" simple has-breadcrumb no-content-padding>
<MsSplitBox>
<template #left>
<div class="p-[24px]">
<CaseTree ref="folderTreeRef" @folder-node-select="handleFolderNodeSelect" />
</div>
</template>
<template #right>
<CaseTable :active-folder="activeFolderId"></CaseTable>
</template>
</MsSplitBox>
</MsCard>
</template>
<script setup lang="ts">
import { useRoute, useRouter } from 'vue-router';
import MsButton from '@/components/pure/ms-button/index.vue';
import MsCard from '@/components/pure/ms-card/index.vue';
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
import MsSplitBox from '@/components/pure/ms-split-box/index.vue';
import MsTableMoreAction from '@/components/pure/ms-table-more-action/index.vue';
import { ActionsItem } from '@/components/pure/ms-table-more-action/types';
import MsPrevNextButton from '@/components/business/ms-prev-next-button/index.vue';
import CaseTable from './components/detail/caseTable.vue';
import CaseTree from './components/detail/caseTree.vue';
import passRateLine from './components/passRateLine.vue';
import statusTag, { StatusMap } from './components/statusTag.vue';
import { useI18n } from '@/hooks/useI18n';
const router = useRouter();
const route = useRoute();
const { t } = useI18n();
const loading = ref(false);
const reviewDetail = ref({
name: '具体的用例评审的名称最大宽度260px,超过展示省略号啦',
status: 2,
caseCount: 100,
passCount: 0,
failCount: 10,
reviewCount: 20,
reviewingCount: 25,
});
const onlyMine = ref(false);
const moreAction = ref<ActionsItem[]>([]);
const fullActions = [
{
label: t('caseManagement.caseReview.archive'),
eventTag: 'archive',
icon: 'icon-icon-draft',
},
{
label: t('common.export'),
eventTag: 'export',
icon: 'icon-icon_upload_outlined',
},
{
label: t('caseManagement.caseReview.createTestPlan'),
eventTag: 'createTestPlan',
icon: 'icon-icon_add_outlined-1',
},
{
isDivider: true,
},
{
label: t('common.delete'),
eventTag: 'delete',
icon: 'icon-icon_delete-trash_outlined1',
danger: true,
},
];
onBeforeMount(() => {
if (reviewDetail.value.status === 2) {
moreAction.value = [...fullActions];
} else if (reviewDetail.value.status === 3) {
moreAction.value = fullActions.filter((e) => e.eventTag === 'delete');
} else {
moreAction.value = fullActions.filter((e) => e.eventTag !== 'archive');
}
});
const showTab = ref(0);
const tabList = ref([
{
key: 0,
title: t('menu.caseManagement.featureCase'),
},
]);
const pagination = ref({
current: 1,
pageSize: 10,
total: 0,
});
const detailIndex = ref(0);
const tableData = ref([]);
async function getDetailFunc() {
console.log('getDetailFunc');
}
async function pageChange() {
console.log('page');
}
function loaded(e: any) {
loading.value = false;
reviewDetail.value = e;
}
const folderTreeRef = ref<InstanceType<typeof CaseTree>>();
const activeFolderId = ref<string | number>('all');
function handleFolderNodeSelect(ids: (string | number)[]) {
[activeFolderId.value] = ids;
}
</script>
<style lang="less" scoped>
:deep(.arco-tabs-content) {
@apply hidden;
}
</style>

View File

@ -0,0 +1,69 @@
<template>
<MsCard simple no-content-padding>
<div class="flex items-center justify-between border-b border-[var(--color-text-n8)] p-[24px_24px_16px_24px]">
<a-button type="primary" @click="goCreateReview">{{ t('caseManagement.caseReview.create') }}</a-button>
<a-radio-group v-model:model-value="showType" type="button" class="file-show-type" @change="changeShowType">
<a-radio value="all">{{ t('common.all') }}</a-radio>
<a-radio value="wait">{{ t('caseManagement.caseReview.waitMyReview') }}</a-radio>
<a-radio value="create">{{ t('caseManagement.caseReview.myCreate') }}</a-radio>
</a-radio-group>
</div>
<div class="relative h-[calc(100%-73px)]">
<MsSplitBox>
<template #left>
<div class="px-[24px] py-[16px]">
<ModuleTree ref="folderTreeRef" @folder-node-select="handleFolderNodeSelect" />
</div>
</template>
<template #right>
<ReviewTable :active-folder="activeFolderId" />
</template>
</MsSplitBox>
</div>
</MsCard>
</template>
<script setup lang="ts">
import { useRouter } from 'vue-router';
import MsCard from '@/components/pure/ms-card/index.vue';
import MsSplitBox from '@/components/pure/ms-split-box/index.vue';
import ModuleTree from './components/index/moduleTree.vue';
import ReviewTable from './components/index/reviewTable.vue';
import { useI18n } from '@/hooks/useI18n';
import { CaseManagementRouteEnum } from '@/enums/routeEnum';
const router = useRouter();
const { t } = useI18n();
type ShowType = 'all' | 'wait' | 'create';
const showType = ref<ShowType>('all');
function changeShowType(val: string | number | boolean) {
console.log('changeShowType', val);
}
const folderTreeRef = ref<InstanceType<typeof ModuleTree>>();
const activeFolderId = ref<string | number>('all');
function handleFolderNodeSelect(ids: (string | number)[]) {
[activeFolderId.value] = ids;
}
function goCreateReview() {
router.push({
name: CaseManagementRouteEnum.CASE_MANAGEMENT_REVIEW_CREATE,
query:
activeFolderId.value === 'all'
? {}
: {
moduleId: activeFolderId.value,
},
});
}
</script>
<style lang="less" scoped></style>

View File

@ -0,0 +1,81 @@
export default {
'caseManagement.caseReview.create': 'Create review',
'caseManagement.caseReview.waitMyReview': 'Awaiting my review',
'caseManagement.caseReview.myCreate': 'I created',
'caseManagement.caseReview.searchPlaceholder': 'Search by ID or name',
'caseManagement.caseReview.archive': 'Archive',
'caseManagement.caseReview.tableNoData': 'No data yet, please',
'caseManagement.caseReview.name': 'Review name',
'caseManagement.caseReview.creator': 'Creator',
'caseManagement.caseReview.reviewer': 'Reviewer',
'caseManagement.caseReview.reviewerRequired': 'Please select at least one reviewer',
'caseManagement.caseReview.type': 'Review criteria',
'caseManagement.caseReview.status': 'Review status',
'caseManagement.caseReview.caseCount': 'Use case number',
'caseManagement.caseReview.passRate': 'Passing rate',
'caseManagement.caseReview.tag': 'Tag',
'caseManagement.caseReview.module': 'Module',
'caseManagement.caseReview.cycle': 'Review cycle',
'caseManagement.caseReview.unStart': 'Not started',
'caseManagement.caseReview.going': 'Processing',
'caseManagement.caseReview.finished': 'Completed',
'caseManagement.caseReview.archived': 'Archived',
'caseManagement.caseReview.progress': 'Review progress',
'caseManagement.caseReview.pass': 'Pass',
'caseManagement.caseReview.fail': 'Reject',
'caseManagement.caseReview.reReview': 'Re-arraignment',
'caseManagement.caseReview.reviewing': 'Under review',
'caseManagement.caseReview.single': 'Single reviewer',
'caseManagement.caseReview.singleTip': 'The last review result is the final review result',
'caseManagement.caseReview.multi': 'Multiple reviewers',
'caseManagement.caseReview.multiTip': 'If all reviewers pass the review, then it passes',
'caseManagement.caseReview.desc': 'Description',
'caseManagement.caseReview.passRateTip': 'Passed use cases/all use cases*100%',
'caseManagement.caseReview.deleteReviewTitle': 'Are you sure you want to delete {name}?',
'caseManagement.caseReview.deleteReviewContent':
'The review {status}, the data will not be recoverable after deletion, please operate with caution!',
'caseManagement.caseReview.deleteReviewingContent':
'The review is in progress. Once deleted, the review will be terminated and the data cannot be recovered. Please operate with caution!',
'caseManagement.caseReview.deleteFinishedReviewContent1':
'This review is a completed review, and you can choose to archive it. After archiving, the use case review will not be displayed in the list, and the use case information and review results will be retained;',
'caseManagement.caseReview.deleteFinishedReviewContent2':
'If you continue to delete, the data will not be restored, so please operate with caution!',
'caseManagement.caseReview.deleteReviewPlaceholder': 'Please enter the name of the review',
'caseManagement.caseReview.archivedTitle': 'Are you sure you want to archive {name}?',
'caseManagement.caseReview.archivedContent':
'After archiving, the review information will no longer be updated and cannot be edited. The operation is irreversible, so please operate with caution!',
'caseManagement.caseReview.archiveSuccess': 'Archived successfully',
'caseManagement.caseReview.move': 'Move to',
'caseManagement.caseReview.batchMove': 'Batch move',
'caseManagement.caseReview.batchMoveConfirm': 'Move {count} use cases to the selected module',
'caseManagement.caseReview.batchMoveTitleSub': '({count} reviews selected)',
'caseManagement.caseReview.batchMoveSuccess': 'Review moved successfully',
'caseManagement.caseReview.folderSearchPlaceholder': 'Please enter a group name',
'caseManagement.caseReview.allReviews': 'All reviews',
'caseManagement.caseReview.noReviews': 'No matching review data yet',
'caseManagement.caseReview.deleteFolderTipTitle': 'Remove the `{name}` module?',
'caseManagement.caseReview.deleteFolderTipContent':
'This operation will delete the module and all resources under it, please operate with caution!',
'caseManagement.caseReview.deleteConfirm': 'Confirm delete',
'caseManagement.caseReview.deleteSuccess': 'Delete successful',
'caseManagement.caseReview.moduleMoveSuccess': 'Module moved successfully',
'caseManagement.caseReview.review': 'Review',
'caseManagement.caseReview.reviewName': 'Review Name',
'caseManagement.caseReview.reviewNamePlaceholder': 'Please enter review name',
'caseManagement.caseReview.reviewNameRequired': 'Review name cannot be empty',
'caseManagement.caseReview.descPlaceholder': 'Please describe this review',
'caseManagement.caseReview.belongModule': 'Belonging module',
'caseManagement.caseReview.belongModulePlaceholder': 'Please select the module to which the use case belongs',
'caseManagement.caseReview.reviewerPlaceholder': 'Please select a reviewer',
'caseManagement.caseReview.defaultReviewer': 'Default reviewer',
'caseManagement.caseReview.defaultReviewerRequired': 'The default reviewer cannot be empty',
'caseManagement.caseReview.defaultReviewerTip': 'For newly added use cases, the reviewer is the default reviewer',
'caseManagement.caseReview.pickCases': 'Select use cases for review',
'caseManagement.caseReview.switchProject': 'Switch project:',
'caseManagement.caseReview.resetReviews': '1.Reset reviewer',
'caseManagement.caseReview.reviewsTip':
'2.The reviewer needs to have 2 project permissions at the same time; if there is no matching person,',
'caseManagement.caseReview.reviewsTip2': 'can set permissions',
'caseManagement.caseReview.clearSelectedCases': 'Clear selected use cases',
'caseManagement.caseReview.selectedCases': '{count} use cases selected',
};

View File

@ -0,0 +1,121 @@
export default {
'caseManagement.caseReview.create': '创建评审',
'caseManagement.caseReview.waitMyReview': '待我评审',
'caseManagement.caseReview.myCreate': '我创建的',
'caseManagement.caseReview.searchPlaceholder': '通过 ID 或名称搜索',
'caseManagement.caseReview.archive': '归档',
'caseManagement.caseReview.tableNoData': '暂无数据,请',
'caseManagement.caseReview.name': '评审名称',
'caseManagement.caseReview.creator': '创建人',
'caseManagement.caseReview.reviewer': '评审人',
'caseManagement.caseReview.reviewerRequired': '请至少选择一位评审人',
'caseManagement.caseReview.type': '评审标准',
'caseManagement.caseReview.status': '评审状态',
'caseManagement.caseReview.caseCount': '用例数量',
'caseManagement.caseReview.passRate': '通过率',
'caseManagement.caseReview.tag': '标签',
'caseManagement.caseReview.module': '所属模块',
'caseManagement.caseReview.cycle': '评审周期',
'caseManagement.caseReview.unStart': '未开始',
'caseManagement.caseReview.going': '进行中',
'caseManagement.caseReview.finished': '已完成',
'caseManagement.caseReview.archived': '已归档',
'caseManagement.caseReview.progress': '评审进度',
'caseManagement.caseReview.pass': '通过',
'caseManagement.caseReview.fail': '不通过',
'caseManagement.caseReview.reReview': '重新提审',
'caseManagement.caseReview.reviewing': '评审中',
'caseManagement.caseReview.single': '单人评审',
'caseManagement.caseReview.singleTip': '最后一次评审结果,为最终审结果',
'caseManagement.caseReview.multi': '多人评审',
'caseManagement.caseReview.multiTip': '所有评审人评审通过则通过',
'caseManagement.caseReview.desc': '描述',
'caseManagement.caseReview.passRateTip': '已通过用例/全部用例*100%',
'caseManagement.caseReview.deleteReviewTitle': '确认删除 {name} 吗?',
'caseManagement.caseReview.deleteReviewContent': '该评审 {status},删除后数据将不可恢复,请谨慎操作!',
'caseManagement.caseReview.deleteReviewingContent': '该评审进行中,删除后,将终止评审且数据不可恢复,请谨慎操作!',
'caseManagement.caseReview.deleteFinishedReviewContent1':
'该评审为 已完成 评审,可以选择归档,归档后用例评审将不在列表展示,用例信息及评审结果都将被保留;',
'caseManagement.caseReview.deleteFinishedReviewContent2': '若继续删除,数据将不会恢复,请谨慎操作!',
'caseManagement.caseReview.deleteReviewPlaceholder': '请输入评审名称',
'caseManagement.caseReview.archivedTitle': '确定归档 {name} 吗?',
'caseManagement.caseReview.archivedContent': '归档后,评审信息将不再更新且不可编辑,操作不可逆,请谨慎操作!',
'caseManagement.caseReview.archiveSuccess': '归档成功',
'caseManagement.caseReview.move': '移动到',
'caseManagement.caseReview.batchMove': '批量移动',
'caseManagement.caseReview.batchMoveConfirm': '移动 {count} 个用例至已选模块 ',
'caseManagement.caseReview.batchMoveTitleSub': '(已选 {count} 条评审) ',
'caseManagement.caseReview.batchMoveSuccess': '评审移动成功',
'caseManagement.caseReview.folderSearchPlaceholder': '请输入分组名称',
'caseManagement.caseReview.allReviews': '全部评审',
'caseManagement.caseReview.noReviews': '暂无匹配的评审数据',
'caseManagement.caseReview.deleteFolderTipTitle': '是否删除 `{name}` 模块?',
'caseManagement.caseReview.deleteFolderTipContent': '该操作会删除模块及其下所有资源,请谨慎操作!',
'caseManagement.caseReview.deleteConfirm': '确认删除',
'caseManagement.caseReview.deleteSuccess': '删除成功',
'caseManagement.caseReview.moduleMoveSuccess': '模块移动成功',
'caseManagement.caseReview.review': '评审',
'caseManagement.caseReview.reviewName': '评审名称',
'caseManagement.caseReview.reviewNamePlaceholder': '请输入评审名称',
'caseManagement.caseReview.reviewNameRequired': '评审名称不能为空',
'caseManagement.caseReview.descPlaceholder': '请对该评审进行描述',
'caseManagement.caseReview.belongModule': '所属模块',
'caseManagement.caseReview.belongModulePlaceholder': '请选择该用例所属模块',
'caseManagement.caseReview.reviewerPlaceholder': '请选择评审人',
'caseManagement.caseReview.defaultReviewer': '默认评审人',
'caseManagement.caseReview.defaultReviewerRequired': '默认评审人',
'caseManagement.caseReview.defaultReviewerTip': '新添加的用例,评审人为默认评审人',
'caseManagement.caseReview.pickCases': '选择需要评审的用例',
'caseManagement.caseReview.switchProject': '切换项目:',
'caseManagement.caseReview.resetReviews': '1.重置评审人',
'caseManagement.caseReview.reviewsTip': '2.评审人需要同时拥有 2 个项目权限;若无匹配人员,',
'caseManagement.caseReview.reviewsTip2': '可设置权限',
'caseManagement.caseReview.clearSelectedCases': '清空已选用例',
'caseManagement.caseReview.selectedCases': '已选 {count} 条用例',
'caseManagement.caseReview.onlyMine': '只看我的',
'caseManagement.caseReview.createTestPlan': '创建测试计划',
'caseManagement.caseReview.reviewedCase': '已评用例',
'caseManagement.caseReview.createCase': '创建用例',
'caseManagement.caseReview.allCases': '全部用例',
'caseManagement.caseReview.noCases': '暂无匹配的用例数据',
'caseManagement.caseReview.caseName': '用例名称',
'caseManagement.caseReview.reviewResult': '评审结果',
'caseManagement.caseReview.reviewResultTip': '“只看我的”开启时,可在列表上查看我的评审结果',
'caseManagement.caseReview.disassociate': '取消关联',
'caseManagement.caseReview.disassociateConfirmTitle': '确认取消已选的 {count} 条用例吗?',
'caseManagement.caseReview.version': '版本',
'caseManagement.caseReview.unReview': '未评审',
'caseManagement.caseReview.reviewPass': '已通过',
'caseManagement.caseReview.disassociateTip': '确认取消关联关系吗?',
'caseManagement.caseReview.disassociateTipContent': '取消后,再次关联,评审结果为:未评审',
'caseManagement.caseReview.changeReviewer': '修改评审人',
'caseManagement.caseReview.batchReview': '批量评审',
'caseManagement.caseReview.selectedCase': '已选 {count} 条用例',
'caseManagement.caseReview.reason': '原因',
'caseManagement.caseReview.reasonRequired': '原因不能为空',
'caseManagement.caseReview.reasonPlaceholder': '请输入原因',
'caseManagement.caseReview.commitResult': '提交结果',
'caseManagement.caseReview.batchReviewTip': '修改评审结果为修改个人的评审结果',
'caseManagement.caseReview.chooseReviewer': '选择评审人',
'caseManagement.caseReview.batchChangeReviewer': '批量修改评审人',
'caseManagement.caseReview.append': '追加',
'caseManagement.caseReview.appendTip1': '开启:新增评审人',
'caseManagement.caseReview.appendTip2': '关闭:更新评审人',
'caseManagement.caseReview.myReview': '我的评审',
'caseManagement.caseReview.caseLevel': '用例等级',
'caseManagement.caseReview.caseVersion': '用例版本',
'caseManagement.caseReview.caseStatus': '用例状态',
'caseManagement.caseReview.responsiblePerson': '责任人',
'caseManagement.caseReview.createTime': '创建时间',
'caseManagement.caseReview.caseBaseInfo': '基本信息',
'caseManagement.caseReview.caseDetail': '详情',
'caseManagement.caseReview.caseDemand': '需求',
'caseManagement.caseReview.startReview': '开始评审',
'caseManagement.caseReview.autoNext': '自动下一条',
'caseManagement.caseReview.autoNextTip1': '开启:提交评审结果后,跳转至下一条用例',
'caseManagement.caseReview.autoNextTip2': '关闭:提交评审结果后,还在当前',
'caseManagement.caseReview.suggestion': '建议',
'caseManagement.caseReview.suggestionTip': '不作为评审结果',
'caseManagement.caseReview.submitReview': '提交评审',
'caseManagement.caseReview.reviewHistory': '评审历史',
};

View File

@ -62,7 +62,7 @@
<a-spin class="h-full w-full" :loading="fileLoading">
<MsThumbnailCard
mode="hover"
:type="detail?.fileType"
:type="detail.fileType || ''"
:url="`${CompressImgUrl}/${userStore.id}/${detail.id}`"
:footer-text="t('project.fileManagement.replaceFile')"
@click="handleFileIconClick"
@ -137,7 +137,7 @@
</template>
</div>
<div class="file-relation">
<a-tabs v-model:active-key="activeTab" :disabled="loading" class="no-content">
<a-tabs v-model:active-key="activeTab" :disabled="loading" class="no-content" @change="() => loadTable()">
<a-tab-pane key="case" :title="t('project.fileManagement.cases')" />
<a-tab-pane key="version" :title="t('project.fileManagement.versionHistory')" />
</a-tabs>
@ -288,74 +288,6 @@
const fileType = ref('unknown');
const renameTitle = ref(''); //
function loadedFile(detail: FileDetail) {
if (detail.fileType) {
fileType.value = getFileEnum(`/${detail.fileType.toLowerCase()}`);
}
renameTitle.value = detail.name;
fileDescriptions.value = [
{
label: t('project.fileManagement.name'),
value: detail.name,
key: 'name',
},
{
label: t('project.fileManagement.desc'),
value: detail.description,
key: 'desc',
},
{
label: t('project.fileManagement.type'),
value: detail.fileType,
},
{
label: t('project.fileManagement.size'),
value: formatFileSize(detail.size),
},
{
label: t('project.fileManagement.creator'),
value: detail.createUser,
},
{
label: t('project.fileManagement.fileModule'),
value: detail.moduleName,
key: 'fileModule',
},
{
label: t('project.fileManagement.tag'),
value: detail.tags,
isTag: true,
showTagAdd: true,
closable: true,
key: 'tag',
},
{
label: t('project.fileManagement.createTime'),
value: dayjs(detail.createTime).format('YYYY-MM-DD HH:mm:ss'),
},
];
if (detail?.storage !== 'MINIO') {
fileDescriptions.value.splice(
3,
0,
...[
{
label: t('project.fileManagement.gitBranch'),
value: detail.branch || '',
},
{
label: t('project.fileManagement.gitPath'),
value: detail.filePath || '',
},
{
label: t('project.fileManagement.gitVersion'),
value: detail.fileVersion || '',
},
]
);
}
}
const fileLoading = ref(false);
watch(
() => newFile.value,
@ -430,7 +362,7 @@
{
title: 'project.fileManagement.id',
dataIndex: 'id',
width: 100,
showTooltip: true,
},
{
title: 'project.fileManagement.name',
@ -538,20 +470,91 @@
}
);
watchEffect(() => {
if (innerVisible.value) {
if (activeTab.value === 'case') {
setLoadListParams({
id: props.fileId,
});
loadCaseList();
} else {
setVersionLoadListParams({
id: props.fileId,
});
loadVersionList();
}
function loadTable() {
if (activeTab.value === 'case') {
setLoadListParams({
id: props.fileId,
});
loadCaseList();
} else {
setVersionLoadListParams({
id: props.fileId,
});
loadVersionList();
}
}
function loadedFile(detail: FileDetail) {
if (detail.fileType) {
fileType.value = getFileEnum(`/${detail.fileType.toLowerCase()}`);
}
renameTitle.value = detail.name;
fileDescriptions.value = [
{
label: t('project.fileManagement.name'),
value: detail.name,
key: 'name',
},
{
label: t('project.fileManagement.desc'),
value: detail.description,
key: 'desc',
},
{
label: t('project.fileManagement.type'),
value: detail.fileType,
},
{
label: t('project.fileManagement.size'),
value: formatFileSize(detail.size),
},
{
label: t('project.fileManagement.creator'),
value: detail.createUser,
},
{
label: t('project.fileManagement.fileModule'),
value: detail.moduleName,
key: 'fileModule',
},
{
label: t('project.fileManagement.tag'),
value: detail.tags,
isTag: true,
showTagAdd: true,
closable: true,
key: 'tag',
},
{
label: t('project.fileManagement.createTime'),
value: dayjs(detail.createTime).format('YYYY-MM-DD HH:mm:ss'),
},
];
if (detail?.storage !== 'MINIO') {
fileDescriptions.value.splice(
3,
0,
...[
{
label: t('project.fileManagement.gitBranch'),
value: detail.branch || '',
},
{
label: t('project.fileManagement.gitPath'),
value: detail.filePath || '',
},
{
label: t('project.fileManagement.gitVersion'),
value: detail.fileVersion || '',
},
]
);
}
loadTable();
}
watchEffect(() => {
if (!innerVisible.value) {
activeTab.value = 'case';
}
});

View File

@ -103,7 +103,7 @@
<MsDrawer v-model:visible="uploadDrawerVisible" :title="t('project.fileManagement.addFile')" :width="680">
<div class="mb-[8px] flex items-center justify-between text-[var(--color-text-1)]">
{{ t('project.fileManagement.fileType') }}
<div class="flex items-center text-[12px] text-[rgb(var(--warning-6))]">
<div class="flex items-center text-[12px] leading-[16px] text-[rgb(var(--warning-6))]">
<icon-exclamation-circle class="mr-[2px]" />
{{ t('project.fileManagement.fileTypeTip') }}
</div>
@ -476,6 +476,7 @@
title: 'project.fileManagement.size',
dataIndex: 'size',
slotName: 'size',
width: 120,
},
{
title: 'project.fileManagement.tag',
@ -486,11 +487,13 @@
title: 'project.fileManagement.creator',
dataIndex: 'creator',
showTooltip: true,
width: 120,
},
{
title: 'project.fileManagement.updater',
dataIndex: 'updateUser',
showTooltip: true,
width: 120,
},
{
title: 'project.fileManagement.updateTime',
@ -607,12 +610,7 @@
projectId: appStore.currentProjectId,
current: propsRes.value.msPagination?.current,
pageSize: propsRes.value.msPagination?.pageSize,
combine:
props.activeFolder === 'my'
? {
createUser: userStore.id,
}
: {},
combine: combine.value,
});
}
@ -1207,6 +1205,7 @@
.file-type-card-desc {
font-size: 12px;
color: var(--color-text-4);
line-height: 16px;
}
}
.file-type-card--active {

View File

@ -12,7 +12,7 @@
v-if="!props.isUpdatePreview"
class="flex items-center justify-between border-b border-[var(--color-text-n8)] p-[16px]"
>
<div class="text-[16px] font-medium text-[var(--color-text-1)]">
<div class="text-[16px] font-medium leading-[24px] text-[var(--color-text-1)]">
{{ t('project.messageManagement') }}
</div>
<icon-close size="12" />
@ -31,15 +31,19 @@
v-else-if="props.robot.platform === 'MAIL'"
class="preview-rounded w-[400px] bg-[var(--color-text-n9)] p-[12px] text-[14px]"
>
<div class="mb-[4px] text-[16px] font-medium text-[var(--color-text-1)]">
<div class="mb-[4px] text-[16px] font-medium leading-[24px] text-[var(--color-text-1)]">
{{ subject || '-' }}
</div>
<div class="mb-[8px] flex flex-col">
<div class="text-[12px] text-[var(--color-text-4)]">{{ t('project.messageManagement.emailSender') }}</div>
<div class="text-[12px] text-[var(--color-text-4)]">
<div class="text-[12px] leading-[16px] text-[var(--color-text-4)]">
{{ t('project.messageManagement.emailSender') }}
</div>
<div class="text-[12px] leading-[16px] text-[var(--color-text-4)]">
{{ `${t('project.messageManagement.emailSendTime')}${dayjs().format('YYYY-MM-DD HH:mm:ss')}` }}
</div>
<div class="text-[12px] text-[var(--color-text-4)]">{{ t('project.messageManagement.emailReceiver') }}</div>
<div class="text-[12px] leading-[16px] text-[var(--color-text-4)]">
{{ t('project.messageManagement.emailReceiver') }}
</div>
</div>
<div class="preview-rounded bg-white p-[16px] text-[var(--color-text-2)]" v-html="template || '-'"> </div>
</div>
@ -133,7 +137,7 @@
>
{{ t('project.messageManagement.robot') }}
</MsTag>
<div class="ml-[4px] text-[12px] text-[var(--color-text-4)]">
<div class="ml-[4px] text-[12px] leading-[16px] text-[var(--color-text-4)]">
{{ t('project.messageManagement.larkRobotTip') }}
</div>
</div>

View File

@ -24,10 +24,13 @@
/>
<div class="flex flex-col">
<div class="font-medium text-[var(--color-text-1)]">{{ robot.name }}</div>
<div v-if="['IN_SITE', 'MAIL'].includes(robot.platform)" class="text-[12px] text-[var(--color-text-4)]">
<div
v-if="['IN_SITE', 'MAIL'].includes(robot.platform)"
class="text-[12px] leading-[16px] text-[var(--color-text-4)]"
>
{{ robot.description }}
</div>
<div v-else class="flex flex-wrap items-center text-[12px] text-[var(--color-text-4)]">
<div v-else class="flex flex-wrap items-center text-[12px] leading-[16px] text-[var(--color-text-4)]">
<div class="mr-[16px]">
<a-tooltip position="tl" mini :content="robot.createUser">{{ robot.createUser }}</a-tooltip>
{{
@ -139,7 +142,7 @@
<MsFormItemSub :text="t('project.messageManagement.dingTalkCustomTip')" :show-fill-icon="false">
<MsButton
type="text"
class="ml-[8px] !text-[12px]"
class="ml-[8px] !text-[12px] leading-[16px]"
@click="openExternalLink('https://open.dingtalk.com/document/orgapp/custom-robot-access')"
>
<MsIcon type="icon-icon_share" size="12" class="mr-[4px]" />
@ -158,7 +161,7 @@
<MsFormItemSub :text="t('project.messageManagement.dingTalkEnterpriseTip')" :show-fill-icon="false">
<MsButton
type="text"
class="ml-[8px] !text-[12px]"
class="ml-[8px] !text-[12px] leading-[16px]"
@click="
openExternalLink(
'https://open.dingtalk.com/document/orgapp/the-creation-and-installation-of-the-application-robot-in-the'

View File

@ -1,7 +1,7 @@
<template>
<a-spin v-if="!projectVersionStatus" :loading="loading" class="h-full w-full min-w-[930px]">
<div class="flex h-full flex-col items-center p-[24px]">
<div class="mt-[200px] text-[16px] font-medium text-[var(--color-text-1)]">
<div class="mt-[200px] text-[16px] font-medium leading-[24px] text-[var(--color-text-1)]">
{{ t('project.projectVersion.version') }}
</div>
<div class="mt-[16px] text-[var(--color-text-4)]">{{ t('project.projectVersion.tip') }}</div>
@ -566,6 +566,7 @@
margin-top: 4px;
font-size: 12px;
color: var(--color-text-4);
line-height: 16px;
}
}
.statusTipContent {

View File

@ -127,7 +127,7 @@
{ label: 'menu.workbench', value: 'workstation' },
{ label: 'menu.testPlan', value: 'testPlan' },
{ label: 'menu.bugManagement', value: 'bugManagement' },
{ label: 'menu.featureTest', value: 'caseManagement' },
{ label: 'menu.caseManagement', value: 'caseManagement' },
{ label: 'menu.apiTest', value: 'apiTest' },
{ label: 'menu.uiTest', value: 'uiTest' },
{ label: 'menu.performanceTest', value: 'loadTest' },

View File

@ -602,7 +602,7 @@
title: 'system.config.auth.action',
slotName: 'action',
fixed: 'right',
width: 120,
width: 140,
dataIndex: 'operation',
showInTable: true,
},

View File

@ -95,7 +95,7 @@
</a-button>
</MsUpload>
</div>
<p class="text-[12px] text-[var(--color-text-4)]">{{ t('system.config.page.iconTip') }}</p>
<p class="text-[12px] leading-[16px] text-[var(--color-text-4)]">{{ t('system.config.page.iconTip') }}</p>
</div>
<div class="config-form-card">
<div class="mb-[8px] flex items-center justify-between">
@ -123,7 +123,9 @@
</a-button>
</MsUpload>
</div>
<p class="text-[12px] text-[var(--color-text-4)]">{{ t('system.config.page.loginLogoTip') }}</p>
<p class="text-[12px] leading-[16px] text-[var(--color-text-4)]">
{{ t('system.config.page.loginLogoTip') }}
</p>
</div>
<div class="config-form-card">
<div class="mb-[8px] flex items-center justify-between">
@ -151,7 +153,9 @@
</a-button>
</MsUpload>
</div>
<p class="text-[12px] text-[var(--color-text-4)]">{{ t('system.config.page.loginBgTip') }}</p>
<p class="text-[12px] leading-[16px] text-[var(--color-text-4)]">
{{ t('system.config.page.loginBgTip') }}
</p>
</div>
<a-form
ref="loginConfigFormRef"
@ -253,7 +257,9 @@
</a-button>
</MsUpload>
</div>
<p class="text-[12px] text-[var(--color-text-4)]">{{ t('system.config.page.platformLogoTip') }}</p>
<p class="text-[12px] leading-[16px] text-[var(--color-text-4)]">
{{ t('system.config.page.platformLogoTip') }}
</p>
</div>
<a-form
ref="platformConfigFormRef"

View File

@ -400,6 +400,14 @@
label: 'system.log.operateType.logout',
value: 'LOGOUT',
},
{
label: 'system.log.operateType.disassociate',
value: 'DISASSOCIATE',
},
{
label: 'system.log.operateType.archived',
value: 'ARCHIVED',
},
];
function resetFilter() {

View File

@ -29,6 +29,8 @@ export default {
'system.log.operateType.select': 'Select',
'system.log.operateType.recover': 'Recover',
'system.log.operateType.logout': 'Logout',
'system.log.operateType.disassociate': 'Disassociate',
'system.log.operateType.archived': 'Archived',
'system.log.log': 'Operation log',
'system.log.time': 'Operation time',
'system.log.content': 'in {module} under {range}',

View File

@ -29,6 +29,8 @@ export default {
'system.log.operateType.select': '选择',
'system.log.operateType.recover': '恢复',
'system.log.operateType.logout': '登出',
'system.log.operateType.disassociate': '取消关联',
'system.log.operateType.archived': '归档',
'system.log.log': '操作日志',
'system.log.time': '操作时间',
'system.log.content': '{operator} 在 {range} 下的 {module} 中 ',

View File

@ -126,7 +126,7 @@
{ label: 'menu.workbench', value: 'workstation' },
{ label: 'menu.testPlan', value: 'testPlan' },
{ label: 'menu.bugManagement', value: 'bugManagement' },
{ label: 'menu.featureTest', value: 'caseManagement' },
{ label: 'menu.caseManagement', value: 'caseManagement' },
{ label: 'menu.apiTest', value: 'apiTest' },
{ label: 'menu.uiTest', value: 'uiTest' },
{ label: 'menu.performanceTest', value: 'loadTest' },

View File

@ -113,7 +113,7 @@
:placeholder="t('system.resourcePool.uiGridPlaceholder')"
:max-length="250"
></a-input>
<div class="mt-[4px] text-[12px] text-[var(--color-text-4)]">
<div class="mt-[4px] text-[12px] leading-[16px] text-[var(--color-text-4)]">
{{ t('system.resourcePool.uiGridExample', { grid: defaultGrid }) }}
</div>
</a-form-item>
@ -164,7 +164,7 @@
<div class="font-semibold text-[var(--color-text-1)]">
{{ t('system.resourcePool.changeAddTypePopTitle') }}
</div>
<div class="mt-[8px] w-[290px] text-[12px] text-[var(--color-text-2)]">
<div class="mt-[8px] w-[290px] text-[12px] leading-[16px] text-[var(--color-text-2)]">
{{ t('system.resourcePool.changeAddTypeTip') }}
</div>
</template>
@ -202,7 +202,7 @@
</a-form-item>
</template>
</MsCodeEditor>
<div class="mb-[24px] text-[12px] text-[var(--color-text-4)]">
<div class="mb-[24px] text-[12px] leading-[16px] text-[var(--color-text-4)]">
{{ t('system.resourcePool.nodeConfigEditorTip') }}
</div>
</div>
@ -220,7 +220,7 @@
:placeholder="t('system.resourcePool.testResourceDTO.ipPlaceholder')"
:max-length="250"
></a-input>
<div class="mt-[4px] text-[12px] text-[var(--color-text-4)]">
<div class="mt-[4px] text-[12px] leading-[16px] text-[var(--color-text-4)]">
{{ t('system.resourcePool.testResourceDTO.ipSubTip', { ip: '100.0.0.100', domain: 'example.com' }) }}
</div>
</a-form-item>

View File

@ -134,7 +134,7 @@
</template>
<div v-if="importResult === 'success'" class="flex flex-col items-center justify-center">
<icon-check-circle-fill class="text-[32px] text-[rgb(var(--success-6))]" />
<div class="mb-[8px] mt-[16px] text-[16px] font-medium text-[var(--color-text-000)]">
<div class="mb-[8px] mt-[16px] text-[16px] font-medium leading-[24px] text-[var(--color-text-000)]">
{{ t('system.user.importSuccess') }}
</div>
<div class="sub-text">