feat(功能用例): 功能用例和用例回收站页面和本地联调
This commit is contained in:
parent
86ce86649a
commit
700003a01f
|
@ -79,18 +79,26 @@ export class MSAxios {
|
|||
/**
|
||||
* @description: 文件上传
|
||||
*/
|
||||
uploadFile<T = any>(config: AxiosRequestConfig, params: UploadFileParams, customFileKey = ''): Promise<T> {
|
||||
uploadFile<T = any>(
|
||||
config: AxiosRequestConfig,
|
||||
params: UploadFileParams,
|
||||
customFileKey = '',
|
||||
isMultiple = false
|
||||
): Promise<T> {
|
||||
const formData = new window.FormData();
|
||||
const fileName = params.fileList.length === 1 ? 'file' : 'files';
|
||||
|
||||
const fileName = isMultiple ? 'files' : 'file';
|
||||
if (customFileKey !== '') {
|
||||
params.fileList.forEach((file: File) => {
|
||||
formData.append(customFileKey, file);
|
||||
});
|
||||
} else {
|
||||
} else if (!isMultiple && !customFileKey) {
|
||||
params.fileList.forEach((file: File) => {
|
||||
formData.append(fileName, file);
|
||||
});
|
||||
} else {
|
||||
params.fileList.forEach((item: any) => {
|
||||
formData.append(fileName, item.file, item.file.name);
|
||||
});
|
||||
}
|
||||
if (params.request) {
|
||||
const requestData = JSON.stringify(params.request);
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
import MSR from '@/api/http/index';
|
||||
import {
|
||||
BatchCopyCaseUrl,
|
||||
BatchDeleteCaseUrl,
|
||||
BatchDeleteRecycleCaseListUrl,
|
||||
BatchEditCaseUrl,
|
||||
BatchMoveCaseUrl,
|
||||
CreateCaseModuleTreeUrl,
|
||||
CreateCaseUrl,
|
||||
DeleteCaseModuleTreeUrl,
|
||||
DeleteCaseUrl,
|
||||
DeleteRecycleCaseListUrl,
|
||||
DetailCaseUrl,
|
||||
GetAssociatedFilePageUrl,
|
||||
GetCaseListUrl,
|
||||
GetCaseModulesCountUrl,
|
||||
GetCaseModuleTreeUrl,
|
||||
GetDefaultTemplateFieldsUrl,
|
||||
GetRecycleCaseListUrl,
|
||||
GetRecycleCaseModulesCountUrl,
|
||||
GetTrashCaseModuleTreeUrl,
|
||||
MoveCaseModuleTreeUrl,
|
||||
RecoverRecycleCaseListUrl,
|
||||
RestoreCaseListUrl,
|
||||
UpdateCaseModuleTreeUrl,
|
||||
UpdateCaseUrl,
|
||||
} from '@/api/requrls/case-management/featureCase';
|
||||
|
||||
import type {
|
||||
AssociatedList,
|
||||
BatchDeleteType,
|
||||
BatchEditCaseType,
|
||||
BatchMoveOrCopyType,
|
||||
CaseManagementTable,
|
||||
CaseModuleQueryParams,
|
||||
CreateOrUpdateModule,
|
||||
DeleteCaseType,
|
||||
ModulesTreeType,
|
||||
MoveModules,
|
||||
UpdateModule,
|
||||
} from '@/models/caseManagement/featureCase';
|
||||
import type { CommonList, TableQueryParams } from '@/models/common';
|
||||
// 获取模块树
|
||||
export function getCaseModuleTree(projectId: string) {
|
||||
return MSR.get<ModulesTreeType[]>({ url: `${GetCaseModuleTreeUrl}/${projectId}` });
|
||||
}
|
||||
|
||||
// 创建模块树
|
||||
export function createCaseModuleTree(data: CreateOrUpdateModule) {
|
||||
return MSR.post({ url: CreateCaseModuleTreeUrl, data });
|
||||
}
|
||||
|
||||
// 更新模块树
|
||||
export function updateCaseModuleTree(data: UpdateModule) {
|
||||
return MSR.post({ url: UpdateCaseModuleTreeUrl, data });
|
||||
}
|
||||
|
||||
// 移动模块树
|
||||
export function moveCaseModuleTree(data: MoveModules) {
|
||||
return MSR.post({ url: MoveCaseModuleTreeUrl, data });
|
||||
}
|
||||
|
||||
// 回收站-模块-获取模块树
|
||||
export function getTrashCaseModuleTree(projectId: string) {
|
||||
return MSR.get<ModulesTreeType[]>({ url: `${GetTrashCaseModuleTreeUrl}/${projectId}` });
|
||||
}
|
||||
|
||||
// 删除模块
|
||||
export function deleteCaseModuleTree(id: string) {
|
||||
return MSR.get({ url: `${DeleteCaseModuleTreeUrl}/${id}` });
|
||||
}
|
||||
|
||||
// 用例分页表
|
||||
export function getCaseList(data: TableQueryParams) {
|
||||
return MSR.post<CommonList<CaseManagementTable>>({ url: GetCaseListUrl, data });
|
||||
}
|
||||
// 删除用例
|
||||
export function deleteCaseRequest(data: DeleteCaseType) {
|
||||
return MSR.post({ url: `${DeleteCaseUrl}`, data });
|
||||
}
|
||||
// 获取默认模版自定义字段
|
||||
export function getCaseDefaultFields(projectId: string) {
|
||||
return MSR.get({ url: `${GetDefaultTemplateFieldsUrl}/${projectId}` });
|
||||
}
|
||||
// 获取关联文件列表
|
||||
export function getAssociatedFileListUrl(data: TableQueryParams) {
|
||||
return MSR.post<CommonList<AssociatedList>>({ url: GetAssociatedFilePageUrl, data });
|
||||
}
|
||||
// 创建用例
|
||||
export function createCaseRequest(data: Record<string, any>) {
|
||||
return MSR.uploadFile({ url: CreateCaseUrl }, { request: data.request, fileList: data.fileList }, '', true);
|
||||
}
|
||||
// 编辑用例
|
||||
export function updateCaseRequest(data: Record<string, any>) {
|
||||
return MSR.uploadFile({ url: UpdateCaseUrl }, { request: data.request, fileList: data.fileList }, '', true);
|
||||
}
|
||||
// 用例详情
|
||||
export function getCaseDetail(id: string) {
|
||||
return MSR.get({ url: `${DetailCaseUrl}/${id}` });
|
||||
}
|
||||
// 批量删除用例
|
||||
export function batchDeleteCase(data: BatchDeleteType) {
|
||||
return MSR.post({ url: `${BatchDeleteCaseUrl}`, data });
|
||||
}
|
||||
// 批量编辑属性
|
||||
export function batchEditAttrs(data: BatchEditCaseType) {
|
||||
return MSR.post({ url: `${BatchEditCaseUrl}`, data });
|
||||
}
|
||||
// 批量移动到模块
|
||||
export function batchMoveToModules(data: BatchMoveOrCopyType) {
|
||||
return MSR.post({ url: `${BatchMoveCaseUrl}`, data });
|
||||
}
|
||||
|
||||
// 批量复制到模块
|
||||
export function batchCopyToModules(data: BatchMoveOrCopyType) {
|
||||
return MSR.post({ url: `${BatchCopyCaseUrl}`, data });
|
||||
}
|
||||
|
||||
// 回收站
|
||||
|
||||
// 回收站用例分页表
|
||||
export function getRecycleListRequest(data: TableQueryParams) {
|
||||
return MSR.post<CommonList<CaseManagementTable>>({ url: GetRecycleCaseListUrl, data });
|
||||
}
|
||||
// 获取回收站模块数量
|
||||
export function getRecycleModulesCounts(data: CaseModuleQueryParams) {
|
||||
return MSR.post({ url: GetRecycleCaseModulesCountUrl, data });
|
||||
}
|
||||
// 获取全部用例模块数量
|
||||
export function getCaseModulesCounts(data: CaseModuleQueryParams) {
|
||||
return MSR.post({ url: GetCaseModulesCountUrl, data });
|
||||
}
|
||||
// 批量恢复回收站用例表
|
||||
export function restoreCaseList(data: BatchMoveOrCopyType) {
|
||||
return MSR.post({ url: RestoreCaseListUrl, data });
|
||||
}
|
||||
// 批量彻底删除回收站用例表
|
||||
export function batchDeleteRecycleCase(data: BatchMoveOrCopyType) {
|
||||
return MSR.post({ url: BatchDeleteRecycleCaseListUrl, data });
|
||||
}
|
||||
// 恢复回收站单个用例
|
||||
export function recoverRecycleCase(id: string) {
|
||||
return MSR.get({ url: `${RecoverRecycleCaseListUrl}/${id}` });
|
||||
}
|
||||
// 删除回收站单个用例
|
||||
export function deleteRecycleCaseList(id: string) {
|
||||
return MSR.get({ url: `${DeleteRecycleCaseListUrl}/${id}` });
|
||||
}
|
||||
export default {};
|
|
@ -12,13 +12,13 @@ import {
|
|||
} from '@/api/requrls/setting/member';
|
||||
|
||||
import type { CommonList, TableQueryParams } from '@/models/common';
|
||||
import type { AddorUpdateMemberModel, BatchAddProjectModel, LinkItem, MemberItem } from '@/models/setting/member';
|
||||
import type { AddOrUpdateMemberModel, BatchAddProjectModel, LinkItem, MemberItem } from '@/models/setting/member';
|
||||
// 获取成员列表
|
||||
export function getMemberList(data: TableQueryParams) {
|
||||
return MSR.post<CommonList<MemberItem>>({ url: GetMemberListUrl, data });
|
||||
}
|
||||
// 添加成员
|
||||
export function addOrUpdate(data: AddorUpdateMemberModel, type: string) {
|
||||
export function addOrUpdate(data: AddOrUpdateMemberModel, type: string) {
|
||||
if (type === 'add') {
|
||||
return MSR.post({ url: AddMemberUrl, data });
|
||||
}
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
// 用例管理列表
|
||||
export const GetCaseListUrl = '/functional/case/page';
|
||||
// 用例管理-添加
|
||||
export const CreateCaseUrl = '/functional/case/add';
|
||||
// 用例管理-更新
|
||||
export const UpdateCaseUrl = '/functional/case/update';
|
||||
// 用例管理-删除
|
||||
export const DeleteCaseUrl = '/functional/case/delete';
|
||||
// 用例管理-详情
|
||||
export const DetailCaseUrl = '/functional/case/detail';
|
||||
// 用例管理-批量移动用例
|
||||
export const BatchMoveCaseUrl = '/functional/case/batch/move';
|
||||
// 用例管理-批量删除用例
|
||||
export const BatchDeleteCaseUrl = '/functional/case/batch/delete-to-gc';
|
||||
// 用例管理-批量删除用例
|
||||
export const BatchEditCaseUrl = '/functional/case/batch/edit';
|
||||
// 用例管理-批量复制
|
||||
export const BatchCopyCaseUrl = '/functional/case/batch/copy';
|
||||
// 用例管理-关注/取消关注用例
|
||||
export const FollowerCaseUrl = '/functional/case/edit/follower';
|
||||
// 获取用例关注人
|
||||
export const GetCaseFollowerUrl = '/functional/case/follower';
|
||||
// 获取用例模板自定义字段
|
||||
export const GetCaseCustomFieldsUrl = '/functional/case/default/template/field';
|
||||
// 获取表头自定义字段(高级搜索中的自定义字段)
|
||||
export const GetSearchCustomFieldsUrl = '/functional/case/custom/field';
|
||||
// 关联文件列表
|
||||
export const GetAssociatedFilePageUrl = '/attachment/page';
|
||||
|
||||
// 获取模块树
|
||||
export const GetCaseModuleTreeUrl = '/functional/case/module/tree';
|
||||
// 创建模块树
|
||||
export const CreateCaseModuleTreeUrl = '/functional/case/module/add';
|
||||
// 更新模块树
|
||||
export const UpdateCaseModuleTreeUrl = '/functional/case/module/update';
|
||||
// 移动模块
|
||||
export const MoveCaseModuleTreeUrl = '/functional/case/module/move';
|
||||
// 回收站-模块-获取模块树
|
||||
export const GetTrashCaseModuleTreeUrl = '/functional/case/module/trash/tree';
|
||||
// 删除模块
|
||||
export const DeleteCaseModuleTreeUrl = '/functional/case/module/delete';
|
||||
// 获取默认模版自定义字段
|
||||
export const GetDefaultTemplateFieldsUrl = '/functional/case/default/template/field';
|
||||
|
||||
// 回收站
|
||||
|
||||
// 回收站分页
|
||||
export const GetRecycleCaseListUrl = '/functional/case/trash/page';
|
||||
// 获取回收站模块数量
|
||||
export const GetRecycleCaseModulesCountUrl = '/functional/case/trash/module/count';
|
||||
// 获取全部用例模块数量
|
||||
export const GetCaseModulesCountUrl = '/functional/case/module/count';
|
||||
// 恢复回收站用例表
|
||||
export const RestoreCaseListUrl = '/functional/case/trash/batch/recover';
|
||||
// 批量彻底删除回收站用例表
|
||||
export const BatchDeleteRecycleCaseListUrl = '/functional/case/trash/batch/delete';
|
||||
// 恢复回收站单个用例
|
||||
export const RecoverRecycleCaseListUrl = '/functional/case/trash/recover';
|
||||
// 删除回收站单个用例
|
||||
export const DeleteRecycleCaseListUrl = '/functional/case/trash/delete';
|
||||
|
||||
export default {};
|
|
@ -1,7 +1,7 @@
|
|||
@font-face {
|
||||
font-family: iconfont; /* Project id 3462279 */
|
||||
src: url('iconfont.woff2?t=1697180140168') format('woff2'), url('iconfont.woff?t=1697180140168') format('woff'),
|
||||
url('iconfont.ttf?t=1697180140168') format('truetype'), url('iconfont.svg?t=1697180140168#iconfont') format('svg');
|
||||
src: url('iconfont.woff2?t=1700905969825') format('woff2'), url('iconfont.woff?t=1700905969825') format('woff'),
|
||||
url('iconfont.ttf?t=1700905969825') format('truetype'), url('iconfont.svg?t=1700905969825#iconfont') format('svg');
|
||||
}
|
||||
.iconfont {
|
||||
font-size: 16px;
|
||||
|
@ -10,6 +10,102 @@
|
|||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
.icon-icon_text-wrap-overflow::before {
|
||||
content: '\e78f';
|
||||
}
|
||||
.icon-icon_template_filled::before {
|
||||
content: '\e78e';
|
||||
}
|
||||
.icon-icon_laser_filled::before {
|
||||
content: '\e78b';
|
||||
}
|
||||
.icon-icon_stop_outlined::before {
|
||||
content: '\e78c';
|
||||
}
|
||||
.icon-icon_card_filled::before {
|
||||
content: '\e78d';
|
||||
}
|
||||
.icon-icon_community-tab_outlined::before {
|
||||
content: '\e77e';
|
||||
}
|
||||
.icon-icon_play-round_filled1::before {
|
||||
content: '\e77f';
|
||||
}
|
||||
.icon-icon_thumbdown_outlined::before {
|
||||
content: '\e780';
|
||||
}
|
||||
.icon-icon_file-doc_colorful::before {
|
||||
content: '\e781';
|
||||
}
|
||||
.icon-icon-product-forum_filled::before {
|
||||
content: '\e782';
|
||||
}
|
||||
.icon-icon_file-add_colorful::before {
|
||||
content: '\e783';
|
||||
}
|
||||
.icon-icon_group_filled::before {
|
||||
content: '\e784';
|
||||
}
|
||||
.icon-icon_send_colorful::before {
|
||||
content: '\e785';
|
||||
}
|
||||
.icon-icon-product-forum_colorful::before {
|
||||
content: '\e786';
|
||||
}
|
||||
.icon-icon_nearby-group_outlined::before {
|
||||
content: '\e787';
|
||||
}
|
||||
.icon-icon_thumbdown_filled::before {
|
||||
content: '\e788';
|
||||
}
|
||||
.icon-icon_thumbsup_filled::before {
|
||||
content: '\e789';
|
||||
}
|
||||
.icon-icon_file-add_outlined::before {
|
||||
content: '\e78a';
|
||||
}
|
||||
.icon-icon_thumbsup_outlined::before {
|
||||
content: '\e77b';
|
||||
}
|
||||
.icon-icon-product-forum_outlined::before {
|
||||
content: '\e77c';
|
||||
}
|
||||
.icon-icon_test-tracking_colorful::before {
|
||||
content: '\e77d';
|
||||
}
|
||||
.icon-icon_reply::before {
|
||||
content: '\e778';
|
||||
}
|
||||
.icon-icon_comment_collapse_text_input::before {
|
||||
content: '\e779';
|
||||
}
|
||||
.icon-icon_comment_expand_text_input::before {
|
||||
content: '\e77a';
|
||||
}
|
||||
.icon-icon_chart_graph::before {
|
||||
content: '\e777';
|
||||
}
|
||||
.icon-icon_share1::before {
|
||||
content: '\e776';
|
||||
}
|
||||
.icon-icon_text::before {
|
||||
content: '\e775';
|
||||
}
|
||||
.icon-icon_click::before {
|
||||
content: '\e697';
|
||||
}
|
||||
.icon-icon_feedback_outlined::before {
|
||||
content: '\e773';
|
||||
}
|
||||
.icon-icon_done_outlined::before {
|
||||
content: '\e774';
|
||||
}
|
||||
.icon-icon_dataset_outlined::before {
|
||||
content: '\e772';
|
||||
}
|
||||
.icon-icon_outer-borders_outlined::before {
|
||||
content: '\e771';
|
||||
}
|
||||
.icon-icon_checkbox::before {
|
||||
content: '\e76e';
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -5,6 +5,230 @@
|
|||
"css_prefix_text": "icon-",
|
||||
"description": "DE、MS项目icon管理",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "38195845",
|
||||
"name": "icon_text-wrap-overflow",
|
||||
"font_class": "icon_text-wrap-overflow",
|
||||
"unicode": "e78f",
|
||||
"unicode_decimal": 59279
|
||||
},
|
||||
{
|
||||
"icon_id": "38036023",
|
||||
"name": "icon_template_filled",
|
||||
"font_class": "icon_template_filled",
|
||||
"unicode": "e78e",
|
||||
"unicode_decimal": 59278
|
||||
},
|
||||
{
|
||||
"icon_id": "38020820",
|
||||
"name": "icon_laser_filled",
|
||||
"font_class": "icon_laser_filled",
|
||||
"unicode": "e78b",
|
||||
"unicode_decimal": 59275
|
||||
},
|
||||
{
|
||||
"icon_id": "38020819",
|
||||
"name": "icon_stop_outlined",
|
||||
"font_class": "icon_stop_outlined",
|
||||
"unicode": "e78c",
|
||||
"unicode_decimal": 59276
|
||||
},
|
||||
{
|
||||
"icon_id": "38020817",
|
||||
"name": "icon_card_filled",
|
||||
"font_class": "icon_card_filled",
|
||||
"unicode": "e78d",
|
||||
"unicode_decimal": 59277
|
||||
},
|
||||
{
|
||||
"icon_id": "38020824",
|
||||
"name": "icon_community-tab_outlined",
|
||||
"font_class": "icon_community-tab_outlined",
|
||||
"unicode": "e77e",
|
||||
"unicode_decimal": 59262
|
||||
},
|
||||
{
|
||||
"icon_id": "38020833",
|
||||
"name": "icon_play-round_filled",
|
||||
"font_class": "icon_play-round_filled1",
|
||||
"unicode": "e77f",
|
||||
"unicode_decimal": 59263
|
||||
},
|
||||
{
|
||||
"icon_id": "38020826",
|
||||
"name": "icon_thumbdown_outlined",
|
||||
"font_class": "icon_thumbdown_outlined",
|
||||
"unicode": "e780",
|
||||
"unicode_decimal": 59264
|
||||
},
|
||||
{
|
||||
"icon_id": "38020832",
|
||||
"name": "icon_file-doc_colorful",
|
||||
"font_class": "icon_file-doc_colorful",
|
||||
"unicode": "e781",
|
||||
"unicode_decimal": 59265
|
||||
},
|
||||
{
|
||||
"icon_id": "38020828",
|
||||
"name": "icon-product-forum_filled",
|
||||
"font_class": "icon-product-forum_filled",
|
||||
"unicode": "e782",
|
||||
"unicode_decimal": 59266
|
||||
},
|
||||
{
|
||||
"icon_id": "38020827",
|
||||
"name": "icon_file-add_colorful",
|
||||
"font_class": "icon_file-add_colorful",
|
||||
"unicode": "e783",
|
||||
"unicode_decimal": 59267
|
||||
},
|
||||
{
|
||||
"icon_id": "38020830",
|
||||
"name": "icon_group_filled",
|
||||
"font_class": "icon_group_filled",
|
||||
"unicode": "e784",
|
||||
"unicode_decimal": 59268
|
||||
},
|
||||
{
|
||||
"icon_id": "38020829",
|
||||
"name": "icon_send_colorful",
|
||||
"font_class": "icon_send_colorful",
|
||||
"unicode": "e785",
|
||||
"unicode_decimal": 59269
|
||||
},
|
||||
{
|
||||
"icon_id": "38020823",
|
||||
"name": "icon-product-forum_colorful",
|
||||
"font_class": "icon-product-forum_colorful",
|
||||
"unicode": "e786",
|
||||
"unicode_decimal": 59270
|
||||
},
|
||||
{
|
||||
"icon_id": "38020822",
|
||||
"name": "icon_nearby-group_outlined",
|
||||
"font_class": "icon_nearby-group_outlined",
|
||||
"unicode": "e787",
|
||||
"unicode_decimal": 59271
|
||||
},
|
||||
{
|
||||
"icon_id": "38020825",
|
||||
"name": "icon_thumbdown_filled",
|
||||
"font_class": "icon_thumbdown_filled",
|
||||
"unicode": "e788",
|
||||
"unicode_decimal": 59272
|
||||
},
|
||||
{
|
||||
"icon_id": "38020821",
|
||||
"name": "icon_thumbsup_filled",
|
||||
"font_class": "icon_thumbsup_filled",
|
||||
"unicode": "e789",
|
||||
"unicode_decimal": 59273
|
||||
},
|
||||
{
|
||||
"icon_id": "38020818",
|
||||
"name": "icon_file-add_outlined",
|
||||
"font_class": "icon_file-add_outlined",
|
||||
"unicode": "e78a",
|
||||
"unicode_decimal": 59274
|
||||
},
|
||||
{
|
||||
"icon_id": "38020835",
|
||||
"name": "icon_thumbsup_outlined",
|
||||
"font_class": "icon_thumbsup_outlined",
|
||||
"unicode": "e77b",
|
||||
"unicode_decimal": 59259
|
||||
},
|
||||
{
|
||||
"icon_id": "38020834",
|
||||
"name": "icon-product-forum_outlined",
|
||||
"font_class": "icon-product-forum_outlined",
|
||||
"unicode": "e77c",
|
||||
"unicode_decimal": 59260
|
||||
},
|
||||
{
|
||||
"icon_id": "38020831",
|
||||
"name": "icon_test-tracking_colorful",
|
||||
"font_class": "icon_test-tracking_colorful",
|
||||
"unicode": "e77d",
|
||||
"unicode_decimal": 59261
|
||||
},
|
||||
{
|
||||
"icon_id": "37903599",
|
||||
"name": "icon_reply",
|
||||
"font_class": "icon_reply",
|
||||
"unicode": "e778",
|
||||
"unicode_decimal": 59256
|
||||
},
|
||||
{
|
||||
"icon_id": "37903597",
|
||||
"name": "icon_comment_collapse_text_input",
|
||||
"font_class": "icon_comment_collapse_text_input",
|
||||
"unicode": "e779",
|
||||
"unicode_decimal": 59257
|
||||
},
|
||||
{
|
||||
"icon_id": "37903598",
|
||||
"name": "icon_comment_expand_text_input",
|
||||
"font_class": "icon_comment_expand_text_input",
|
||||
"unicode": "e77a",
|
||||
"unicode_decimal": 59258
|
||||
},
|
||||
{
|
||||
"icon_id": "37878729",
|
||||
"name": "icon_chart_graph",
|
||||
"font_class": "icon_chart_graph",
|
||||
"unicode": "e777",
|
||||
"unicode_decimal": 59255
|
||||
},
|
||||
{
|
||||
"icon_id": "37848043",
|
||||
"name": "icon_share",
|
||||
"font_class": "icon_share1",
|
||||
"unicode": "e776",
|
||||
"unicode_decimal": 59254
|
||||
},
|
||||
{
|
||||
"icon_id": "37842152",
|
||||
"name": "icon_text",
|
||||
"font_class": "icon_text",
|
||||
"unicode": "e775",
|
||||
"unicode_decimal": 59253
|
||||
},
|
||||
{
|
||||
"icon_id": "37841481",
|
||||
"name": "icon_click",
|
||||
"font_class": "icon_click",
|
||||
"unicode": "e697",
|
||||
"unicode_decimal": 59031
|
||||
},
|
||||
{
|
||||
"icon_id": "37789808",
|
||||
"name": "icon_feedback_outlined",
|
||||
"font_class": "icon_feedback_outlined",
|
||||
"unicode": "e773",
|
||||
"unicode_decimal": 59251
|
||||
},
|
||||
{
|
||||
"icon_id": "37789807",
|
||||
"name": "icon_done_outlined",
|
||||
"font_class": "icon_done_outlined",
|
||||
"unicode": "e774",
|
||||
"unicode_decimal": 59252
|
||||
},
|
||||
{
|
||||
"icon_id": "37789689",
|
||||
"name": "icon_dataset_outlined",
|
||||
"font_class": "icon_dataset_outlined",
|
||||
"unicode": "e772",
|
||||
"unicode_decimal": 59250
|
||||
},
|
||||
{
|
||||
"icon_id": "37715855",
|
||||
"name": "icon_outer-borders_outlined",
|
||||
"font_class": "icon_outer-borders_outlined",
|
||||
"unicode": "e771",
|
||||
"unicode_decimal": 59249
|
||||
},
|
||||
{
|
||||
"icon_id": "37662517",
|
||||
"name": "icon_checkbox",
|
||||
|
@ -1608,13 +1832,6 @@
|
|||
"unicode": "e695",
|
||||
"unicode_decimal": 59029
|
||||
},
|
||||
{
|
||||
"icon_id": "32849836",
|
||||
"name": "icon_logs_outlined-1",
|
||||
"font_class": "icon_logs_outlined-1",
|
||||
"unicode": "e697",
|
||||
"unicode_decimal": 59031
|
||||
},
|
||||
{
|
||||
"icon_id": "32849837",
|
||||
"name": "icon_refresh_outlined",
|
||||
|
|
|
@ -14,6 +14,70 @@
|
|||
/>
|
||||
<missing-glyph />
|
||||
|
||||
<glyph glyph-name="icon_text-wrap-overflow" unicode="" d="M746.666667 488.32a234.666667 234.666667 0 0 0 0-469.333333h-78.208v-52.181334a26.069333 26.069333 0 0 0-41.728-20.821333l-111.232 83.413333a52.138667 52.138667 0 0 0 0 83.456l111.232 83.413334a26.069333 26.069333 0 0 0 41.728-20.864v-52.138667H746.666667a130.389333 130.389333 0 1 1 0 260.736H94.805333a52.138667 52.138667 0 0 0 0 104.32H746.666667zM303.402667 123.264a52.138667 52.138667 0 0 0 0-104.277333H94.805333a52.138667 52.138667 0 0 0 0 104.277333h208.64zM94.805333 853.333333h834.389334a52.138667 52.138667 0 0 0 0-104.277333H94.805333a52.138667 52.138667 0 1 0 0 104.277333z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_template_filled" unicode="" d="M728.96 853.333333H170.666667a42.666667 42.666667 0 0 1-42.666667-42.666666v-853.333334a42.666667 42.666667 0 0 1 42.666667-42.666666h682.666666a42.666667 42.666667 0 0 1 42.666667 42.666666V686.250667a42.666667 42.666667 0 0 1-12.501333 30.165333l-124.330667 124.416A42.666667 42.666667 0 0 1 729.002667 853.333333zM298.666667 533.333333a21.333333 21.333333 0 0 0 21.333333 21.333334h384a21.333333 21.333333 0 0 0 21.333333-21.333334v-42.666666a21.333333 21.333333 0 0 0-21.333333-21.333334h-384a21.333333 21.333333 0 0 0-21.333333 21.333334v42.666666z m170.666666-170.666666a21.333333 21.333333 0 0 0 21.333334 21.333333h213.333333a21.333333 21.333333 0 0 0 21.333333-21.333333v-213.333334a21.333333 21.333333 0 0 0-21.333333-21.333333h-213.333333a21.333333 21.333333 0 0 0-21.333334 21.333333v213.333334z m-170.666666 0a21.333333 21.333333 0 0 0 21.333333 21.333333h42.666667a21.333333 21.333333 0 0 0 21.333333-21.333333v-213.333334a21.333333 21.333333 0 0 0-21.333333-21.333333h-42.666667a21.333333 21.333333 0 0 0-21.333333 21.333333v213.333334z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_laser_filled" unicode="" d="M533.248 604.245333a234.666667 234.666667 0 1 1-241.664-241.493333l-36.693333 91.776a149.333333 149.333333 0 1 0 186.666666 186.368l91.690667-36.693333zM523.818667-45.397333c14.464-36.096 65.664-35.669333 79.488 0.64l92.714666 242.858666 244.864 94.592c36.138667 13.994667 36.437333 65.024 0.426667 79.445334L337.962667 613.504c-34.858667 13.909333-69.418667-20.650667-55.466667-55.466667l241.322667-603.434666z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_stop_outlined" unicode="" d="M981.333333 384c0-259.2-210.133333-469.333333-469.333333-469.333333S42.666667 124.8 42.666667 384 252.8 853.333333 512 853.333333s469.333333-210.133333 469.333333-469.333333z m-85.333333 0a384 384 0 1 1-768 0 384 384 0 0 1 768 0zM384 554.666667h256c23.466667 0 42.666667-19.072 42.666667-42.666667v-256c0-23.552-19.2-42.666667-42.666667-42.666667H384c-23.466667 0-42.666667 19.114667-42.666667 42.666667V512c0 23.594667 19.2 42.666667 42.666667 42.666667z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_card_filled" unicode="" d="M426.666667 810.666667H128a42.666667 42.666667 0 0 1-42.666667-42.666667v-298.666667a42.666667 42.666667 0 0 1 42.666667-42.666666h298.666667a42.666667 42.666667 0 0 1 42.666666 42.666666V768a42.666667 42.666667 0 0 1-42.666666 42.666667zM426.666667 341.333333H128a42.666667 42.666667 0 0 1-42.666667-42.666666v-298.666667a42.666667 42.666667 0 0 1 42.666667-42.666667h298.666667a42.666667 42.666667 0 0 1 42.666666 42.666667v298.666667a42.666667 42.666667 0 0 1-42.666666 42.666666zM896 810.666667h-298.666667a42.666667 42.666667 0 0 1-42.666666-42.666667v-298.666667a42.666667 42.666667 0 0 1 42.666666-42.666666h298.666667a42.666667 42.666667 0 0 1 42.666667 42.666666V768a42.666667 42.666667 0 0 1-42.666667 42.666667zM893.482667 341.333333H599.893333c-24.96 0-45.184-20.224-45.184-45.184v-293.632c0-24.96 20.224-45.184 45.184-45.184h293.632c24.96 0 45.184 20.224 45.184 45.184V296.106667c0 24.96-20.224 45.184-45.184 45.184z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_community-tab_outlined" unicode="" d="M213.333333 167.808c0 142.933333 120.021333 258.816 258.901334 258.816L552.149333 426.666667c138.922667 0 258.56-115.882667 258.56-258.858667V21.333333a42.666667 42.666667 0 0 0-42.666666-42.666666H256a42.666667 42.666667 0 0 0-42.666667 42.666666v146.474667z m258.901334 173.482667C379.605333 341.333333 298.666667 262.784 298.666667 167.808V64h426.666666v103.808C725.333333 262.912 644.693333 341.333333 552.192 341.333333h-79.914667zM617.6 555.733333A149.333333 149.333333 0 0 0 513.152 512H510.976a149.333333 149.333333 0 1 0 106.666667 43.733333zM512 725.333333a64 64 0 1 1 0-128 64 64 0 0 1 0 128zM320 522.666667a96 96 0 1 0-192 0 96 96 0 0 0 192 0z m-64 0a32 32 0 1 1-64 0 32 32 0 0 1 64 0zM215.253333 384C111.061333 384 64 297.088 64 189.866667v-115.2c0-17.706667 14.336-32 32-32H149.333333v128c0 154.837333 72.96 189.781333 116.309334 210.602666l4.266666 2.048A183.850667 183.850667 0 0 1 253.781333 384h-38.570666zM808.704 384c104.192 0 151.210667-86.912 151.210667-194.133333v-115.2a32 32 0 0 0-32-32h-53.333334v128c0 154.837333-72.874667 189.781333-116.266666 210.602666l-4.266667 2.048c5.333333 0.426667 10.666667 0.682667 16.085333 0.682667h38.570667zM800 426.666667a96 96 0 1 1 0 192 96 96 0 0 1 0-192z m0 64a32 32 0 1 0 0 64 32 32 0 0 0 0-64z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_play-round_filled1" unicode="" d="M512 853.333333c259.2 0 469.333333-210.133333 469.333333-469.333333s-210.133333-469.333333-469.333333-469.333333S42.666667 124.8 42.666667 384 252.8 853.333333 512 853.333333zM421.077333 597.333333c-9.813333 0-19.2-3.84-26.24-10.666666A35.797333 35.797333 0 0 1 384 560.896v-353.92c0-6.826667 1.962667-13.44 5.632-19.242667a37.674667 37.674667 0 0 1 51.072-11.562666l288.554667 176.938666A36.352 36.352 0 0 1 746.666667 384a36.352 36.352 0 0 1-17.408 30.890667L440.746667 591.786667A37.589333 37.589333 0 0 1 421.077333 597.333333z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_thumbdown_outlined" unicode="" d="M128.341333 814.08H42.666667v-599.68h85.674666C128 213.333333 128 810.666667 128.341333 814.08z m492.544-599.722667h183.722667c127.786667 0 157.141333 112.810667 127.786667 197.333334l-127.786667 336.469333A90.88 90.88 0 0 1 716.8 814.421333H213.674667a21.418667 21.418667 0 0 1-21.376-21.376v-557.312c0-11.818667 9.557333-21.418667 21.376-21.418666H257.706667c13.952 0 27.008-6.784 35.029333-18.176l177.834667-252.970667c12.032-19.157333 44.544-33.834667 79.146666-18.048 51.968 23.637333 114.133333 75.264 114.133334 160.853333 0 32.256-14.336 75.050667-42.965334 128.341334z m183.722667 85.632h-327.04l67.84-126.208c22.570667-41.984 32.768-72.490667 32.768-87.808 0-24.874667-5.205333-52.992-49.834667-76.032l-191.104 271.872a42.837333 42.837333 0 0 1-35.029333 18.176h-24.277333V728.789333H716.8c2.645333 0 4.693333-1.578667 5.205333-3.413333l1.066667-3.882667 128.768-338.944c16.938667-49.877333 0.042667-82.56-47.232-82.56z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_file-doc_colorful" unicode="" d="M170.666667 789.333333a42.666667 42.666667 0 0 0 42.666666 42.666667h420.693334a21.333333 21.333333 0 0 0 15.232-6.4l197.973333-201.386667a21.333333 21.333333 0 0 0 6.101333-14.933333V-21.333333a42.666667 42.666667 0 0 0-42.666666-42.666667H213.333333a42.666667 42.666667 0 0 0-42.666666 42.666667v810.666666zM640 831.146667a21.333333 21.333333 0 0 0 9.258667-5.546667l197.973333-201.386667a21.333333 21.333333 0 0 0 3.925333-5.546666h-162.730666A48.426667 48.426667 0 0 0 640 667.093333V831.146667zM344.448 461.568h323.498667c3.84 0 6.954667-3.114667 6.954666-6.954667v-32.597333c0-3.84-3.114667-6.997333-6.954666-6.997333H344.448a6.997333 6.997333 0 0 0-6.997333 6.997333v32.597333c0 3.84 3.114667 6.954667 6.997333 6.954667z m0-139.648h323.498667c3.84 0 6.954667-3.114667 6.954666-6.954667v-32.597333c0-3.84-3.114667-6.997333-6.954666-6.997333H344.448a6.997333 6.997333 0 0 0-6.997333 6.997333v32.597333c0 3.84 3.114667 6.954667 6.997333 6.954667z m0-139.605333h172.202667c3.84 0 6.997333-3.114667 6.997333-6.997334v-32.597333c0-3.84-3.114667-6.954667-6.997333-6.954667H344.448a6.997333 6.997333 0 0 0-6.997333 6.954667v32.597333c0 3.84 3.114667 6.997333 6.997333 6.997334z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon-product-forum_filled" unicode="" d="M725.333333 426.666667a42.666667 42.666667 0 0 0 42.666667 42.666666h170.666667a42.666667 42.666667 0 0 0 42.666666-42.666666v-341.333334a42.666667 42.666667 0 0 0-42.666666-42.666666h-89.002667l-51.498667-51.498667a42.666667 42.666667 0 0 0-60.330666 0L686.336 42.666667H469.333333a42.666667 42.666667 0 0 0-42.666666 42.666666v170.666667a42.666667 42.666667 0 0 0 42.666666 42.666667h256v128z m85.333334-42.666667v-128a42.666667 42.666667 0 0 0-42.666667-42.666667h-256v-85.333333h192a42.666667 42.666667 0 0 0 30.165333-12.501333l33.834667-33.834667 33.834667 33.834667A42.666667 42.666667 0 0 0 832 128H896v256h-85.333333zM85.333333 810.666667a42.666667 42.666667 0 0 1-42.666666-42.666667v-512a42.666667 42.666667 0 0 1 42.666666-42.666667h89.002667l72.832-72.832a42.666667 42.666667 0 0 1 60.330667 0L380.330667 213.333333H768a42.666667 42.666667 0 0 1 42.666667 42.666667V768a42.666667 42.666667 0 0 1-42.666667 42.666667H85.333333z m213.333334-298.666667a42.666667 42.666667 0 1 0-85.333334 0 42.666667 42.666667 0 0 0 85.333334 0z m170.666666 0a42.666667 42.666667 0 1 0-85.333333 0 42.666667 42.666667 0 0 0 85.333333 0z m170.666667 0a42.666667 42.666667 0 1 0-85.333333 0 42.666667 42.666667 0 0 0 85.333333 0z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_file-add_colorful" unicode="" d="M170.666667 783.573333C170.666667 810.325333 191.744 832 217.728 832h425.130667c6.229333 0 12.202667-2.56 16.597333-7.04l186.88-190.634667a24.576 24.576 0 0 0 6.997333-17.194666v-632.704c0-26.752-21.077333-48.426667-47.061333-48.426667H217.728C191.744-64 170.666667-42.325333 170.666667-15.573333V783.573333zM652.586667 829.866667a23.466667 23.466667 0 0 0 6.869333-4.906667l186.922667-190.634667a24.32 24.32 0 0 0 5.290666-8.149333h-152.021333c-25.984 0-47.061333 21.674667-47.061333 48.426667V829.866667zM512 469.333333a21.333333 21.333333 0 0 1-21.333333-21.333333v-128h-128a21.333333 21.333333 0 0 1 0-42.666667h128v-128a21.333333 21.333333 0 0 1 42.666666 0v128h128a21.333333 21.333333 0 0 1 0 42.666667h-128v128a21.333333 21.333333 0 0 1-21.333333 21.333333z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_group_filled" unicode="" d="M362.666667 384a192 192 0 1 1 0 384 192 192 0 0 1 0-384zM64-42.666667a42.666667 42.666667 0 0 0-42.666667 42.666667v82.474667C21.333333 225.408 141.354667 341.333333 280.234667 341.333333h165.248c138.88 0 258.517333-115.882667 258.517333-258.858666V0a42.666667 42.666667 0 0 0-42.666667-42.666667h-597.333333zM789.333333 0v12.629333c0 98.645333 0 200.704-85.333333 264.704 3.584 0.298667 9.557333 0.213333 15.36 0.085334l7.850667-0.085334H810.666667c104.192 0 192-65.578667 192-172.8v-72.533333a32 32 0 0 0-32-32H789.333333zM746.666667 341.333333a128 128 0 1 1 0 256 128 128 0 0 1 0-256z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_send_colorful" unicode="" d="M512 332.373333v-267.349333l146.773333-132.266667a43.477333 43.477333 0 0 1 72.661334 19.541334l220.373333 780.544c6.058667 21.376-20.522667 36.608-35.925333 20.565333L512 332.373333zM881.706667 788.181333c16.213333 15.573333 0.426667 42.410667-21.034667 35.797334L81.92 583.424a43.434667 43.434667 0 0 1-19.712-72.704l133.888-146.645333h243.413333l442.154667 424.106666z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon-product-forum_colorful" unicode="" d="M725.333333 426.666667a42.666667 42.666667 0 0 0 42.666667 42.666666h170.666667a42.666667 42.666667 0 0 0 42.666666-42.666666v-341.333334a42.666667 42.666667 0 0 0-42.666666-42.666666h-89.002667l-51.498667-51.498667a42.666667 42.666667 0 0 0-60.330666 0L686.336 42.666667H469.333333a42.666667 42.666667 0 0 0-42.666666 42.666666v170.666667a42.666667 42.666667 0 0 0 42.666666 42.666667h256v128z m85.333334-42.666667v-128a42.666667 42.666667 0 0 0-42.666667-42.666667h-256v-85.333333h192a42.666667 42.666667 0 0 0 30.165333-12.501333l33.834667-33.834667 33.834667 33.834667A42.666667 42.666667 0 0 0 832 128H896v256h-85.333333zM85.333333 810.666667a42.666667 42.666667 0 0 1-42.666666-42.666667v-512a42.666667 42.666667 0 0 1 42.666666-42.666667h89.002667l72.832-72.832a42.666667 42.666667 0 0 1 60.330667 0L380.330667 213.333333H768a42.666667 42.666667 0 0 1 42.666667 42.666667V768a42.666667 42.666667 0 0 1-42.666667 42.666667H85.333333z m213.333334-298.666667a42.666667 42.666667 0 1 0-85.333334 0 42.666667 42.666667 0 0 0 85.333334 0z m170.666666 0a42.666667 42.666667 0 1 0-85.333333 0 42.666667 42.666667 0 0 0 85.333333 0z m170.666667 0a42.666667 42.666667 0 1 0-85.333333 0 42.666667 42.666667 0 0 0 85.333333 0z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_nearby-group_outlined" unicode="" d="M256 426.666667a170.666667 170.666667 0 1 1 0 341.333333 170.666667 170.666667 0 0 1 0-341.333333z m0 85.333333a85.333333 85.333333 0 1 0 0 170.666667 85.333333 85.333333 0 0 0 0-170.666667zM42.666667 213.333333a170.666667 170.666667 0 0 0 170.666666 170.666667h85.333334a170.666667 170.666667 0 0 0 170.666666-170.666667v-170.666666a42.666667 42.666667 0 0 0-42.666666-42.666667H85.333333a42.666667 42.666667 0 0 0-42.666666 42.666667v170.666666z m256 85.333334H213.333333a85.333333 85.333333 0 0 1-85.333333-85.333334v-128h256v128a85.333333 85.333333 0 0 1-85.333333 85.333334zM554.666667 213.333333a170.666667 170.666667 0 0 0 170.666666 170.666667h85.333334a170.666667 170.666667 0 0 0 170.666666-170.666667v-170.666666a42.666667 42.666667 0 0 0-42.666666-42.666667h-341.333334a42.666667 42.666667 0 0 0-42.666666 42.666667v170.666666z m85.333333 0v-128h256v128a85.333333 85.333333 0 0 1-85.333333 85.333334h-85.333334a85.333333 85.333333 0 0 1-85.333333-85.333334zM938.666667 597.333333a170.666667 170.666667 0 1 1-341.333334 0 170.666667 170.666667 0 0 1 341.333334 0z m-85.333334 0a85.333333 85.333333 0 1 0-170.666666 0 85.333333 85.333333 0 0 0 170.666666 0z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_thumbdown_filled" unicode="" d="M620.842667 210.56h183.722666c127.829333 0 157.184 112.810667 127.829334 197.376l-127.829334 336.426667A90.88 90.88 0 0 1 716.8 810.666667H213.76a21.418667 21.418667 0 0 1-21.461333-21.418667v-557.269333c0-11.818667 9.6-21.418667 21.418666-21.418667H257.706667c13.952 0 27.008-6.826667 35.029333-18.218667l177.834667-252.928c12.032-19.2 44.501333-33.834667 79.146666-18.090666 51.925333 23.68 114.133333 75.306667 114.133334 160.853333 0 32.256-14.336 75.093333-43.008 128.384zM128 810.666667H42.325333v-599.68H128C127.658667 212.053333 127.658667 807.253333 128 810.666667z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_thumbsup_filled" unicode="" d="M128.298667-42.282667H42.666667V557.354667h85.674666C128 554.666667 126.72-40.618667 128.341333-42.24zM804.565333 557.44h-183.722666c28.672 53.333333 43.008 96.128 43.008 128.384 0 85.546667-62.208 137.173333-114.133334 160.853333-34.645333 15.786667-67.114667 1.066667-79.146666-18.090666L292.693333 575.658667a42.837333 42.837333 0 0 0-35.029333-18.218667H213.674667a21.418667 21.418667 0 0 1-21.418667-21.418667v-557.269333c0-11.818667 9.6-21.418667 21.418667-21.418667H716.8a90.88 90.88 0 0 1 87.808 66.261334l127.829333 336.469333c29.354667 84.565333 0 197.376-127.829333 197.376z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_file-add_outlined" unicode="" d="M213.333333 768h469.333334v-107.52a21.333333 21.333333 0 0 1 21.333333-21.333333H810.666667V341.333333h85.333333V686.293333a42.666667 42.666667 0 0 1-12.501333 30.165334l-124.330667 124.373333A42.666667 42.666667 0 0 1 729.002667 853.333333H170.666667a42.666667 42.666667 0 0 1-42.666667-42.666666v-853.333334a42.666667 42.666667 0 0 1 42.666667-42.666666h341.333333v85.333333H213.333333V768zM746.666667 256a21.333333 21.333333 0 0 1-21.333334-21.333333V128h-106.666666a21.333333 21.333333 0 0 1-21.333334-21.333333v-42.666667a21.333333 21.333333 0 0 1 21.333334-21.333333H725.333333v-106.666667a21.333333 21.333333 0 0 1 21.333334-21.333333h42.666666a21.333333 21.333333 0 0 1 21.333334 21.333333V42.666667h106.666666a21.333333 21.333333 0 0 1 21.333334 21.333333v42.666667a21.333333 21.333333 0 0 1-21.333334 21.333333H810.666667v106.666667a21.333333 21.333333 0 0 1-21.333334 21.333333h-42.666666z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_thumbsup_outlined" unicode="" d="M128.341333-42.282667H42.666667V557.354667h85.674666C128 554.666667 126.72-43.946667 128.341333-42.24zM620.8 557.44h183.722667c127.829333 0 157.184-112.810667 127.829333-197.333333l-127.829333-336.469334A90.88 90.88 0 0 0 716.8-42.666667H213.76a21.418667 21.418667 0 0 0-21.461333 21.418667V536.021333c0 11.818667 9.6 21.418667 21.418666 21.418667H257.706667c13.952 0 27.008 6.826667 35.029333 18.218667L470.613333 828.586667c12.032 19.2 44.501333 33.834667 79.146667 18.090666 51.925333-23.68 114.133333-75.306667 114.133333-160.853333 0-32.256-14.336-75.093333-43.008-128.384z m183.722667-85.674667h-326.997334l67.84 126.208c22.528 41.984 32.768 72.533333 32.768 87.850667 0 24.832-5.248 52.949333-49.834666 76.032L337.237333 489.984a42.837333 42.837333 0 0 0-35.029333-18.218667h-24.277333v-428.8H716.8c2.688 0 4.736 1.578667 5.248 3.413334l1.066667 3.882666 128.768 338.944c16.896 49.92 0 82.56-47.274667 82.56z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon-product-forum_outlined" unicode="" d="M725.333333 426.666667a42.666667 42.666667 0 0 0 42.666667 42.666666h170.666667a42.666667 42.666667 0 0 0 42.666666-42.666666v-341.333334a42.666667 42.666667 0 0 0-42.666666-42.666666h-89.002667l-51.498667-51.498667a42.666667 42.666667 0 0 0-60.330666 0L686.336 42.666667H469.333333a42.666667 42.666667 0 0 0-42.666666 42.666666v170.666667a42.666667 42.666667 0 0 0 42.666666 42.666667h256v128z m85.333334-42.666667v-128a42.666667 42.666667 0 0 0-42.666667-42.666667h-256v-85.333333h192a42.666667 42.666667 0 0 0 30.165333-12.501333l33.834667-33.834667 33.834667 33.834667A42.666667 42.666667 0 0 0 832 128H896v256h-85.333333zM42.666667 768a42.666667 42.666667 0 0 0 42.666666 42.666667h682.666667a42.666667 42.666667 0 0 0 42.666667-42.666667v-512a42.666667 42.666667 0 0 0-42.666667-42.666667H380.330667l-72.832-72.832a42.666667 42.666667 0 0 0-60.330667 0L174.336 213.333333H85.333333a42.666667 42.666667 0 0 0-42.666666 42.666667V768z m85.333333-42.666667v-426.666666h64a42.666667 42.666667 0 0 0 30.165333-12.501334L277.333333 230.997333l55.168 55.168A42.666667 42.666667 0 0 0 362.666667 298.666667H725.333333V725.333333H128zM298.666667 512a42.666667 42.666667 0 1 0-85.333334 0 42.666667 42.666667 0 0 0 85.333334 0z m170.666666 0a42.666667 42.666667 0 1 0-85.333333 0 42.666667 42.666667 0 0 0 85.333333 0z m128-42.666667a42.666667 42.666667 0 1 1 0 85.333334 42.666667 42.666667 0 0 1 0-85.333334z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_test-tracking_colorful" unicode="" d="M172.714667 808.618667H298.666667V640a42.666667 42.666667 0 0 1 42.666666-42.666667h341.333334a42.666667 42.666667 0 0 1 42.666666 42.666667V808.618667h125.952c30.677333 0 44.714667-17.237333 44.714667-44.672v-804.565334c0-27.434667-14.037333-44.714667-44.714667-44.714666H172.714667C141.994667-85.333333 128-68.096 128-40.618667V763.946667c0 27.392 14.037333 44.672 44.714667 44.672zM321.024 426.666667a22.357333 22.357333 0 0 1-22.357333-22.357334v-44.714666c0-12.330667 9.984-22.314667 22.357333-22.314667h381.952c12.373333 0 22.357333 9.984 22.357333 22.314667v44.714666a22.357333 22.357333 0 0 1-22.357333 22.357334H321.024z m0-213.333334a22.357333 22.357333 0 0 1-22.357333-22.357333v-44.672c0-12.373333 9.984-22.357333 22.357333-22.357333h394.154667c12.373333 0 22.357333 9.984 22.357333 22.357333v44.672a22.357333 22.357333 0 0 1-22.357333 22.357333H321.024zM405.333333 853.333333a21.333333 21.333333 0 0 1-21.333333-21.333333v-128a21.333333 21.333333 0 0 1 21.333333-21.333333h213.333334a21.333333 21.333333 0 0 1 21.333333 21.333333v128a21.333333 21.333333 0 0 1-21.333333 21.333333h-213.333334z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_reply" unicode="" d="M938.666667 768a42.666667 42.666667 0 0 0 42.666666-42.666667v-640a42.666667 42.666667 0 0 0-42.666666-42.666666H500.693333l-204.288-102.144a42.666667 42.666667 0 0 0-61.44 33.237333L234.666667-21.333333V42.666667H85.333333a42.666667 42.666667 0 0 0-42.368 37.674666L42.666667 85.333333V725.333333a42.666667 42.666667 0 0 0 42.666666 42.666667h853.333334z m-42.666667-85.333333H128v-554.666667h149.333333a42.666667 42.666667 0 0 0 42.368-37.674667L320 85.333333v-37.589333l151.594667 75.733333a42.666667 42.666667 0 0 0 14.122666 4.266667L490.666667 128H896V682.666667z m-170.666667-234.666667a42.666667 42.666667 0 0 0 0-85.333333H298.666667a42.666667 42.666667 0 0 0 0 85.333333h426.666666z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_comment_collapse_text_input" unicode="" d="M938.666667 768a42.666667 42.666667 0 0 0 42.666666-42.666667v-234.666666a42.666667 42.666667 0 0 0-85.333333 0V682.666667H128v-554.666667h106.666667a42.666667 42.666667 0 0 0 42.368-37.674667L277.333333 85.333333v-37.589333l151.594667 75.733333a42.666667 42.666667 0 0 0 14.122667 4.266667L448 128h96a42.666667 42.666667 0 0 0 0-85.333333h-85.973333l-204.288-102.144a42.666667 42.666667 0 0 0-61.44 33.237333L192-21.333333V42.666667H85.333333a42.666667 42.666667 0 0 0-42.368 37.674666L42.666667 85.333333V725.333333a42.666667 42.666667 0 0 0 42.666666 42.666667h853.333334z m-204.8-546.133333a42.666667 42.666667 0 0 0 42.666666-42.666667V42.666667a42.666667 42.666667 0 0 0-85.333333 0v93.866666H597.333333a42.666667 42.666667 0 0 0-42.368 37.674667L554.666667 179.2a42.666667 42.666667 0 0 0 42.666666 42.666667h136.533334z m68.266666 204.8a42.666667 42.666667 0 0 0 42.666667-42.666667v-93.866667H938.666667a42.666667 42.666667 0 0 0 42.368-37.674666L981.333333 247.466667a42.666667 42.666667 0 0 0-42.666666-42.666667h-136.533334a42.666667 42.666667 0 0 0-42.666666 42.666667V384a42.666667 42.666667 0 0 0 42.666666 42.666667zM512 469.333333a42.666667 42.666667 0 0 0 0-85.333333H256a42.666667 42.666667 0 0 0 0 85.333333h256zM384 597.333333a42.666667 42.666667 0 1 0 0-85.333333H256a42.666667 42.666667 0 1 0 0 85.333333h128z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_comment_expand_text_input" unicode="" d="M938.666667 768a42.666667 42.666667 0 0 0 42.666666-42.666667v-234.666666a42.666667 42.666667 0 0 0-85.333333 0V682.666667H128v-554.666667h106.666667a42.666667 42.666667 0 0 0 42.368-37.674667L277.333333 85.333333v-37.589333l151.594667 75.733333a42.666667 42.666667 0 0 0 14.122667 4.266667L448 128h96a42.666667 42.666667 0 0 0 0-85.333333h-85.973333l-204.288-102.144a42.666667 42.666667 0 0 0-61.44 33.237333L192-21.333333V42.666667H85.333333a42.666667 42.666667 0 0 0-42.368 37.674666L42.666667 85.333333V725.333333a42.666667 42.666667 0 0 0 42.666666 42.666667h853.333334z m-298.666667-507.264a42.666667 42.666667 0 0 0 42.666667-42.666667v-90.026666l90.069333-0.042667a42.666667 42.666667 0 0 0 42.368-37.674667l0.298667-4.992a42.666667 42.666667 0 0 0-42.666667-42.666666H640a42.666667 42.666667 0 0 0-42.666667 42.666666v132.736a42.666667 42.666667 0 0 0 42.666667 42.666667zM938.666667 426.666667a42.666667 42.666667 0 0 0 42.666666-42.666667v-132.736a42.666667 42.666667 0 1 0-85.333333 0V341.333333h-90.069333a42.666667 42.666667 0 0 0-42.368 37.674667L763.264 384a42.666667 42.666667 0 0 0 42.666667 42.666667H938.666667z m-426.666667 42.666666a42.666667 42.666667 0 0 0 0-85.333333H256a42.666667 42.666667 0 0 0 0 85.333333h256zM384 597.333333a42.666667 42.666667 0 1 0 0-85.333333H256a42.666667 42.666667 0 1 0 0 85.333333h128z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_chart_graph" unicode="" d="M661.333333 810.666667a42.666667 42.666667 0 0 0 42.666667-42.666667v-192a42.666667 42.666667 0 0 0-42.666667-42.666667H554.666667V426.666667h192a42.666667 42.666667 0 0 0 42.666666-42.666667v-149.333333H896a42.666667 42.666667 0 0 0 42.666667-42.666667V0a42.666667 42.666667 0 0 0-42.666667-42.666667h-298.666667a42.666667 42.666667 0 0 0-42.666666 42.666667v192a42.666667 42.666667 0 0 0 42.666666 42.666667h106.666667V341.333333h-384v-106.666666H426.666667a42.666667 42.666667 0 0 0 42.666666-42.666667V0a42.666667 42.666667 0 0 0-42.666666-42.666667H128a42.666667 42.666667 0 0 0-42.666667 42.666667v192a42.666667 42.666667 0 0 0 42.666667 42.666667h106.666667V384a42.666667 42.666667 0 0 0 42.666666 42.666667H469.333333V533.333333H362.666667a42.666667 42.666667 0 0 0-42.666667 42.666667V768a42.666667 42.666667 0 0 0 42.666667 42.666667h298.666666zM384 149.333333H170.666667V42.666667h213.333333v106.666666z m469.333333 0h-213.333333V42.666667h213.333333v106.666666zM618.666667 725.333333h-213.333334v-106.666666h213.333334V725.333333z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_share1" unicode="" d="M746.666667 810.666667a149.333333 149.333333 0 1 0-106.453334-254.037334l-218.965333-132.608a149.461333 149.461333 0 0 0 1.024-76.117333l222.890667-131.712a149.333333 149.333333 0 1 0-43.434667-73.472l-222.890667 131.754667a149.333333 149.333333 0 1 0-2.986666 221.824l224.341333 135.893333A149.333333 149.333333 0 0 0 746.666667 810.666667z m0-640a64 64 0 1 1 0-128 64 64 0 0 1 0 128z m-469.333334 277.333333a64 64 0 1 1 0-128 64 64 0 0 1 0 128z m469.333334 277.333333a64 64 0 1 1 0-128 64 64 0 0 1 0 128z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_text" unicode="" d="M576 810.666667l3.114667-0.128 1.322666-0.085334L576 810.666667c2.986667 0 5.888-0.298667 8.704-0.853334l0.725333-0.213333 4.778667-1.365333a42.538667 42.538667 0 0 0 17.237333-11.392l234.666667-256 0.682667-0.768c0.768-0.853333 1.493333-1.749333 2.133333-2.688l-2.816 3.413333a43.008 43.008 0 0 0 10.88-23.466667L853.333333 512v-512a42.666667 42.666667 0 0 0-42.666666-42.666667H213.333333a42.666667 42.666667 0 0 0-42.666666 42.666667V768a42.666667 42.666667 0 0 0 42.666666 42.666667h362.666667z m-42.666667-85.333334H256v-682.666666h512V469.333333h-192a42.666667 42.666667 0 0 0-42.368 37.674667L533.333333 512V725.333333zM597.333333 298.666667a42.666667 42.666667 0 1 0 0-85.333334H341.333333a42.666667 42.666667 0 0 0 0 85.333334h256z m-170.666666 170.666666a42.666667 42.666667 0 1 0 0-85.333333H341.333333a42.666667 42.666667 0 0 0 0 85.333333h85.333334z m192 188.970667V554.666667h95.018666L618.666667 658.304z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_click" unicode="" d="M554.666667 853.333333a42.666667 42.666667 0 0 0 42.666666-42.666666v-170.666667a42.666667 42.666667 0 0 0-85.333333 0V810.666667a42.666667 42.666667 0 0 0 42.666667 42.666666z m-127.061334-439.296a46.208 46.208 0 0 0 54.357334 54.357334l462.208-92.416c40.362667-8.106667 50.773333-60.928 16.554666-83.797334l-91.733333-61.141333 98.773333-98.773333c16.64-16.682667 17.92-42.88 3.84-61.013334l-3.84-4.352-138.666666-138.666666a46.208 46.208 0 0 0-65.365334 0l-98.773333 98.773333-61.141333-91.733333c-21.802667-32.682667-70.954667-24.661333-82.432 11.264l-1.365334 5.290666-92.416 462.208z m104.192-49.834666l56.96-284.8 30.549334 45.781333a46.208 46.208 0 0 0 66.858666 10.88l4.266667-3.84 105.984-105.898667 73.258667 73.258667-105.941334 105.941333a46.208 46.208 0 0 0 2.474667 67.669334l4.608 3.498666 45.781333 30.549334-284.8 56.96z m288.768 348.16a44.202667 44.202667 0 0 0 62.506667-62.464l-125.013333-124.970667a44.202667 44.202667 0 0 0-62.464 62.506667l125.013333 124.970666z m-512-512a44.202667 44.202667 0 1 0 62.506667-62.464l-125.013333-124.970667a44.202667 44.202667 0 1 0-62.464 62.506667l125.013333 124.970666zM256 384a42.666667 42.666667 0 0 0 0-85.333333H85.333333a42.666667 42.666667 0 0 0 0 85.333333h170.666667zM183.594667 712.405333a44.202667 44.202667 0 0 0 62.506666 0l124.970667-125.013333a44.202667 44.202667 0 0 0-62.506667-62.464l-124.970666 125.013333a44.202667 44.202667 0 0 0 0 62.464z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_feedback_outlined" unicode="" d="M840.832 840.832A42.666667 42.666667 0 0 0 853.333333 810.666667v-341.333334h-85.333333V768H170.666667v-768h213.333333v-85.333333H128a42.666667 42.666667 0 0 0-42.666667 42.666666V810.666667a42.666667 42.666667 0 0 0 42.666667 42.666666h682.666667a42.666667 42.666667 0 0 0 30.165333-12.501333zM277.333333 640a21.333333 21.333333 0 0 1-21.333333-21.333333v-42.666667a21.333333 21.333333 0 0 1 21.333333-21.333333h384a21.333333 21.333333 0 0 1 21.333334 21.333333v42.666667a21.333333 21.333333 0 0 1-21.333334 21.333333h-384zM868.138667 158.848l-120.32 120.32-264.448-266.112L469.333333-100.949333a21.333333 21.333333 0 0 1 21.333334-21.333334l114.176 18.133334 263.296 262.997333zM899.114667 370.602667c-16.64 16.64-42.368 17.92-57.472 2.901333l-63.786667-64 120.490667-120.490667 63.872 63.744 2.005333 2.133334c12.970667 15.317333 11.093333 39.509333-4.778667 55.424l-60.330666 60.288zM256 448a21.333333 21.333333 0 0 0 21.333333 21.333333h298.666667a21.333333 21.333333 0 0 0 21.333333-21.333333v-42.666667a21.333333 21.333333 0 0 0-21.333333-21.333333h-298.666667a21.333333 21.333333 0 0 0-21.333333 21.333333v42.666667z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_done_outlined" unicode="" d="M840.832 840.832A42.666667 42.666667 0 0 0 853.333333 810.666667v-341.333334h-85.333333V768H170.666667v-768h213.333333v-85.333333H128a42.666667 42.666667 0 0 0-42.666667 42.666666V810.666667a42.666667 42.666667 0 0 0 42.666667 42.666666h682.666667a42.666667 42.666667 0 0 0 30.165333-12.501333zM277.333333 640a21.333333 21.333333 0 0 1-21.333333-21.333333v-42.666667a21.333333 21.333333 0 0 1 21.333333-21.333333h384a21.333333 21.333333 0 0 1 21.333334 21.333333v42.666667a21.333333 21.333333 0 0 1-21.333334 21.333333h-384zM256 448a21.333333 21.333333 0 0 0 21.333333 21.333333h298.666667a21.333333 21.333333 0 0 0 21.333333-21.333333v-42.666667a21.333333 21.333333 0 0 0-21.333333-21.333333h-298.666667a21.333333 21.333333 0 0 0-21.333333 21.333333v42.666667zM859.648 235.264l30.165333-30.165333a21.333333 21.333333 0 0 0 0-30.165334l-211.2-211.2a21.205333 21.205333 0 0 0-11.306666-5.930666l-2.474667-0.298667h-2.56a21.248 21.248 0 0 0-13.824 6.229333l-120.661333 120.661334a21.333333 21.333333 0 0 0 0 30.165333l30.165333 30.165333a21.333333 21.333333 0 0 0 30.165333 0l75.434667-75.392 165.973333 165.930667a21.333333 21.333333 0 0 0 30.122667 0z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_dataset_outlined" unicode="" d="M42.666667 569.856a42.666667 42.666667 0 0 0 25.002666 38.826667l426.666667 193.962666a42.666667 42.666667 0 0 0 35.328 0l426.666667-193.92a42.666667 42.666667 0 0 0 25.002666-38.826666v-415.530667a42.666667 42.666667 0 0 0-23.594666-38.144l-426.666667-213.333333a42.666667 42.666667 0 0 0-38.144 0l-426.666667 213.333333A42.666667 42.666667 0 0 0 42.666667 154.368V569.856z m777.301333 7.082667L512 716.928 202.368 576.213333l307.925333-132.693333 309.674667 133.418667zM554.666667 369.749333v-359.68l341.333333 170.666667V516.778667l-341.333333-147.029334zM128 515.328v-334.592l341.333333-170.666667v358.229334L128 515.328z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_outer-borders_outlined" unicode="" d="M910.208 736.725333c0 25.130667-20.352 45.482667-45.482667 45.482667H159.274667c-25.130667 0-45.525333-20.352-45.525334-45.482667v-705.450666c0-25.130667 20.394667-45.482667 45.525334-45.482667h705.450666c25.130667 0 45.482667 20.352 45.482667 45.482667V736.725333z m-711.082667-665.6V696.874667h625.749334v-625.749334H199.125333zM492.074667 663.722667a22.741333 22.741333 0 0 1-22.741334-22.784v-39.808c0-12.586667 10.197333-22.741333 22.741334-22.741334h39.850666A22.741333 22.741333 0 0 1 554.666667 601.130667v39.808a22.741333 22.741333 0 0 1-22.741334 22.784h-39.850666zM469.333333 522.410667c0 12.586667 10.197333 22.784 22.741334 22.784h39.850666c12.544 0 22.741333-10.197333 22.741334-22.784v-39.808a22.741333 22.741333 0 0 0-22.741334-22.741334h-39.850666A22.741333 22.741333 0 0 0 469.333333 482.56v39.808z m0-118.485334c0 12.544 10.197333 22.741333 22.741334 22.741334h39.850666c12.544 0 22.741333-10.197333 22.741334-22.741334v-39.850666a22.741333 22.741333 0 0 0-22.741334-22.741334h-39.850666a22.741333 22.741333 0 0 0-22.741334 22.741334v39.850666z m0-118.528c0 12.544 10.197333 22.741333 22.741334 22.741334h39.850666c12.544 0 22.741333-10.197333 22.741334-22.741334v-39.808a22.741333 22.741333 0 0 0-22.741334-22.784h-39.850666a22.741333 22.741333 0 0 0-22.741334 22.784v39.808z m22.741334-95.744a22.741333 22.741333 0 0 1-22.741334-22.784v-39.808c0-12.586667 10.197333-22.784 22.741334-22.784h39.850666a22.741333 22.741333 0 0 1 22.741334 22.784v39.808a22.741333 22.741333 0 0 1-22.741334 22.784h-39.850666z m214.272 214.272c0 12.544 10.24 22.741333 22.784 22.741334h39.808c12.586667 0 22.741333-10.197333 22.741333-22.741334v-39.850666a22.741333 22.741333 0 0 0-22.741333-22.741334h-39.808a22.741333 22.741333 0 0 0-22.784 22.741334v39.850666zM610.602667 426.666667a22.741333 22.741333 0 0 1-22.741334-22.741334v-39.850666c0-12.544 10.154667-22.741333 22.741334-22.741334h39.808a22.741333 22.741333 0 0 1 22.784 22.741334v39.850666a22.741333 22.741333 0 0 1-22.784 22.741334h-39.808z m-259.797334-22.741334c0 12.544 10.197333 22.741333 22.741334 22.741334h39.850666c12.544 0 22.741333-10.197333 22.741334-22.741334v-39.850666A22.741333 22.741333 0 0 0 413.44 341.333333h-39.850667a22.741333 22.741333 0 0 0-22.741333 22.741334v39.850666zM255.061333 426.666667a22.741333 22.741333 0 0 1-22.784-22.741334v-39.850666c0-12.544 10.24-22.741333 22.784-22.741334h39.808a22.741333 22.741333 0 0 1 22.741334 22.741334v39.850666A22.741333 22.741333 0 0 1 294.869333 426.666667h-39.808z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_checkbox" unicode="" d="M640 810.666667a42.666667 42.666667 0 0 0 0-85.333334H192a21.333333 21.333333 0 0 1-21.333333-21.333333v-640a21.333333 21.333333 0 0 1 21.333333-21.333333h640a21.333333 21.333333 0 0 1 21.333333 21.333333V469.333333a42.666667 42.666667 0 0 0 85.333334 0v-405.333333a106.666667 106.666667 0 0 0-106.666667-106.666667h-640A106.666667 106.666667 0 0 0 85.333333 64v640A106.666667 106.666667 0 0 0 192 810.666667H640z m259.456-29.269334a42.666667 42.666667 0 0 0 9.941333-59.52l-320-448a42.666667 42.666667 0 0 0-61.397333-8.533333l-213.333333 170.666667a42.666667 42.666667 0 1 0 53.333333 66.645333l178.090667-142.506667 293.845333 411.306667a42.666667 42.666667 0 0 0 59.52 9.941333z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_radio" unicode="" d="M512 853.333333c259.2 0 469.333333-210.133333 469.333333-469.333333s-210.133333-469.333333-469.333333-469.333333S42.666667 124.8 42.666667 384 252.8 853.333333 512 853.333333z m0-85.333333a384 384 0 1 1 0-768 384 384 0 0 1 0 768z m0-170.666667a213.333333 213.333333 0 1 0 0-426.666666 213.333333 213.333333 0 0 0 0 426.666666z m0-85.333333a128 128 0 1 1 0-256 128 128 0 0 1 0 256z" horiz-adv-x="1024" />
|
||||
|
@ -374,7 +438,7 @@
|
|||
|
||||
<glyph glyph-name="icon_file-sketch_colorful" unicode="" d="M170.666667 789.333333a42.666667 42.666667 0 0 0 42.666666 42.666667h417.834667a21.333333 21.333333 0 0 0 15.061333-6.229333l200.874667-200.874667a21.333333 21.333333 0 0 0 6.229333-15.061333V-21.333333a42.666667 42.666667 0 0 0-42.666666-42.666667H213.333333a42.666667 42.666667 0 0 0-42.666666 42.666667v810.666666zM170.666667 789.333333a42.666667 42.666667 0 0 0 42.666666 42.666667h417.834667a21.333333 21.333333 0 0 0 15.061333-6.229333l200.874667-200.874667a21.333333 21.333333 0 0 0 6.229333-15.061333V-21.333333a42.666667 42.666667 0 0 0-42.666666-42.666667H213.333333a42.666667 42.666667 0 0 0-42.666666 42.666667v810.666666zM640 830.08a21.290667 21.290667 0 0 0 6.229333-4.309333l200.874667-200.874667a21.376 21.376 0 0 0 4.309333-6.229333H682.666667a42.666667 42.666667 0 0 0-42.666667 42.666666V830.08zM428.202667 426.666667a31.018667 31.018667 0 0 1-24.618667-12.16l-55.893333-73.045334a31.018667 31.018667 0 0 1 0.426666-38.186666l139.605334-175.232a31.018667 31.018667 0 0 1 48.554666 0l139.605334 175.232a31.018667 31.018667 0 0 1 0.426666 38.186666l-55.893333 73.045334a31.018667 31.018667 0 0 1-24.618667 12.16h-167.594666z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_block_filled" unicode="" d="M512-85.333333c259.2 0 469.333333 210.133333 469.333333 469.333333S771.2 853.333333 512 853.333333 42.666667 643.2 42.666667 384s210.133333-469.333333 469.333333-469.333333zM298.666667 405.333333a21.333333 21.333333 0 0 0 21.333333 21.333334h384a21.333333 21.333333 0 0 0 21.333333-21.333334v-42.666666a21.333333 21.333333 0 0 0-21.333333-21.333334h-384a21.333333 21.333333 0 0 0-21.333333 21.333334v42.666666z" horiz-adv-x="1024" />
|
||||
<glyph glyph-name="icon_block_filled" unicode="" d="M981.333333 384c0-259.2-210.133333-469.333333-469.333333-469.333333S42.666667 124.79999999999995 42.666667 384 252.8 853.333333 512 853.333333s469.333333-210.133333 469.333333-469.333333zM320 426.666667a21.333333 21.333333 0 0 1-21.333333-21.333334v-42.666666a21.333333 21.333333 0 0 1 21.333333-21.333334h384a21.333333 21.333333 0 0 1 21.333333 21.333334v42.666666a21.333333 21.333333 0 0 1-21.333333 21.333334h-384z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_not-started_filled" unicode="" d="M981.333333 384c0-259.2-210.133333-469.333333-469.333333-469.333333S42.666667 124.79999999999995 42.666667 384 252.8 853.333333 512 853.333333s469.333333-210.133333 469.333333-469.333333z m-213.333333 64h-85.333333a21.248 21.248 0 0 1-21.333334-21.333333v-85.333334a21.333333 21.333333 0 0 1 21.333334-21.333333h85.333333a21.248 21.248 0 0 1 21.333333 21.333333v85.333334a21.248 21.248 0 0 1-21.333333 21.333333z m-426.666667 0H256a21.290667 21.290667 0 0 1-21.333333-21.333333v-85.333334a21.333333 21.333333 0 0 1 21.333333-21.333333h85.333333a21.333333 21.333333 0 0 1 21.333334 21.333333v85.333334a21.333333 21.333333 0 0 1-21.333334 21.333333z m221.482667-1.621333A21.248 21.248 0 0 1 554.666667 448h-85.333334a21.248 21.248 0 0 1-21.333333-21.333333v-85.333334a21.333333 21.333333 0 0 1 21.333333-21.333333h85.333334a21.248 21.248 0 0 1 21.333333 21.333333v85.333334a21.248 21.248 0 0 1-13.184 19.712z" horiz-adv-x="1024" />
|
||||
|
||||
|
@ -472,8 +536,6 @@
|
|||
|
||||
<glyph glyph-name="icon_new-item_outlined" unicode="" d="M896 810.666667a42.666667 42.666667 0 0 0 42.666667-42.666667v-768a42.666667 42.666667 0 0 0-42.666667-42.666667H128a42.666667 42.666667 0 0 0-42.666667 42.666667V768a42.666667 42.666667 0 0 0 42.666667 42.666667h768z m-64-85.333334h-640a21.333333 21.333333 0 0 1-21.205333-18.816L170.666667 704v-640a21.333333 21.333333 0 0 1 18.816-21.162667L192 42.66666699999996h640a21.333333 21.333333 0 0 1 21.205333 18.858666L853.333333 64v640a21.333333 21.333333 0 0 1-21.333333 21.333333z m-298.666667-128a21.333333 21.333333 0 0 0 21.333334-21.333333V426.666667h149.333333a21.333333 21.333333 0 0 0 21.333333-21.333334v-42.666666a21.248 21.248 0 0 0-21.333333-21.333334H554.666667v-149.333333a21.248 21.248 0 0 0-21.333334-21.333333h-42.666666a21.333333 21.333333 0 0 0-21.333334 21.333333V341.33333300000004H320a21.333333 21.333333 0 0 0-21.333333 21.333334v42.666666a21.333333 21.333333 0 0 0 21.333333 21.333334H469.333333V576a21.290667 21.290667 0 0 0 21.333334 21.333333h42.666666z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_logs_outlined-1" unicode="" d="M682.666667 768H213.333333v-768h597.333334V639.146667h-106.666667a21.333333 21.333333 0 0 0-21.333333 21.333333V768zM170.666667 853.333333h558.293333a42.666667 42.666667 0 0 0 30.208-12.501333l124.373333-124.373333a42.666667 42.666667 0 0 0 12.458667-30.165334V-42.666667a42.666667 42.666667 0 0 0-42.666667-42.666666H170.666667a42.666667 42.666667 0 0 0-42.666667 42.666666V810.666667a42.666667 42.666667 0 0 0 42.666667 42.666666z m170.666666-384h341.333334a21.333333 21.333333 0 0 0 21.333333-21.333333v-42.666667a21.333333 21.333333 0 0 0-21.333333-21.333333H341.333333a21.333333 21.333333 0 0 0-21.333333 21.333333v42.666667A21.333333 21.333333 0 0 0 341.333333 469.333333z m0-213.333333h192a21.248 21.248 0 0 0 21.333334-21.333333v-42.666667a21.248 21.248 0 0 0-21.333334-21.333333H341.333333a21.333333 21.333333 0 0 0-21.333333 21.333333v42.666667A21.333333 21.333333 0 0 0 341.333333 256z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_refresh_outlined" unicode="" d="M757.12 554.666667a298.666667 298.666667 0 1 1 41.173333-256h88.192A384 384 0 1 0 810.666667 625.365333V746.666667a21.333333 21.333333 0 0 0 21.333333 21.333333h42.666667a21.333333 21.333333 0 0 0 21.333333-21.333333V512a42.666667 42.666667 0 0 0-42.666667-42.666667h-234.666666a21.333333 21.333333 0 0 0-21.333334 21.333334v42.666666a21.333333 21.333333 0 0 0 21.333334 21.333334h138.453333z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_font-color_outlined" unicode="" d="M128 19.925333c0 12.544 9.813333 22.741333 21.930667 22.741334h724.138666c12.117333 0 21.930667-10.197333 21.930667-22.741334v-125.184c0-12.544-9.813333-22.741333-21.930667-22.741333H149.930667A22.357333 22.357333 0 0 0 128-105.258667v125.184zM462.634667 768a21.333333 21.333333 0 0 1-19.882667-13.653333L224.512 187.733333a21.333333 21.333333 0 0 1 19.882667-29.013333H297.813333a21.333333 21.333333 0 0 1 19.882667 13.525333l61.013333 155.562667A21.333333 21.333333 0 0 0 398.549333 341.333333h211.114667a21.333333 21.333333 0 0 0 20.138667-14.293333l53.845333-154.026667a21.333333 21.333333 0 0 1 20.138667-14.293333h53.632a21.333333 21.333333 0 0 1 19.882666 29.013333L559.061333 754.346667a21.333333 21.333333 0 0 1-19.882666 13.653333h-76.544z m-52.394667-341.333333l88.362667 239.914666a2.432 2.432 0 0 0 4.608 0L590.848 426.666667H410.24z" horiz-adv-x="1024" />
|
||||
|
@ -482,7 +544,7 @@
|
|||
|
||||
<glyph glyph-name="icon_moments-categories_outlined" unicode="" d="M523.477333 782.08l429.568-273.408a21.333333 21.333333 0 0 0 0-36.010667L523.52 199.296a21.333333 21.333333 0 0 0-22.912 0L70.954667 472.661333a21.333333 21.333333 0 0 0 0 36.010667l429.610666 273.365333a21.333333 21.333333 0 0 0 22.912 0zM201.6 490.666667L512 293.12l310.4 197.546667L512 688.213333 201.6 490.666667zM110.805333 303.530667a21.333333 21.333333 0 0 1-29.354666-7.04l-22.314667-36.394667a21.333333 21.333333 0 0 1 7.04-29.312l390.613333-239.530667a84.992 84.992 0 0 1 89.088 0l390.613334 239.530667a21.333333 21.333333 0 0 1 7.04 29.312l-22.314667 36.394667a21.333333 21.333333 0 0 1-29.312 7.04L506.88 67.413333a10.666667 10.666667 0 0 0-11.136 0l-384.981333 236.074667z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_doc-replace_outlined" unicode="" d="M85.333333-1.066667a45.653333 45.653333 0 0 1 45.482667-45.738666h295.68v85.76H170.581333V724.906667H767.573333v-300.202667h85.333334V764.928A45.653333 45.653333 0 0 1 807.338667 810.666667H130.816A45.653333 45.653333 0 0 1 85.333333 764.928v-765.994667zM255.914667 585.002667c0 6.357333 5.077333 11.477333 11.349333 11.477333h403.669333c6.272 0 11.392-5.12 11.392-11.477333v-62.890667c0-6.314667-5.12-11.434667-11.392-11.434667h-403.626666a11.392 11.392 0 0 0-11.392 11.434667V585.002667zM267.264 424.704a11.392 11.392 0 0 1-11.349333-11.434667v-62.890666c0-6.314667 5.077333-11.434667 11.349333-11.434667h173.397333c6.314667 0 11.392 5.12 11.392 11.434667v62.890666a11.392 11.392 0 0 1-11.392 11.434667H267.264zM891.52 170.752h-349.738667a21.333333 21.333333 0 0 0-21.333333 21.333333v42.666667a21.333333 21.333333 0 0 0 21.333333 21.333333h192v58.752a21.333333 21.333333 0 0 0 35.626667 15.872l136.405333-122.794666a21.333333 21.333333 0 0 0-14.293333-37.162667zM691.114667 0.085333v-58.794666a21.333333 21.333333 0 0 0-35.626667-15.829334l-136.405333 122.752a21.333333 21.333333 0 0 0 14.293333 37.205334h349.738667a21.333333 21.333333 0 0 0 21.333333-21.333334v-42.666666a21.333333 21.333333 0 0 0-21.333333-21.333334h-192z" horiz-adv-x="1024" />
|
||||
<glyph glyph-name="icon_doc-replace_outlined" unicode="" d="M891.52 170.75199999999995h-349.738667a21.333333 21.333333 0 0 0-21.333333 21.333333v42.666667a21.333333 21.333333 0 0 0 21.333333 21.333333h192v58.752a21.333333 21.333333 0 0 0 35.626667 15.872l136.405333-122.794666a21.333333 21.333333 0 0 0-14.293333-37.162667zM691.114667 0.08533299999999144v-58.794666a21.333333 21.333333 0 0 0-35.626667-15.829334l-136.405333 122.752a21.333333 21.333333 0 0 0 14.293333 37.205334h349.738667a21.333333 21.333333 0 0 0 21.333333-21.333334v-42.666666a21.333333 21.333333 0 0 0-21.333333-21.333334h-192zM840.832 840.832A42.666667 42.666667 0 0 0 853.333333 810.666667v-341.333334h-85.333333V768H170.666667v-768h213.333333v-85.333333H128a42.666667 42.666667 0 0 0-42.666667 42.666666V810.666667a42.666667 42.666667 0 0 0 42.666667 42.666666h682.666667a42.666667 42.666667 0 0 0 30.165333-12.501333zM277.333333 640a21.333333 21.333333 0 0 1-21.333333-21.333333v-42.666667a21.333333 21.333333 0 0 1 21.333333-21.333333h384a21.333333 21.333333 0 0 1 21.333334 21.333333v42.666667a21.333333 21.333333 0 0 1-21.333334 21.333333h-384zM256 448a21.333333 21.333333 0 0 0 21.333333 21.333333h298.666667a21.333333 21.333333 0 0 0 21.333333-21.333333v-42.666667a21.333333 21.333333 0 0 0-21.333333-21.333333h-298.666667a21.333333 21.333333 0 0 0-21.333333 21.333333v42.666667z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_italic_outlined" unicode="" d="M341.333333 746.666667a21.333333 21.333333 0 0 0 21.333334 21.333333h469.333333a21.333333 21.333333 0 0 0 21.333333-21.333333v-42.666667a21.333333 21.333333 0 0 0-21.333333-21.333333H640l-170.666667-597.333334h192a21.333333 21.333333 0 0 0 21.333334-21.333333v-42.666667a21.333333 21.333333 0 0 0-21.333334-21.333333h-469.333333a21.333333 21.333333 0 0 0-21.333333 21.333333v42.666667a21.333333 21.333333 0 0 0 21.333333 21.333333H384l170.666667 597.333334H362.666667a21.333333 21.333333 0 0 0-21.333334 21.333333v42.666667z" horiz-adv-x="1024" />
|
||||
|
||||
|
|
Before Width: | Height: | Size: 381 KiB After Width: | Height: | Size: 413 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -6,7 +6,7 @@
|
|||
{{ t('msBatchModal.batchModalSubTitle', { count: (props.selectData || []).length }) }}
|
||||
</div>
|
||||
</template>
|
||||
<a-spin :loading="loading">
|
||||
<a-spin :loading="loading" class="w-full">
|
||||
<a-alert v-if="props.action === 'batchAddProject'" class="mb-[16px]">
|
||||
{{ t('msBatchModal.batchModalTip') }}
|
||||
</a-alert>
|
||||
|
@ -19,8 +19,9 @@
|
|||
title: 'name',
|
||||
children: 'children',
|
||||
disabled: 'disabled',
|
||||
isLeaf: 'isLeaf',
|
||||
}"
|
||||
height="370px"
|
||||
show-search
|
||||
/>
|
||||
</a-spin>
|
||||
<template #footer>
|
||||
|
|
|
@ -135,7 +135,7 @@ export const MULTIPLE_INPUT = {
|
|||
title: '',
|
||||
value: [],
|
||||
props: {
|
||||
placeholder: t('formCreate.PleaseSelect'),
|
||||
placeholder: t('formCreate.PleaseEnter'),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -152,4 +152,3 @@
|
|||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@/store/modules/form-create/form-create
|
||||
|
|
|
@ -116,7 +116,7 @@
|
|||
}
|
||||
);
|
||||
const emits = defineEmits<{
|
||||
(e: 'confirm', isPass: boolean): void;
|
||||
(e: 'confirm', formValue?: { field: string }, cancel?: () => void): void;
|
||||
(e: 'cancel'): void;
|
||||
(e: 'update:visible', visible: boolean): void;
|
||||
}>();
|
||||
|
@ -131,6 +131,11 @@
|
|||
isPass.value = isValidatePass;
|
||||
};
|
||||
|
||||
// 表单
|
||||
const form = ref({
|
||||
field: props.fieldConfig?.field || '',
|
||||
});
|
||||
|
||||
// 校验表单
|
||||
const validateForm = async () => {
|
||||
await formRef.value?.validate((errors) => {
|
||||
|
@ -142,16 +147,6 @@
|
|||
});
|
||||
};
|
||||
|
||||
const handleConfirm = async () => {
|
||||
await validateForm();
|
||||
emits('confirm', isPass.value);
|
||||
};
|
||||
|
||||
// 表单
|
||||
const form = ref({
|
||||
field: props.fieldConfig?.field || '',
|
||||
});
|
||||
|
||||
// 重置
|
||||
const reset = () => {
|
||||
form.value.field = '';
|
||||
|
@ -164,6 +159,14 @@
|
|||
reset();
|
||||
};
|
||||
|
||||
const handleConfirm = async () => {
|
||||
await validateForm();
|
||||
if (props.isDelete) {
|
||||
emits('confirm');
|
||||
} else {
|
||||
emits('confirm', form.value, handleCancel);
|
||||
}
|
||||
};
|
||||
// 获取当前标题的样式
|
||||
const titleClass = computed(() => {
|
||||
return props.isDelete
|
||||
|
@ -208,6 +211,7 @@
|
|||
|
||||
defineExpose({
|
||||
form,
|
||||
isPass,
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
@ -595,4 +595,9 @@
|
|||
:deep(.arco-table .arco-table-expand-btn:hover) {
|
||||
border-color: transparent;
|
||||
}
|
||||
:deep(.arco-table-drag-handle) {
|
||||
.arco-icon-drag-dot-vertical {
|
||||
color: var(--color-text-brand);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<template v-for="(element, idx) in baseAction" :key="element.label">
|
||||
<a-divider v-if="element.isDivider" class="divider mx-0 my-[6px]" />
|
||||
<a-button
|
||||
v-else
|
||||
v-if="!element.isDivider && !element.children"
|
||||
class="ml-[12px]"
|
||||
:class="{
|
||||
'arco-btn-outline--danger': element.danger,
|
||||
|
@ -14,6 +14,28 @@
|
|||
@click="handleSelect(element)"
|
||||
>{{ t(element.label as string) }}</a-button
|
||||
>
|
||||
<!-- baseAction多菜单选择 -->
|
||||
<a-dropdown v-if="!element.isDivider && element.children" position="tr" @select="handleSelect">
|
||||
<a-button
|
||||
class="ml-[12px]"
|
||||
:class="{
|
||||
'arco-btn-outline--danger': element.danger,
|
||||
'ml-[16px]': idx === 0,
|
||||
}"
|
||||
type="outline"
|
||||
@click="handleSelect"
|
||||
>{{ t(element.label as string) }}</a-button
|
||||
>
|
||||
<template #content>
|
||||
<template v-for="item in element.children" :key="item.label">
|
||||
<a-divider v-if="element.isDivider" margin="4px" />
|
||||
<a-doption v-else :value="item" :class="{ delete: item.danger }">
|
||||
{{ t(item.label as string) }}
|
||||
</a-doption>
|
||||
</template>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
<!-- baseAction多菜单选择 -->
|
||||
</template>
|
||||
<div v-if="moreAction?.length" class="drop-down relative ml-[16px] inline-block">
|
||||
<a-dropdown position="tr" @select="handleSelect">
|
||||
|
|
|
@ -117,6 +117,7 @@ export interface BatchActionParams {
|
|||
eventTag?: string;
|
||||
isDivider?: boolean;
|
||||
danger?: boolean;
|
||||
children?: BatchActionParams[];
|
||||
}
|
||||
export interface BatchActionConfig {
|
||||
baseAction: BatchActionParams[];
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
const attrs = useAttrs();
|
||||
|
||||
const filterTagList = computed(() => {
|
||||
return props.tagList.filter((item: any) => item) || [];
|
||||
return (props.tagList || []).filter((item: any) => item) || [];
|
||||
});
|
||||
|
||||
const showTagList = computed(() => {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="sticky top-[0] z-[9999] mb-[8px] flex justify-between bg-white">
|
||||
<div v-if="props.mode === 'remote'" class="sticky top-[0] z-[9999] mb-[8px] flex justify-between bg-white">
|
||||
<a-radio-group v-model:model-value="fileListTab" type="button" size="small">
|
||||
<a-radio value="all">{{ `${t('ms.upload.all')} (${innerFileList.length})` }}</a-radio>
|
||||
<a-radio value="waiting">{{ `${t('ms.upload.uploading')} (${totalWaitingFileList.length})` }}</a-radio>
|
||||
|
@ -105,15 +105,21 @@
|
|||
import { getFileEnum, getFileIcon } from './iconMap';
|
||||
import type { MsFileItem } from './types';
|
||||
|
||||
const props = defineProps<{
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
mode?: 'static' | 'remote'; // 静态|远程
|
||||
fileList: MsFileItem[];
|
||||
uploadFunc: (params: any) => Promise<any>; // 上传文件时,自定义上传方法
|
||||
uploadFunc?: (params: any) => Promise<any>; // 上传文件时,自定义上传方法
|
||||
requestParams?: Record<string, any>; // 上传文件时,额外的请求参数
|
||||
route?: string; // 用于后台上传文件时,查看详情跳转的路由
|
||||
routeQuery?: Record<string, string>; // 用于后台上传文件时,查看详情跳转的路由参数
|
||||
handleDelete?: (item: MsFileItem) => void;
|
||||
handleReupload?: (item: MsFileItem) => void;
|
||||
}>();
|
||||
}>(),
|
||||
{
|
||||
mode: 'remote',
|
||||
}
|
||||
);
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:fileList', fileList: MsFileItem[]): void;
|
||||
(e: 'delete', item: MsFileItem): void;
|
||||
|
@ -179,9 +185,11 @@
|
|||
*/
|
||||
function startUpload() {
|
||||
emit('start');
|
||||
if (props.mode === 'remote' && props.uploadFunc) {
|
||||
asyncTaskStore.setUploadFunc(props.uploadFunc, props.requestParams);
|
||||
asyncTaskStore.startUpload(innerFileList.value, props.route, props.routeQuery);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 后台上传
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<template>
|
||||
<a-upload
|
||||
v-if="showDropArea"
|
||||
v-bind="{ ...props }"
|
||||
v-model:file-list="fileList"
|
||||
:accept="
|
||||
|
@ -9,6 +10,10 @@
|
|||
"
|
||||
:multiple="props.multiple"
|
||||
:disabled="props.disabled"
|
||||
:class="getAllScreenClass"
|
||||
:style="{
|
||||
width: props.isAllScreen ? `calc(100% - ${menuWidth}px - 16px)` : '100%',
|
||||
}"
|
||||
@change="handleChange"
|
||||
@before-upload="beforeUpload"
|
||||
>
|
||||
|
@ -80,6 +85,7 @@
|
|||
sizeUnit: 'MB' | 'KB'; // 文件大小单位
|
||||
isLimit: boolean; // 是否限制文件大小
|
||||
draggable: boolean; // 是否支持拖拽上传
|
||||
isAllScreen?: boolean; // 是否是全屏显示拖拽上传
|
||||
}> & {
|
||||
accept: UploadType;
|
||||
fileList: MsFileItem[];
|
||||
|
@ -88,7 +94,9 @@
|
|||
const props = withDefaults(defineProps<UploadProps>(), {
|
||||
showSubText: true,
|
||||
isLimit: true,
|
||||
isAllScreen: false,
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:fileList', 'change']);
|
||||
|
||||
const defaultMaxSize = 50;
|
||||
|
@ -126,16 +134,97 @@
|
|||
function handleChange(_fileList: MsFileItem[], fileItem: MsFileItem) {
|
||||
emit('change', _fileList, fileItem);
|
||||
}
|
||||
|
||||
const total = ref(''); // 总高度
|
||||
const other = ref(''); // 被减去高度
|
||||
const showDropArea = ref(false);
|
||||
|
||||
watch(
|
||||
() => props.isAllScreen,
|
||||
(val) => {
|
||||
if (val) {
|
||||
total.value = '100vh';
|
||||
other.value = '110px';
|
||||
showDropArea.value = false;
|
||||
} else {
|
||||
total.value = '154px';
|
||||
other.value = '0px';
|
||||
showDropArea.value = true;
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
const getAllScreenClass = computed(() => {
|
||||
return props.isAllScreen ? ['!fixed', 'right-[16px]', '-bottom-[10px]', 'z-[999]', 'opacity-90'] : [];
|
||||
});
|
||||
|
||||
// 禁用默认拖拽事件
|
||||
function disableDefaultEvents() {
|
||||
const doc = document.documentElement;
|
||||
doc.addEventListener('dragleave', (e) => e.preventDefault()); // 拖离
|
||||
doc.addEventListener('drop', (e) => e.preventDefault()); // 拖后放
|
||||
doc.addEventListener('dragenter', (e) => e.preventDefault()); // 拖进
|
||||
doc.addEventListener('dragover', (e) => e.preventDefault()); // 结束拖拽
|
||||
}
|
||||
|
||||
const menuWidth = ref<number>();
|
||||
const resizeObserver = ref();
|
||||
const targetElement = ref();
|
||||
|
||||
function init() {
|
||||
const ele = document.querySelector('body');
|
||||
targetElement.value = document.querySelector('.menu-wrapper');
|
||||
resizeObserver.value = new ResizeObserver((entries) => {
|
||||
entries.forEach((item) => {
|
||||
menuWidth.value = item.contentRect.width;
|
||||
});
|
||||
});
|
||||
|
||||
resizeObserver.value.observe(targetElement.value);
|
||||
menuWidth.value = targetElement.value.getBoundingClientRect().width;
|
||||
if (ele) {
|
||||
ele.addEventListener('dragenter', () => {
|
||||
showDropArea.value = true;
|
||||
});
|
||||
// 拖后放
|
||||
ele.addEventListener('dragleave', (e: any) => {
|
||||
if (
|
||||
e.target.nodeName === 'HTML' ||
|
||||
e.target === e.explicitOriginalTarget ||
|
||||
(!e.fromElement &&
|
||||
(e.clientX <= 0 || e.clientY <= 0 || e.clientX >= window.innerWidth || e.clientY >= window.innerHeight))
|
||||
) {
|
||||
showDropArea.value = false;
|
||||
}
|
||||
});
|
||||
// 拖离
|
||||
ele.addEventListener('drop', (e) => {
|
||||
showDropArea.value = false;
|
||||
e.preventDefault();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
disableDefaultEvents();
|
||||
init();
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
resizeObserver.value.disconnect();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.ms-upload-area {
|
||||
@apply flex w-full flex-col items-center justify-center;
|
||||
|
||||
height: 154px;
|
||||
height: calc(v-bind(total) - v-bind(other));
|
||||
border: 1px dashed var(--color-text-input-border);
|
||||
border-color: rgb(var(--primary-5)) !important;
|
||||
border-radius: var(--border-radius-small);
|
||||
background-color: var(--color-text-n9);
|
||||
|
||||
@apply flex flex-col items-center justify-center;
|
||||
.ms-upload-icon-box {
|
||||
@apply rounded-full bg-white;
|
||||
|
||||
|
|
|
@ -11,4 +11,5 @@ export type MsFileItem = FileItem & {
|
|||
enable?: boolean; // jar类型文件是否可用
|
||||
uploadedTime?: string | number; // 上传完成时间
|
||||
errMsg?: string; // 上传失败的错误信息
|
||||
[key: string]: any;
|
||||
};
|
||||
|
|
|
@ -337,4 +337,34 @@ export const pathMap: PathMapItem[] = [
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'FEATURE_TEST', // 功能测试
|
||||
locale: 'menu.featureTest',
|
||||
route: RouteEnum.FEATURE_TEST,
|
||||
permission: [],
|
||||
level: MENU_LEVEL[2],
|
||||
children: [
|
||||
{
|
||||
key: 'FEATURE_TEST_CASE', // 功能测试-功能用例
|
||||
locale: 'menu.featureTest.featureCase',
|
||||
route: RouteEnum.FEATURE_TEST_CASE,
|
||||
permission: [],
|
||||
level: MENU_LEVEL[2],
|
||||
},
|
||||
{
|
||||
key: 'FEATURE_TEST_CASE_DETAIL', // 功能测试-功能用例
|
||||
locale: 'menu.featureTest.featureCaseDetail',
|
||||
route: RouteEnum.FEATURE_TEST_CASE_DETAIL,
|
||||
permission: [],
|
||||
level: MENU_LEVEL[2],
|
||||
},
|
||||
{
|
||||
key: 'FEATURE_TEST_CASE_RECYCLE', // 功能测试-功能用例-回收站
|
||||
locale: 'menu.featureTest.featureCaseRecycle',
|
||||
route: RouteEnum.FEATURE_TEST_CASE_RECYCLE,
|
||||
permission: [],
|
||||
level: MENU_LEVEL[2],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
export enum StatusType {
|
||||
UN_REVIEWED = 'icon-icon_block_filled', // 未评审
|
||||
UNDER_REVIEWED = 'icon-icon_testing', // 评审中
|
||||
PASS = 'icon-icon_succeed_colorful', // 已通过
|
||||
UN_PASS = 'icon-icon_close_colorful', // 未通过
|
||||
RE_REVIEWED = 'icon-icon_resubmit_filled', // 重新提审
|
||||
UN_EXECUTED = 'icon-icon_block_filled', // 未执行
|
||||
PASSED = 'icon-icon_succeed_colorful', // 已执行
|
||||
FAILED = 'icon-icon_close_colorful', // 失败
|
||||
BLOCKED = 'icon-icon_block_filled', // 阻塞
|
||||
SKIPPED = 'icon-icon_skip_planarity', // 跳过
|
||||
}
|
||||
|
||||
export default {};
|
|
@ -5,6 +5,10 @@ export enum FormCreateKeyEnum {
|
|||
PROJECT_DEFECT_SYNC_TEMPLATE = 'ProjectDefectSyncTemplate',
|
||||
// 关联需求
|
||||
PROJECT__RELATED_TEMPLATE = 'ProjectRelatedTemplate',
|
||||
// 功能用例自定义字段
|
||||
CASE_MANAGEMENT_FIELD = 'caseManagementFields',
|
||||
// 自定义属性
|
||||
CASE_CUSTOM_ATTRS = 'caseCustomAttributes',
|
||||
}
|
||||
|
||||
export default {};
|
||||
|
|
|
@ -9,6 +9,8 @@ export enum BugManagementRouteEnum {
|
|||
export enum FeatureTestRouteEnum {
|
||||
FEATURE_TEST = 'featureTest',
|
||||
FEATURE_TEST_CASE = 'featureTestCase',
|
||||
FEATURE_TEST_CASE_RECYCLE = 'featureTestCaseRecycle',
|
||||
FEATURE_TEST_CASE_DETAIL = 'featureTestCaseDetail',
|
||||
}
|
||||
|
||||
export enum PerformanceTestRouteEnum {
|
||||
|
|
|
@ -25,9 +25,13 @@ export enum TableKeyEnum {
|
|||
ORGANIZATION_PROJECT_USER_DRAWER = 'organizationProjectUserDrawer',
|
||||
FILE_MANAGEMENT_FILE = 'fileManagementFile',
|
||||
FILE_MANAGEMENT_CASE = 'fileManagementCase',
|
||||
FILE_MANAGEMENT_CASE_RECYCLE = 'fileManagementCaseRecycle',
|
||||
FILE_MANAGEMENT_VERSION = 'fileManagementVersion',
|
||||
PROJECT_MANAGEMENT_MENU_FALSE_ALERT = 'projectManagementMenuFalseAlert',
|
||||
ORGANIZATION_TEMPLATE_DEFECT_TABLE = 'organizationTemplateManagementDefect',
|
||||
CASE_MANAGEMENT_TABLE = 'caseManagement',
|
||||
CASE_MANAGEMENT_DETAIL_TABLE = 'caseManagementDetailTable',
|
||||
CASE_MANAGEMENT_ASSOCIATED_TABLE = 'caseManagementAssociatedFileTable',
|
||||
BUG_MANAGEMENT = 'bugManagement',
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,9 @@ export default {
|
|||
'menu.projectManagement.messageManagement': '消息管理',
|
||||
'menu.projectManagement.messageManagementEdit': '更新模板',
|
||||
'menu.featureTest.featureCase': '功能用例',
|
||||
'menu.featureTest.featureCaseRecycle': '回收站',
|
||||
'menu.featureTest.featureCaseList': '用例列表',
|
||||
'menu.featureTest.featureCaseDetail': '创建用例',
|
||||
'menu.projectManagement.projectPermission': '项目与权限',
|
||||
'menu.settings': '系统设置',
|
||||
'menu.settings.system': '系统',
|
||||
|
|
|
@ -0,0 +1,184 @@
|
|||
import { TableQueryParams } from '@/models/common';
|
||||
import { StatusType } from '@/enums/caseEnum';
|
||||
|
||||
export interface ModulesTreeType {
|
||||
id: string;
|
||||
name: string;
|
||||
type: string;
|
||||
parentId: string;
|
||||
children: ModulesTreeType[];
|
||||
attachInfo: Record<string, any>; // 附加信息
|
||||
count: number; // 节点资源数量(多数情况下不会随着节点信息返回,视接口而定)
|
||||
}
|
||||
// 创建模块
|
||||
export interface CreateOrUpdateModule {
|
||||
projectId: string;
|
||||
name: string;
|
||||
parentId: string;
|
||||
}
|
||||
// 更新模块
|
||||
export interface UpdateModule {
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
// 移动模块树
|
||||
export interface MoveModules {
|
||||
dragNodeId: string; // 被拖拽的节点
|
||||
dropNodeId: string; // 放入的节点
|
||||
dropPosition: number; // 放入的位置(取值:-1,,0,,1。 -1:dropNodeId节点之前。 0:dropNodeId节点内。 1:dropNodeId节点后)
|
||||
}
|
||||
|
||||
export interface customFieldsItem {
|
||||
caseId?: string; // 用例id
|
||||
fieldId: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
// 功能用例表
|
||||
export interface CaseManagementTable {
|
||||
id: string;
|
||||
num: number;
|
||||
moduleId: string; // 模块ID
|
||||
projectId: string;
|
||||
templateId: string; // 模板ID
|
||||
name: string; // 名称
|
||||
reviewStatus: StatusType[keyof StatusType]; // 评审状态:未评审/评审中/通过/不通过/重新提审
|
||||
tags: any; // 标签(JSON)
|
||||
caseEditType: string; // 编辑模式:步骤模式/文本模式
|
||||
pos: number; // 自定义排序,间隔5000
|
||||
versionId: string; // 版本ID
|
||||
refId: string; // 指向初始版本ID
|
||||
lastExecuteResult: string; // 最近的执行结果:未执行/通过/失败/阻塞/跳过
|
||||
deleted: true; // 是否在回收站:0-否,1-是
|
||||
publicCase: true; // 是否是公共用例:0-否,1-是
|
||||
latest: true; // 是否为最新版本:0-否,1-是
|
||||
createUser: string;
|
||||
updateUser: string;
|
||||
deleteUser: string;
|
||||
createTime: string;
|
||||
updateTime: string;
|
||||
deleteTime: string;
|
||||
customFields: customFieldsItem[]; // 自定义字段集合
|
||||
}
|
||||
|
||||
// 选择类型步骤和预期结果列表
|
||||
export interface StepList {
|
||||
id: string;
|
||||
step: string; // 步骤
|
||||
expected: string; // 预期
|
||||
showStep: boolean; // 编辑步骤模式
|
||||
showExpected: boolean; // 编辑预期模式
|
||||
}
|
||||
|
||||
// 关联文件列表
|
||||
export interface AssociatedList {
|
||||
id: string;
|
||||
name: string;
|
||||
fileType: string; // 文件类型
|
||||
projectId: string;
|
||||
tags: any;
|
||||
description: string;
|
||||
moduleName: string; // 模块名称
|
||||
moduleId: string;
|
||||
createUser: string;
|
||||
createTime: number | string;
|
||||
updateUser: string;
|
||||
updateTime: number;
|
||||
storage: string;
|
||||
size: number;
|
||||
enable: true;
|
||||
refId: string;
|
||||
filePath: string; // 文件路径
|
||||
[key: string]: any;
|
||||
}
|
||||
export interface CreateCaseType {
|
||||
request: CaseManagementTable;
|
||||
files: File[];
|
||||
}
|
||||
|
||||
export interface FileListQueryParams extends TableQueryParams {
|
||||
moduleIds: string[];
|
||||
versionId: string;
|
||||
projectId: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface DeleteCaseType {
|
||||
id: string;
|
||||
deleteAll?: boolean;
|
||||
projectId: string;
|
||||
}
|
||||
export interface BatchDeleteType {
|
||||
selectIds: string[];
|
||||
projectId: string;
|
||||
}
|
||||
|
||||
export interface OptionsFieldId {
|
||||
fieldId: string;
|
||||
value: string;
|
||||
text: string;
|
||||
internal: boolean; // 是否是内置
|
||||
}
|
||||
export interface CustomAttributes {
|
||||
fieldId: string;
|
||||
fieldName: string;
|
||||
required: boolean;
|
||||
apiFieldId: null | undefined | 'string'; // 三方API
|
||||
defaultValue: string;
|
||||
type: string;
|
||||
options: OptionsFieldId[];
|
||||
}
|
||||
|
||||
// 批量编辑
|
||||
export interface BatchEditCaseType {
|
||||
selectIds: string[];
|
||||
projectId: string;
|
||||
append: boolean; // 是否追加标签
|
||||
tags: string[];
|
||||
customField: {
|
||||
fieldId: string;
|
||||
value: string;
|
||||
};
|
||||
}
|
||||
// 批量移动
|
||||
export interface BatchMoveOrCopyType {
|
||||
selectIds: string[] | undefined;
|
||||
projectId: string;
|
||||
moduleId?: string;
|
||||
moduleIds: string[];
|
||||
selectAll: boolean;
|
||||
excludeIds: string[] | undefined;
|
||||
condition: Record<string, any>;
|
||||
}
|
||||
|
||||
export interface CreateCase {
|
||||
projectId: string;
|
||||
templateId: string;
|
||||
name: string;
|
||||
prerequisite: string; // prerequisite
|
||||
caseEditType: string; // 编辑模式:步骤模式/文本模式
|
||||
steps: string;
|
||||
textDescription: string;
|
||||
expectedResult: string; // 预期结果
|
||||
description: string;
|
||||
publicCase: boolean; // 是否公共用例
|
||||
moduleId: string;
|
||||
versionId: string;
|
||||
tags: any;
|
||||
customFields: Record<string, any>; // 自定义字段集合
|
||||
relateFileMetaIds: string[]; // 关联文件ID集合
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
// 回收站
|
||||
export interface CaseModuleQueryParams extends TableQueryParams {
|
||||
moduleIds: string[];
|
||||
projectId: string;
|
||||
}
|
||||
|
||||
// export interface BatchParams extends BatchMoveOrCopyType {
|
||||
// selectIds: string[];
|
||||
// selectAll: boolean;
|
||||
// moduleIds: string[];
|
||||
// projectId: string;
|
||||
// }
|
|
@ -36,7 +36,7 @@ export interface MemberItem {
|
|||
// 成员列表
|
||||
export type MemberList = MemberItem[];
|
||||
// 添加成员
|
||||
export interface AddorUpdateMemberModel {
|
||||
export interface AddOrUpdateMemberModel {
|
||||
id?: string;
|
||||
organizationId?: string;
|
||||
memberIds?: string[];
|
||||
|
|
|
@ -101,7 +101,8 @@ export interface CustomField {
|
|||
fieldId: string;
|
||||
required?: boolean; // 是否必填
|
||||
apiFieldId?: string; // api字段名
|
||||
defaultValue: string | string[] | null | number; // 默认值
|
||||
defaultValue?: string | string[] | null | number; // 默认值
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export interface ActionTemplateManage {
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
import { FeatureTestRouteEnum } 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',
|
||||
component: DEFAULT_LAYOUT,
|
||||
meta: {
|
||||
locale: 'menu.featureTest',
|
||||
icon: 'icon-icon_functional_testing',
|
||||
order: 3,
|
||||
hideChildrenInMenu: true,
|
||||
},
|
||||
children: [
|
||||
// 功能用例
|
||||
{
|
||||
path: 'featureCase',
|
||||
name: FeatureTestRouteEnum.FEATURE_TEST_CASE,
|
||||
component: () => import('@/views/case-management/caseManagementFeature/index.vue'),
|
||||
meta: {
|
||||
locale: 'menu.featureTest.featureCase',
|
||||
roles: ['*'],
|
||||
isTopMenu: true,
|
||||
},
|
||||
},
|
||||
// 功能用例回收站
|
||||
{
|
||||
path: 'featureCaseRecycle',
|
||||
name: FeatureTestRouteEnum.FEATURE_TEST_CASE_RECYCLE,
|
||||
component: () => import('@/views/case-management/caseManagementFeature/components/recycleCaseTable.vue'),
|
||||
meta: {
|
||||
locale: 'menu.featureTest.featureCaseRecycle',
|
||||
roles: ['*'],
|
||||
breadcrumbs: [
|
||||
{
|
||||
name: FeatureTestRouteEnum.FEATURE_TEST_CASE,
|
||||
locale: 'menu.featureTest.featureCaseList',
|
||||
},
|
||||
{
|
||||
name: FeatureTestRouteEnum.FEATURE_TEST_CASE_RECYCLE,
|
||||
locale: 'menu.featureTest.featureCaseRecycle',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
// 创建用例&编辑用例
|
||||
{
|
||||
path: 'featureCaseDetail',
|
||||
name: FeatureTestRouteEnum.FEATURE_TEST_CASE_DETAIL,
|
||||
component: () => import('@/views/case-management/caseManagementFeature/components/caseDetail.vue'),
|
||||
meta: {
|
||||
locale: 'menu.featureTest.featureCaseDetail',
|
||||
roles: ['*'],
|
||||
breadcrumbs: [
|
||||
{
|
||||
name: FeatureTestRouteEnum.FEATURE_TEST_CASE,
|
||||
locale: 'menu.featureTest.featureCase',
|
||||
},
|
||||
{
|
||||
name: FeatureTestRouteEnum.FEATURE_TEST_CASE_DETAIL,
|
||||
locale: 'menu.featureTest.featureCaseDetail',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default FeatureTest;
|
|
@ -1,32 +0,0 @@
|
|||
import { FeatureTestRouteEnum } 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',
|
||||
component: DEFAULT_LAYOUT,
|
||||
meta: {
|
||||
locale: 'menu.featureTest',
|
||||
icon: 'icon-icon_functional_testing',
|
||||
order: 3,
|
||||
hideChildrenInMenu: true,
|
||||
},
|
||||
children: [
|
||||
// 功能用例
|
||||
{
|
||||
path: 'featureCase',
|
||||
name: FeatureTestRouteEnum.FEATURE_TEST_CASE,
|
||||
component: () => import('@/views/feature-test/featureCase/index.vue'),
|
||||
meta: {
|
||||
locale: 'menu.featureTest.featureCase',
|
||||
roles: ['*'],
|
||||
isTopMenu: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default FeatureTest;
|
|
@ -0,0 +1,60 @@
|
|||
import { defineStore } from 'pinia';
|
||||
|
||||
import { getCaseModulesCounts, getRecycleModulesCounts } from '@/api/modules/case-management/featureCase';
|
||||
|
||||
import type { CaseModuleQueryParams } from '@/models/caseManagement/featureCase';
|
||||
import { ModuleTreeNode } from '@/models/projectManagement/file';
|
||||
|
||||
const useFeatureCaseStore = defineStore('featureCase', {
|
||||
persist: true,
|
||||
state: (): {
|
||||
moduleId: string[]; // 当前选中模块
|
||||
allModuleId: string[]; // 所有模块
|
||||
caseTree: ModuleTreeNode[]; // 用例树
|
||||
modulesCount: Record<string, any>; // 用例树模块数量
|
||||
recycleModulesCount: Record<string, any>; // 回收站模块数量
|
||||
operatingState: boolean; // 操作状态
|
||||
} => ({
|
||||
moduleId: [],
|
||||
allModuleId: [],
|
||||
caseTree: [],
|
||||
modulesCount: {},
|
||||
recycleModulesCount: {},
|
||||
operatingState: false,
|
||||
}),
|
||||
actions: {
|
||||
// 设置选择moduleId
|
||||
setModuleId(currentModuleId: string[], offspringIds: string[]) {
|
||||
this.moduleId = currentModuleId;
|
||||
if (offspringIds.length > 0) {
|
||||
this.allModuleId = offspringIds;
|
||||
}
|
||||
},
|
||||
// 设置用例树
|
||||
setModulesTree(tree: ModuleTreeNode[]) {
|
||||
this.caseTree = tree;
|
||||
},
|
||||
// 获取模块数量
|
||||
async getCaseModulesCountCount(params: CaseModuleQueryParams) {
|
||||
try {
|
||||
this.modulesCount = await getCaseModulesCounts(params);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
// 获取模块数量
|
||||
async getRecycleMModulesCountCount(params: CaseModuleQueryParams) {
|
||||
try {
|
||||
this.recycleModulesCount = await getRecycleModulesCounts(params);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
// 设置是否是编辑或者新增成功状态
|
||||
setIsAlreadySuccess(state: boolean) {
|
||||
this.operatingState = state;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default useFeatureCaseStore;
|
|
@ -0,0 +1,216 @@
|
|||
<template>
|
||||
<MsDrawer
|
||||
v-model:visible="showDrawer"
|
||||
:mask="false"
|
||||
:title="t('featureTest.featureCase.associatedFile')"
|
||||
:ok-text="t('featureTest.featureCase.associated')"
|
||||
:ok-loading="drawerLoading"
|
||||
:width="960"
|
||||
unmount-on-close
|
||||
:show-continue="false"
|
||||
@confirm="handleDrawerConfirm"
|
||||
@cancel="handleDrawerCancel"
|
||||
>
|
||||
<div class="mb-4 grid grid-cols-4 gap-2">
|
||||
<div class="col-end-4">
|
||||
<a-select v-model="fileType" @change="changeSelect">
|
||||
<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
|
||||
>
|
||||
</a-select></div
|
||||
>
|
||||
<div>
|
||||
<a-input-search
|
||||
v-model="searchParams.keyword"
|
||||
:max-length="250"
|
||||
:placeholder="t('project.member.searchMember')"
|
||||
allow-clear
|
||||
@search="searchHandler"
|
||||
@press-enter="searchHandler"
|
||||
></a-input-search
|
||||
></div>
|
||||
</div>
|
||||
<MsBaseTable v-bind="propsRes" v-on="propsEvent">
|
||||
<template #name="{ record }">
|
||||
<div class="flex items-center">
|
||||
<span> <MsIcon class="mr-1" :type="getFileType(record.fileType)" /></span>
|
||||
<span>{{ record.name }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</MsBaseTable>
|
||||
</MsDrawer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
|
||||
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
|
||||
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
||||
import type { MsTableColumn } from '@/components/pure/ms-table/type';
|
||||
import useTable from '@/components/pure/ms-table/useTable';
|
||||
import { FileIconMap, getFileEnum } from '@/components/pure/ms-upload/iconMap';
|
||||
|
||||
import { getAssociatedFileListUrl } from '@/api/modules/case-management/featureCase';
|
||||
import { getFileTypes } from '@/api/modules/project-management/fileManagement';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { useAppStore } from '@/store';
|
||||
|
||||
import type { AssociatedList } from '@/models/caseManagement/featureCase';
|
||||
import { TableQueryParams } from '@/models/common';
|
||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||
import { UploadStatus } from '@/enums/uploadEnum';
|
||||
|
||||
const { t } = useI18n();
|
||||
const showDrawer = ref<boolean>(false);
|
||||
const drawerLoading = ref<boolean>(false);
|
||||
const appStore = useAppStore();
|
||||
const getCurrentProjectId = computed(() => appStore.getCurrentProjectId);
|
||||
const fileTypeList = ref<string[]>([]);
|
||||
const fileType = ref('');
|
||||
|
||||
const props = defineProps<{
|
||||
visible: boolean;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:visible', val: boolean): void;
|
||||
(e: 'save', selectList: AssociatedList[]): void;
|
||||
}>();
|
||||
|
||||
const columns: MsTableColumn = [
|
||||
{
|
||||
title: 'featureTest.featureCase.fileName',
|
||||
dataIndex: 'name',
|
||||
slotName: 'name',
|
||||
showInTable: true,
|
||||
showTooltip: true,
|
||||
showDrag: false,
|
||||
width: 300,
|
||||
},
|
||||
{
|
||||
title: 'featureTest.featureCase.description',
|
||||
dataIndex: 'description',
|
||||
showInTable: true,
|
||||
showTooltip: true,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'featureTest.featureCase.tags',
|
||||
dataIndex: 'tags',
|
||||
isTag: true,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'featureTest.featureCase.tableColumnCreateUser',
|
||||
dataIndex: 'createUser',
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
},
|
||||
showTooltip: true,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'featureTest.featureCase.tableColumnUpdateUser',
|
||||
dataIndex: 'updateUser',
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
},
|
||||
showTooltip: true,
|
||||
showInTable: true,
|
||||
},
|
||||
{
|
||||
title: 'featureTest.featureCase.tableColumnUpdateTime',
|
||||
dataIndex: 'updateTime',
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
},
|
||||
showTooltip: true,
|
||||
showInTable: true,
|
||||
},
|
||||
];
|
||||
|
||||
const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector } = useTable(
|
||||
getAssociatedFileListUrl,
|
||||
{
|
||||
tableKey: TableKeyEnum.CASE_MANAGEMENT_ASSOCIATED_TABLE,
|
||||
selectable: true,
|
||||
noDisable: true,
|
||||
columns,
|
||||
scroll: {
|
||||
x: 1400,
|
||||
},
|
||||
heightUsed: 300,
|
||||
},
|
||||
(record) => ({
|
||||
...record,
|
||||
tags: record.tags || [],
|
||||
})
|
||||
);
|
||||
|
||||
const searchParams = ref<TableQueryParams>({
|
||||
keyword: '',
|
||||
filter: {},
|
||||
moduleIds: [],
|
||||
fileType: fileType.value,
|
||||
projectId: getCurrentProjectId.value,
|
||||
});
|
||||
|
||||
const initData = async () => {
|
||||
setLoadListParams({ ...searchParams.value });
|
||||
await loadList();
|
||||
};
|
||||
|
||||
const searchHandler = () => {
|
||||
initData();
|
||||
resetSelector();
|
||||
};
|
||||
|
||||
function changeSelect(value: string | number | boolean | Record<string, any>) {
|
||||
searchParams.value.fileType = value;
|
||||
initData();
|
||||
}
|
||||
const tableSelected = ref<AssociatedList[]>([]);
|
||||
|
||||
function handleDrawerConfirm() {
|
||||
const selectedIds = [...propsRes.value.selectedKeys];
|
||||
tableSelected.value = propsRes.value.data.filter((item: any) => selectedIds.indexOf(item.id) > -1);
|
||||
emit('save', tableSelected.value);
|
||||
showDrawer.value = false;
|
||||
propsRes.value.selectedKeys.clear();
|
||||
}
|
||||
|
||||
function handleDrawerCancel() {
|
||||
showDrawer.value = false;
|
||||
resetSelector();
|
||||
}
|
||||
|
||||
function getFileType(type: string) {
|
||||
const fileTypes = type ? getFileEnum(`/${type.toLowerCase()}`) : 'unknown';
|
||||
return FileIconMap[fileTypes][UploadStatus.done];
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(val) => {
|
||||
showDrawer.value = val;
|
||||
if (val) {
|
||||
initData();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => showDrawer.value,
|
||||
(val) => {
|
||||
emit('update:visible', val);
|
||||
}
|
||||
);
|
||||
|
||||
onBeforeMount(async () => {
|
||||
fileTypeList.value = await getFileTypes(appStore.currentProjectId);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
|
@ -0,0 +1,222 @@
|
|||
<template>
|
||||
<MsDialog
|
||||
v-model:visible="isVisible"
|
||||
dialog-size="small"
|
||||
:title="t('featureTest.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'),
|
||||
showSwitch: form.selectedAttrsId === 'systemTags' ? true : false,
|
||||
enable: form.append,
|
||||
}"
|
||||
>
|
||||
<div class="form">
|
||||
<a-form ref="formRef" :model="form" size="large" layout="vertical">
|
||||
<a-form-item
|
||||
field="selectedAttrsId"
|
||||
:label="t('featureTest.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-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-select>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
v-if="form.selectedAttrsId === 'systemTags'"
|
||||
field="tags"
|
||||
:label="t('featureTest.featureCase.batchUpdate')"
|
||||
asterisk-position="end"
|
||||
:rules="[{ required: true, message: t('featureTest.featureCase.PleaseInputTags') }]"
|
||||
>
|
||||
<a-input-tag
|
||||
v-model="form.tags"
|
||||
:placeholder="t('featureTest.featureCase.pleaseEnterInputTags')"
|
||||
allow-clear
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<MsFormCreate
|
||||
v-if="formRules.length && form.selectedAttrsId !== 'systemTags'"
|
||||
ref="formCreateRef"
|
||||
v-model:api="fApi"
|
||||
:form-rule="formRules"
|
||||
:form-create-key="FormCreateKeyEnum.CASE_CUSTOM_ATTRS"
|
||||
/>
|
||||
</a-form>
|
||||
</div>
|
||||
</MsDialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { FormInstance } from '@arco-design/web-vue';
|
||||
|
||||
import MsDialog from '@/components/pure/ms-dialog/index.vue';
|
||||
import MsFormCreate from '@/components/pure/ms-form-create/form-create.vue';
|
||||
import type { FormItem } from '@/components/pure/ms-form-create/types';
|
||||
import type { BatchActionQueryParams } from '@/components/pure/ms-table/type';
|
||||
|
||||
import { batchEditAttrs, getCaseDefaultFields } from '@/api/modules/case-management/featureCase';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
import useFormCreateStore from '@/store/modules/form-create/form-create';
|
||||
|
||||
import type { BatchEditCaseType, CustomAttributes } from '@/models/caseManagement/featureCase';
|
||||
import { FormCreateKeyEnum } from '@/enums/formCreateEnum';
|
||||
|
||||
import Message from '@arco-design/web-vue/es/message';
|
||||
|
||||
const isVisible = ref<boolean>(false);
|
||||
const appStore = useAppStore();
|
||||
const formCreateStore = useFormCreateStore();
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps<{
|
||||
visible: boolean;
|
||||
batchParams: BatchActionQueryParams;
|
||||
}>();
|
||||
|
||||
const emits = defineEmits<{
|
||||
(e: 'update:visible', visible: boolean): void;
|
||||
(e: 'success'): void;
|
||||
}>();
|
||||
|
||||
const currentProjectId = computed(() => appStore.currentProjectId);
|
||||
const initForm = {
|
||||
selectedAttrsId: '',
|
||||
append: false,
|
||||
tags: [],
|
||||
};
|
||||
const form = ref({ ...initForm });
|
||||
|
||||
const formRef = ref<FormInstance | null>(null);
|
||||
|
||||
const initDefaultForm: FormItem = {
|
||||
type: 'SELECT',
|
||||
name: 'name',
|
||||
label: 'featureTest.featureCase.batchUpdate',
|
||||
value: '',
|
||||
options: [],
|
||||
props: {
|
||||
modelValue: '',
|
||||
options: [],
|
||||
disabled: true,
|
||||
},
|
||||
required: true,
|
||||
};
|
||||
|
||||
/**
|
||||
* 初始化批量编辑属性
|
||||
*/
|
||||
const totalAttrs = ref<CustomAttributes[]>([]);
|
||||
|
||||
async function initDefaultFields() {
|
||||
try {
|
||||
const res = await getCaseDefaultFields(currentProjectId.value);
|
||||
totalAttrs.value = res.customFields;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
const formRules = ref<FormItem[]>([{ ...initDefaultForm }]);
|
||||
const fApi = ref<any>({});
|
||||
const formCreateValue = computed(() => formCreateStore.formCreateRuleMap.get(FormCreateKeyEnum.CASE_CUSTOM_ATTRS));
|
||||
|
||||
const updateType = computed(() => {
|
||||
return totalAttrs.value.find((item: any) => item.fieldId === form.value.selectedAttrsId)?.type;
|
||||
});
|
||||
|
||||
watch(
|
||||
() => updateType.value,
|
||||
(val) => {
|
||||
const currentAttrs = totalAttrs.value.filter((item: any) => item.fieldId === form.value.selectedAttrsId);
|
||||
if (val) {
|
||||
formRules.value = currentAttrs.map((item: CustomAttributes) => {
|
||||
return {
|
||||
type: val,
|
||||
name: item.fieldId,
|
||||
label: 'featureTest.featureCase.batchUpdate',
|
||||
value: item.defaultValue,
|
||||
options: item.options,
|
||||
props: {
|
||||
modelValue: item.defaultValue,
|
||||
options: item.options,
|
||||
disabled: !form.value.selectedAttrsId,
|
||||
},
|
||||
required: item.required,
|
||||
};
|
||||
}) as FormItem[];
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
function closeHandler() {
|
||||
isVisible.value = false;
|
||||
formRef.value?.resetFields();
|
||||
form.value = { ...initForm };
|
||||
formRules.value = [{ ...initDefaultForm }];
|
||||
}
|
||||
|
||||
async function confirmHandler(enable: boolean | undefined) {
|
||||
await formRef.value?.validate().then(async (error) => {
|
||||
if (!error) {
|
||||
try {
|
||||
const customField = {
|
||||
fieldId: '',
|
||||
value: '',
|
||||
};
|
||||
formCreateValue.value?.forEach((item: any) => {
|
||||
customField.fieldId = item.field;
|
||||
customField.value = JSON.stringify(item.value);
|
||||
});
|
||||
const params: BatchEditCaseType = {
|
||||
selectIds: props.batchParams.selectedIds as string[],
|
||||
projectId: currentProjectId.value,
|
||||
append: enable as boolean,
|
||||
tags: form.value.tags,
|
||||
customField,
|
||||
};
|
||||
await batchEditAttrs(params);
|
||||
Message.success(t('featureTest.featureCase.editSuccess'));
|
||||
closeHandler();
|
||||
emits('success');
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
watch(
|
||||
() => isVisible.value,
|
||||
(val) => {
|
||||
emits('update:visible', val);
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(val) => {
|
||||
isVisible.value = val;
|
||||
if (val) {
|
||||
initDefaultFields();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
formRules.value = [];
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
|
@ -0,0 +1,143 @@
|
|||
<template>
|
||||
<MsCard
|
||||
:loading="loading"
|
||||
:title="title"
|
||||
:is-edit="isEdit"
|
||||
has-breadcrumb
|
||||
@save="saveHandler"
|
||||
@save-and-continue="saveHandler(true)"
|
||||
>
|
||||
<template #headerRight>
|
||||
<a-select class="w-[240px]" :placeholder="t('featureTest.featureCase.versionPlaceholder')">
|
||||
<a-option v-for="template of versionOptions" :key="template.id" :value="template.id">{{
|
||||
template.name
|
||||
}}</a-option>
|
||||
</a-select>
|
||||
</template>
|
||||
<CaseTemplateDetail ref="caseModuleDetailRef" v-model:form-mode-value="caseDetailInfo" />
|
||||
</MsCard>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
|
||||
import MsCard from '@/components/pure/ms-card/index.vue';
|
||||
import CaseTemplateDetail from './caseTemplateDetail.vue';
|
||||
|
||||
import { createCaseRequest, updateCaseRequest } from '@/api/modules/case-management/featureCase';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useFeatureCaseStore from '@/store/modules/case/featureCase';
|
||||
import { scrollIntoView } from '@/utils/dom';
|
||||
|
||||
import { FeatureTestRouteEnum } from '@/enums/routeEnum';
|
||||
|
||||
import Message from '@arco-design/web-vue/es/message';
|
||||
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const featureCaseStore = useFeatureCaseStore();
|
||||
|
||||
const caseDetailInfo = ref<Record<string, any>>({
|
||||
request: {},
|
||||
fileList: [],
|
||||
});
|
||||
|
||||
const versionOptions = ref([
|
||||
{
|
||||
id: '1001',
|
||||
name: '模板01',
|
||||
},
|
||||
]);
|
||||
|
||||
const title = ref('');
|
||||
const loading = ref(false);
|
||||
const isEdit = computed(() => !!route.query.id);
|
||||
|
||||
const isContinueFlag = ref(false);
|
||||
|
||||
async function save() {
|
||||
try {
|
||||
loading.value = true;
|
||||
if (isEdit.value) {
|
||||
await updateCaseRequest(caseDetailInfo.value);
|
||||
Message.success(t('featureTest.featureCase.editSuccess'));
|
||||
} else {
|
||||
await createCaseRequest(caseDetailInfo.value);
|
||||
Message.success(t('common.addSuccess'));
|
||||
}
|
||||
router.push({ name: FeatureTestRouteEnum.FEATURE_TEST_CASE, query: { ...route.query } });
|
||||
featureCaseStore.setIsAlreadySuccess(true);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
const caseModuleDetailRef = ref();
|
||||
|
||||
// 保存
|
||||
function saveHandler(isContinue = false) {
|
||||
const { caseFormRef, formRef, fApi } = caseModuleDetailRef.value;
|
||||
isContinueFlag.value = isContinue;
|
||||
caseFormRef?.validate().then((res: any) => {
|
||||
if (!res) {
|
||||
fApi.validate((valid: any) => {
|
||||
if (valid === true) {
|
||||
formRef?.validate().then((result: any) => {
|
||||
if (!result) {
|
||||
return save();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
return scrollIntoView(document.querySelector('.arco-form-item-message'), { block: 'center' });
|
||||
});
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
if (isEdit.value) {
|
||||
title.value = t('featureTest.featureCase.updateCase');
|
||||
} else {
|
||||
title.value = t('featureTest.featureCase.creatingCase');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.wrapper-preview {
|
||||
display: flex;
|
||||
.preview-left {
|
||||
width: 100%;
|
||||
border-right: 1px solid var(--color-text-n8);
|
||||
.changeType {
|
||||
padding: 2px 4px;
|
||||
border-radius: 4px;
|
||||
color: var(--color-text-4);
|
||||
:deep(.arco-icon-down) {
|
||||
font-size: 14px;
|
||||
}
|
||||
&:hover {
|
||||
color: rgb(var(--primary-5));
|
||||
background: rgb(var(--primary-1));
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
.preview-right {
|
||||
width: 428px;
|
||||
}
|
||||
}
|
||||
.circle {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
line-height: 16px;
|
||||
border-radius: 50%;
|
||||
text-align: center;
|
||||
color: var(--color-text-4);
|
||||
background: var(--color-text-n8);
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,779 @@
|
|||
<template>
|
||||
<div class="page-header mb-4 h-[34px]">
|
||||
<div class="text-[var(--color-text-1)]"
|
||||
>{{ t('featureTest.featureCase.allCase') }}
|
||||
<span class="text-[var(--color-text-4)]"> ({{ props.modulesCount.all }})</span></div
|
||||
>
|
||||
<div class="flex w-[80%] items-center justify-end">
|
||||
<a-select class="w-[240px]" :placeholder="t('featureTest.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')"
|
||||
allow-clear
|
||||
class="mx-[8px] w-[240px]"
|
||||
@search="searchList"
|
||||
@press-enter="searchList"
|
||||
></a-input-search>
|
||||
<MsTag
|
||||
:type="isExpandFilter ? 'primary' : 'default'"
|
||||
:theme="isExpandFilter ? 'lightOutLine' : 'outline'"
|
||||
size="large"
|
||||
class="-mt-[3px] min-w-[64px] cursor-pointer"
|
||||
>
|
||||
<span :class="!isExpandFilter ? 'text-[var(--color-text-4)]' : ''" @click="isExpandFilterHandler"
|
||||
><icon-filter class="mr-[4px]" :style="{ 'font-size': '16px' }" />{{
|
||||
t('featureTest.featureCase.filter')
|
||||
}}</span
|
||||
>
|
||||
</MsTag>
|
||||
<a-radio-group v-model:model-value="showType" type="button" class="file-show-type ml-[4px]">
|
||||
<a-radio value="list" class="show-type-icon p-[2px]"><MsIcon type="icon-icon_view-list_outlined" /></a-radio>
|
||||
<a-radio value="xMind" class="show-type-icon p-[2px]"><MsIcon type="icon-icon_mindnote_outlined" /></a-radio>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
<FilterPanel v-show="isExpandFilter"></FilterPanel>
|
||||
<!-- 脑图开始 -->
|
||||
<MinderEditor
|
||||
v-if="showType === 'xMind'"
|
||||
:import-json="importJson"
|
||||
:tags="['模块', '用例', '前置条件', '备注', '步骤', '预期结果']"
|
||||
tag-enable
|
||||
sequence-enable
|
||||
@node-click="handleNodeClick"
|
||||
/>
|
||||
<MsDrawer v-model:visible="visible" :width="480" :mask="false">
|
||||
{{ nodeData.text }}
|
||||
</MsDrawer>
|
||||
<!-- 脑图结束 -->
|
||||
<!-- 用例表开始 -->
|
||||
<ms-base-table
|
||||
v-bind="propsRes"
|
||||
:action-config="tableBatchActions"
|
||||
@selected-change="handleTableSelect"
|
||||
v-on="propsEvent"
|
||||
@batch-action="handleTableBatch"
|
||||
>
|
||||
<template #name="{ record }">
|
||||
<a-button type="text" class="px-0" @click="showCaseDetail(record.id)">{{ record.name }}</a-button>
|
||||
</template>
|
||||
<template #reviewStatus="{ record }">
|
||||
<MsIcon
|
||||
:type="getStatusText(record.reviewStatus)?.iconType || ''"
|
||||
class="mr-1"
|
||||
:class="[getReviewStatusClass(record.reviewStatus)]"
|
||||
></MsIcon>
|
||||
<span>{{ getStatusText(record.reviewStatus)?.statusType || '' }} </span>
|
||||
</template>
|
||||
<template #lastExecuteResult="{ record }">
|
||||
<MsIcon
|
||||
:type="getStatusText(record.lastExecuteResult)?.iconType || ''"
|
||||
class="mr-1"
|
||||
:class="[getReviewStatusClass(record.lastExecuteResult)]"
|
||||
></MsIcon>
|
||||
<span>{{ getStatusText(record.lastExecuteResult)?.statusType || '' }}</span>
|
||||
</template>
|
||||
<template #moduleId="{ record }">
|
||||
<a-tooltip :content="getModules(record.moduleId)" position="top">
|
||||
<span class="one-line-text inline-block">{{ getModules(record.moduleId) }}</span>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<template #operation="{ record }">
|
||||
<MsButton @click="editCase(record)">{{ t('common.edit') }}</MsButton>
|
||||
<MsButton class="!mr-0" @click="deleteCase(record)">{{ t('common.delete') }}</MsButton>
|
||||
</template>
|
||||
</ms-base-table>
|
||||
<!-- 用例表结束 -->
|
||||
<a-modal
|
||||
v-model:visible="showBatchMoveDrawer"
|
||||
title-align="start"
|
||||
class="ms-modal-no-padding ms-modal-small"
|
||||
:mask-closable="false"
|
||||
:ok-text="
|
||||
t(
|
||||
isMove
|
||||
? 'featureTest.featureCase.batchMoveSelectedModules'
|
||||
: 'featureTest.featureCase.batchCopySelectedModules',
|
||||
{
|
||||
number: batchParams?.currentSelectCount || batchParams?.selectedIds?.length,
|
||||
}
|
||||
)
|
||||
"
|
||||
:ok-button-props="{ disabled: selectedModuleKeys.length === 0 }"
|
||||
:cancel-button-props="{ disabled: batchMoveCaseLoading }"
|
||||
:on-before-ok="handleCaseMoveOrCopy"
|
||||
@close="handleMoveCaseModalCancel"
|
||||
>
|
||||
<template #title>
|
||||
<div class="flex w-full items-center justify-between">
|
||||
<div>
|
||||
{{ isMove ? t('featureTest.featureCase.batchMoveTitle') : t('featureTest.featureCase.batchCopyTitle') }}
|
||||
<span class="ml-[4px] text-[var(--color-text-4)]">
|
||||
{{ t('featureTest.featureCase.batchMove', { number: batchParams.currentSelectCount }) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="mr-2">
|
||||
<a-select class="w-[120px]" placeholder="请选择版本">
|
||||
<a-option v-for="item of versionOptions" :key="item.id" :value="item.id">{{ item.name }}</a-option>
|
||||
</a-select>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<FeatureCaseTree
|
||||
v-if="showBatchMoveDrawer"
|
||||
ref="caseTreeRef"
|
||||
v-model:selected-keys="selectedModuleKeys"
|
||||
:active-folder="props.activeFolder"
|
||||
:is-expand-all="true"
|
||||
is-modal
|
||||
@case-node-select="caseNodeSelect"
|
||||
></FeatureCaseTree>
|
||||
</a-modal>
|
||||
<ExportExcelDrawer v-model:visible="showExportExcelVisible" />
|
||||
<BatchEditModal v-model:visible="showEditModel" :batch-params="batchParams" @success="successHandler" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
|
||||
import MinderEditor from '@/components/pure/minder-editor/minderEditor.vue';
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsDrawer from '@/components/pure/ms-drawer/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 MsTag from '@/components/pure/ms-tag/ms-tag.vue';
|
||||
import FilterPanel from '@/components/business/ms-filter-panel/searchForm.vue';
|
||||
import BatchEditModal from './batchEditModal.vue';
|
||||
import FeatureCaseTree from './caseTree.vue';
|
||||
import ExportExcelDrawer from './exportExcelDrawer.vue';
|
||||
|
||||
import {
|
||||
batchCopyToModules,
|
||||
batchDeleteCase,
|
||||
batchMoveToModules,
|
||||
deleteCaseRequest,
|
||||
getCaseDetail,
|
||||
getCaseList,
|
||||
updateCaseRequest,
|
||||
} from '@/api/modules/case-management/featureCase';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useModal from '@/hooks/useModal';
|
||||
import { useAppStore, useTableStore } from '@/store';
|
||||
import useFeatureCaseStore from '@/store/modules/case/featureCase';
|
||||
import { characterLimit, findNodePathByKey } from '@/utils';
|
||||
|
||||
import type { CaseManagementTable, CaseModuleQueryParams } from '@/models/caseManagement/featureCase';
|
||||
import type { TableQueryParams } from '@/models/common';
|
||||
import { FeatureTestRouteEnum } from '@/enums/routeEnum';
|
||||
import { ColumnEditTypeEnum, TableKeyEnum } from '@/enums/tableEnum';
|
||||
|
||||
import { getReviewStatusClass, getStatusText } from './utils';
|
||||
import debounce from 'lodash-es/debounce';
|
||||
|
||||
const { openModal } = useModal();
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
const appStore = useAppStore();
|
||||
const featureCaseStore = useFeatureCaseStore();
|
||||
const tableStore = useTableStore();
|
||||
|
||||
const props = defineProps<{
|
||||
activeFolder: string;
|
||||
activeFolderType: 'folder' | 'module';
|
||||
offspringIds: string[]; // 当前选中文件夹的所有子孙节点id
|
||||
modulesCount: Record<string, number>; // 模块数量
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'init', params: CaseModuleQueryParams): void;
|
||||
}>();
|
||||
|
||||
const keyword = ref<string>();
|
||||
|
||||
const showType = ref<string>('list');
|
||||
|
||||
const isExpandFilter = ref<boolean>(false);
|
||||
|
||||
const versionOptions = ref([
|
||||
{
|
||||
id: '1001',
|
||||
name: 'v_1.0',
|
||||
},
|
||||
]);
|
||||
|
||||
const caseTreeData = computed(() => featureCaseStore.caseTree);
|
||||
const moduleId = computed(() => featureCaseStore.moduleId[0]);
|
||||
const currentProjectId = computed(() => appStore.currentProjectId);
|
||||
|
||||
// 是否展开||折叠高级筛选
|
||||
const isExpandFilterHandler = () => {
|
||||
isExpandFilter.value = !isExpandFilter.value;
|
||||
};
|
||||
|
||||
const visible = ref<boolean>(false);
|
||||
const nodeData = ref<any>({});
|
||||
|
||||
const importJson = ref<any>({});
|
||||
|
||||
function handleNodeClick(data: any) {
|
||||
if (data.resource && data.resource.includes('用例')) {
|
||||
visible.value = true;
|
||||
nodeData.value = data;
|
||||
}
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
importJson.value = {
|
||||
root: {
|
||||
data: {
|
||||
text: '测试用例',
|
||||
id: 'xxxx',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
data: {
|
||||
id: 'sdasdas',
|
||||
text: '模块 1',
|
||||
resource: ['模块'],
|
||||
},
|
||||
},
|
||||
{
|
||||
data: {
|
||||
id: 'dasdasda',
|
||||
text: '模块 2',
|
||||
expandState: 'collapse',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
data: {
|
||||
id: 'frihofiuho3f',
|
||||
text: '用例 1',
|
||||
resource: ['用例'],
|
||||
},
|
||||
},
|
||||
{
|
||||
data: {
|
||||
id: 'df09348f034f',
|
||||
text: ' 用例 2',
|
||||
resource: ['用例'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
template: 'default',
|
||||
};
|
||||
});
|
||||
|
||||
const columns: MsTableColumn = [
|
||||
{
|
||||
title: 'featureTest.featureCase.tableColumnID',
|
||||
dataIndex: 'id',
|
||||
width: 200,
|
||||
showInTable: true,
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
},
|
||||
showTooltip: true,
|
||||
ellipsis: true,
|
||||
showDrag: false,
|
||||
},
|
||||
{
|
||||
title: 'featureTest.featureCase.tableColumnName',
|
||||
slotName: 'name',
|
||||
dataIndex: 'name',
|
||||
showInTable: true,
|
||||
showTooltip: true,
|
||||
width: 300,
|
||||
editType: ColumnEditTypeEnum.INPUT,
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
},
|
||||
ellipsis: true,
|
||||
showDrag: false,
|
||||
},
|
||||
{
|
||||
title: 'featureTest.featureCase.tableColumnLevel',
|
||||
dataIndex: 'level',
|
||||
showInTable: true,
|
||||
width: 200,
|
||||
showTooltip: true,
|
||||
ellipsis: true,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'featureTest.featureCase.tableColumnCaseState',
|
||||
dataIndex: 'caseState',
|
||||
showInTable: true,
|
||||
width: 200,
|
||||
showTooltip: true,
|
||||
ellipsis: true,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'featureTest.featureCase.tableColumnReviewResult',
|
||||
dataIndex: 'reviewStatus',
|
||||
slotName: 'reviewStatus',
|
||||
showInTable: true,
|
||||
width: 200,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'featureTest.featureCase.tableColumnExecutionResult',
|
||||
dataIndex: 'lastExecuteResult',
|
||||
slotName: 'lastExecuteResult',
|
||||
showInTable: true,
|
||||
width: 200,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'featureTest.featureCase.tableColumnVersion',
|
||||
slotName: 'versionId',
|
||||
dataIndex: 'versionId',
|
||||
width: 300,
|
||||
showTooltip: true,
|
||||
showInTable: true,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'featureTest.featureCase.tableColumnModule',
|
||||
slotName: 'moduleId',
|
||||
showInTable: true,
|
||||
width: 300,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'featureTest.featureCase.tableColumnTag',
|
||||
slotName: 'tags',
|
||||
dataIndex: 'tags',
|
||||
showInTable: true,
|
||||
isTag: true,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'featureTest.featureCase.tableColumnCreateUser',
|
||||
slotName: 'createUser',
|
||||
dataIndex: 'createUser',
|
||||
showInTable: true,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'featureTest.featureCase.tableColumnCreateTime',
|
||||
slotName: 'createTime',
|
||||
dataIndex: 'createTime',
|
||||
showInTable: true,
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
},
|
||||
width: 200,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'featureTest.featureCase.tableColumnUpdateUser',
|
||||
slotName: 'updateUser',
|
||||
dataIndex: 'updateUser',
|
||||
showInTable: true,
|
||||
width: 200,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'featureTest.featureCase.tableColumnUpdateTime',
|
||||
slotName: 'updateTime',
|
||||
dataIndex: 'updateTime',
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
},
|
||||
showInTable: true,
|
||||
width: 200,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'featureTest.featureCase.tableColumnActions',
|
||||
slotName: 'operation',
|
||||
dataIndex: 'operation',
|
||||
fixed: 'right',
|
||||
width: 140,
|
||||
showInTable: true,
|
||||
showDrag: false,
|
||||
},
|
||||
];
|
||||
|
||||
const tableBatchActions = {
|
||||
baseAction: [
|
||||
{
|
||||
label: 'featureTest.featureCase.export',
|
||||
eventTag: 'export',
|
||||
children: [
|
||||
{
|
||||
label: 'featureTest.featureCase.exportExcel',
|
||||
eventTag: 'exportExcel',
|
||||
},
|
||||
{
|
||||
label: 'featureTest.featureCase.exportXMind',
|
||||
eventTag: 'exportXMind',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'common.edit',
|
||||
eventTag: 'batchEdit',
|
||||
},
|
||||
{
|
||||
label: 'featureTest.featureCase.moveTo',
|
||||
eventTag: 'batchMoveTo',
|
||||
},
|
||||
{
|
||||
label: 'featureTest.featureCase.copyTo',
|
||||
eventTag: 'batchCopyTo',
|
||||
},
|
||||
],
|
||||
moreAction: [
|
||||
{
|
||||
label: 'featureTest.featureCase.associatedDemand',
|
||||
eventTag: 'associatedDemand',
|
||||
},
|
||||
{
|
||||
label: 'featureTest.featureCase.generatingDependencies',
|
||||
eventTag: 'generatingDependencies',
|
||||
},
|
||||
{
|
||||
label: 'featureTest.featureCase.addToPublic',
|
||||
eventTag: 'addToPublic',
|
||||
},
|
||||
{
|
||||
isDivider: true,
|
||||
},
|
||||
{
|
||||
label: 'common.delete',
|
||||
eventTag: 'delete',
|
||||
danger: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
/**
|
||||
* 处理更新用例参数
|
||||
* @param detailResult 详情字段
|
||||
*/
|
||||
function getUpdateParams(detailResult: Record<string, any>, name: string) {
|
||||
const { customFields } = detailResult;
|
||||
const customFieldsMaps: Record<string, any> = {};
|
||||
customFields.forEach((item: any) => {
|
||||
customFieldsMaps[item.fieldId] = JSON.parse(item.defaultValue);
|
||||
});
|
||||
|
||||
return {
|
||||
request: {
|
||||
...detailResult,
|
||||
name,
|
||||
customFields: customFieldsMaps,
|
||||
tags: JSON.parse(detailResult.tags),
|
||||
},
|
||||
fileList: [],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新用例名称
|
||||
*/
|
||||
async function updateCaseName(record: CaseManagementTable) {
|
||||
try {
|
||||
const detailResult = await getCaseDetail(record.id);
|
||||
const params = await getUpdateParams(detailResult, record.name);
|
||||
await updateCaseRequest(params);
|
||||
Message.success(t('common.updateSuccess'));
|
||||
return Promise.resolve(true);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
}
|
||||
|
||||
const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector, setProps } = useTable(
|
||||
getCaseList,
|
||||
{
|
||||
tableKey: TableKeyEnum.CASE_MANAGEMENT_TABLE,
|
||||
scroll: { x: 3200 },
|
||||
selectable: true,
|
||||
showSetting: true,
|
||||
heightUsed: 340,
|
||||
enableDrag: true,
|
||||
},
|
||||
(record) => ({
|
||||
...record,
|
||||
tags: (JSON.parse(record.tags) || []).map((item: string, i: number) => {
|
||||
return {
|
||||
id: `${record.id}-${i}`,
|
||||
name: item,
|
||||
};
|
||||
}),
|
||||
}),
|
||||
updateCaseName
|
||||
);
|
||||
|
||||
// 获取父组件模块数量
|
||||
function emitTableParams() {
|
||||
emit('init', {
|
||||
keyword: keyword.value,
|
||||
moduleIds: [],
|
||||
projectId: currentProjectId.value,
|
||||
current: propsRes.value.msPagination?.current,
|
||||
pageSize: propsRes.value.msPagination?.pageSize,
|
||||
});
|
||||
}
|
||||
|
||||
const tableSelected = ref<(string | number)[]>([]);
|
||||
|
||||
function handleTableSelect(selectArr: (string | number)[]) {
|
||||
tableSelected.value = selectArr;
|
||||
}
|
||||
|
||||
const searchParams = ref<TableQueryParams>({
|
||||
projectId: currentProjectId.value,
|
||||
moduleIds: [],
|
||||
});
|
||||
|
||||
function getLoadListParams() {
|
||||
if (props.activeFolder === 'all') {
|
||||
searchParams.value.moduleIds = [];
|
||||
} else {
|
||||
searchParams.value.moduleIds = [moduleId.value, ...props.offspringIds];
|
||||
}
|
||||
setLoadListParams({
|
||||
...searchParams.value,
|
||||
keyword: keyword.value,
|
||||
});
|
||||
}
|
||||
|
||||
// 初始化列表
|
||||
async function initData() {
|
||||
getLoadListParams();
|
||||
loadList();
|
||||
emitTableParams();
|
||||
}
|
||||
|
||||
// 编辑
|
||||
function editCase(record: CaseManagementTable) {
|
||||
router.push({
|
||||
name: FeatureTestRouteEnum.FEATURE_TEST_CASE_DETAIL,
|
||||
query: {
|
||||
id: record.id,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// 删除
|
||||
function deleteCase(record: CaseManagementTable) {
|
||||
openModal({
|
||||
type: 'error',
|
||||
title: t('featureTest.featureCase.deleteCaseTitle', { name: characterLimit(record.name) }),
|
||||
content: t('featureTest.featureCase.beforeDeleteCase'),
|
||||
okText: t('common.confirmDelete'),
|
||||
cancelText: t('common.cancel'),
|
||||
okButtonProps: {
|
||||
status: 'danger',
|
||||
},
|
||||
onBeforeOk: async () => {
|
||||
try {
|
||||
const params = {
|
||||
id: record.id,
|
||||
deleteAll: false,
|
||||
projectId: currentProjectId.value,
|
||||
};
|
||||
await deleteCaseRequest(params);
|
||||
Message.success(t('common.deleteSuccess'));
|
||||
emitTableParams();
|
||||
loadList();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
hideCancel: false,
|
||||
});
|
||||
}
|
||||
|
||||
const showExportExcelVisible = ref<boolean>(false);
|
||||
|
||||
// 导出Excel
|
||||
function handleShowExportExcel() {
|
||||
showExportExcelVisible.value = true;
|
||||
}
|
||||
|
||||
const selectData = ref<string[] | undefined>([]);
|
||||
|
||||
const showEditModel = ref<boolean>(false);
|
||||
// 批量编辑
|
||||
function batchEdit() {
|
||||
showEditModel.value = true;
|
||||
}
|
||||
|
||||
const showBatchMoveDrawer = ref<boolean>(false);
|
||||
|
||||
/**
|
||||
* 处理文件夹树节点选中事件
|
||||
*/
|
||||
const selectedModuleKeys = ref<string[]>([]); // 移动文件选中节点
|
||||
const batchMoveCaseLoading = ref(false);
|
||||
|
||||
const batchParams = ref<BatchActionQueryParams>({
|
||||
selectedIds: [],
|
||||
selectAll: false,
|
||||
excludeIds: [],
|
||||
currentSelectCount: 0,
|
||||
});
|
||||
|
||||
const isMove = ref<boolean>(false);
|
||||
// 批量移动和复制
|
||||
async function handleCaseMoveOrCopy() {
|
||||
batchMoveCaseLoading.value = true;
|
||||
try {
|
||||
const params = {
|
||||
selectIds: batchParams.value.selectedIds || [],
|
||||
selectAll: !!batchParams.value?.selectAll,
|
||||
excludeIds: batchParams.value?.excludeIds || [],
|
||||
condition: { keyword: keyword.value },
|
||||
projectId: currentProjectId.value,
|
||||
moduleIds: props.activeFolder === 'all' ? [] : [props.activeFolder],
|
||||
moduleId: selectedModuleKeys.value[0],
|
||||
};
|
||||
if (isMove.value) {
|
||||
await batchMoveToModules(params);
|
||||
Message.success(t('featureTest.featureCase.batchMoveSuccess'));
|
||||
} else {
|
||||
await batchCopyToModules(params);
|
||||
Message.success(t('featureTest.featureCase.batchCopySuccess'));
|
||||
}
|
||||
isMove.value = false;
|
||||
emitTableParams();
|
||||
loadList();
|
||||
resetSelector();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
batchMoveCaseLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function handleMoveCaseModalCancel() {
|
||||
showBatchMoveDrawer.value = false;
|
||||
selectedModuleKeys.value = [];
|
||||
}
|
||||
|
||||
function caseNodeSelect(keys: string[]) {
|
||||
selectedModuleKeys.value = keys;
|
||||
}
|
||||
|
||||
// 批量移动
|
||||
function batchMoveOrCopy() {
|
||||
showBatchMoveDrawer.value = true;
|
||||
}
|
||||
|
||||
// 获取对应模块name
|
||||
function getModules(moduleIds: string) {
|
||||
const modules = findNodePathByKey(caseTreeData.value, moduleIds, undefined, 'id');
|
||||
const moduleName = (modules || []).treePath.map((item: any) => item.name);
|
||||
|
||||
if (moduleName.length === 1) {
|
||||
return moduleName[0];
|
||||
}
|
||||
return `/${moduleName.join('/')}`;
|
||||
}
|
||||
|
||||
// 批量删除
|
||||
async function batchDelete() {
|
||||
openModal({
|
||||
type: 'error',
|
||||
title: t('featureTest.featureCase.batchDelete', { number: (selectData.value || []).length }),
|
||||
content: t('featureTest.featureCase.beforeDeleteCase'),
|
||||
okText: t('common.confirmDelete'),
|
||||
cancelText: t('common.cancel'),
|
||||
okButtonProps: {
|
||||
status: 'danger',
|
||||
},
|
||||
onBeforeOk: async () => {
|
||||
try {
|
||||
await batchDeleteCase({
|
||||
selectIds: batchParams.value.selectedIds as string[],
|
||||
projectId: currentProjectId.value,
|
||||
});
|
||||
resetSelector();
|
||||
Message.success(t('common.deleteSuccess'));
|
||||
emitTableParams();
|
||||
loadList();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
hideCancel: false,
|
||||
});
|
||||
}
|
||||
|
||||
function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) {
|
||||
batchParams.value = params;
|
||||
if (event.eventTag === 'exportExcel') {
|
||||
handleShowExportExcel();
|
||||
} else if (event.eventTag === 'batchEdit') {
|
||||
batchEdit();
|
||||
} else if (event.eventTag === 'delete') {
|
||||
batchDelete();
|
||||
} else if (event.eventTag === 'batchMoveTo') {
|
||||
batchMoveOrCopy();
|
||||
isMove.value = true;
|
||||
} else if (event.eventTag === 'batchCopyTo') {
|
||||
batchMoveOrCopy();
|
||||
isMove.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
const searchList = debounce(() => {
|
||||
getLoadListParams();
|
||||
loadList();
|
||||
}, 100);
|
||||
|
||||
function successHandler() {
|
||||
loadList();
|
||||
emitTableParams();
|
||||
resetSelector();
|
||||
}
|
||||
|
||||
// 详情
|
||||
function showCaseDetail(id: string) {}
|
||||
|
||||
watch(
|
||||
() => showType.value,
|
||||
() => {
|
||||
initData();
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.activeFolder,
|
||||
() => {
|
||||
keyword.value = '';
|
||||
initData();
|
||||
resetSelector();
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
tableStore.initColumn(TableKeyEnum.CASE_MANAGEMENT_TABLE, columns, 'drawer');
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.page-header {
|
||||
@apply flex items-center justify-between;
|
||||
}
|
||||
.filter-panel {
|
||||
background: var(--color-text-n9);
|
||||
@apply mt-1 rounded-md p-3;
|
||||
.condition-text {
|
||||
color: var(--color-text-2);
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,891 @@
|
|||
<template>
|
||||
<div class="wrapper-preview">
|
||||
<div class="preview-left pr-4">
|
||||
<a-form ref="caseFormRef" class="rounded-[4px]" :model="form" layout="vertical">
|
||||
<a-form-item
|
||||
field="name"
|
||||
:label="t('system.orgTemplate.caseName')"
|
||||
:rules="[{ required: true, message: t('system.orgTemplate.caseNamePlaceholder') }]"
|
||||
required
|
||||
asterisk-position="end"
|
||||
>
|
||||
<a-input
|
||||
v-model="form.name"
|
||||
:max-length="255"
|
||||
:placeholder="t('system.orgTemplate.caseNamePlaceholder')"
|
||||
show-word-limit
|
||||
allow-clear
|
||||
></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item field="precondition" :label="t('system.orgTemplate.precondition')" asterisk-position="end">
|
||||
<MsRichText v-model:model-value="form.prerequisite" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
field="step"
|
||||
:label="
|
||||
form.caseEditType === 'STEP'
|
||||
? t('system.orgTemplate.stepDescription')
|
||||
: t('system.orgTemplate.textDescription')
|
||||
"
|
||||
class="relative"
|
||||
>
|
||||
<div class="absolute left-16 top-0">
|
||||
<a-divider direction="vertical" />
|
||||
<a-dropdown :popup-max-height="false" @select="handleSelectType">
|
||||
<span class="changeType">{{ t('system.orgTemplate.changeType') }} <icon-down /></span>
|
||||
<template #content>
|
||||
<a-doption value="STEP" :class="getSelectTypeClass('STEP')">
|
||||
{{ t('system.orgTemplate.stepDescription') }}</a-doption
|
||||
>
|
||||
<a-doption value="TEXT" :class="getSelectTypeClass('TEXT')">{{
|
||||
t('system.orgTemplate.textDescription')
|
||||
}}</a-doption>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</div>
|
||||
<!-- 步骤描述 -->
|
||||
<div v-if="form.caseEditType === 'STEP'" class="w-full">
|
||||
<MsBaseTable v-bind="propsRes" ref="stepTableRef" v-on="propsEvent">
|
||||
<template #index="{ rowIndex }">
|
||||
<div class="circle text-xs font-medium"> {{ rowIndex + 1 }}</div>
|
||||
</template>
|
||||
<template #caseStep="{ record }">
|
||||
<a-textarea
|
||||
v-if="record.showStep"
|
||||
v-model="record.step"
|
||||
size="mini"
|
||||
:auto-size="true"
|
||||
class="w-max-[267px]"
|
||||
:placeholder="t('system.orgTemplate.stepTip')"
|
||||
@blur="blurHandler(record, 'step')"
|
||||
/>
|
||||
<div
|
||||
v-else-if="record.step && !record.showStep"
|
||||
class="w-full cursor-pointer"
|
||||
@click="edit(record, 'step')"
|
||||
>{{ record.step }}</div
|
||||
>
|
||||
<div
|
||||
v-else-if="!record.caseStep && !record.showStep"
|
||||
class="placeholder w-full cursor-pointer text-[var(--color-text-brand)]"
|
||||
@click="edit(record, 'step')"
|
||||
>{{ t('system.orgTemplate.stepTip') }}</div
|
||||
>
|
||||
</template>
|
||||
<template #expectedResult="{ record }">
|
||||
<a-textarea
|
||||
v-if="record.showExpected"
|
||||
v-model="record.expected"
|
||||
size="mini"
|
||||
:auto-size="true"
|
||||
class="w-max-[267px]"
|
||||
:placeholder="t('system.orgTemplate.expectationTip')"
|
||||
@blur="blurHandler(record, 'expected')"
|
||||
/>
|
||||
<div
|
||||
v-else-if="record.expected && !record.showExpected"
|
||||
class="w-full cursor-pointer"
|
||||
@click="edit(record, 'expected')"
|
||||
>{{ record.expected }}</div
|
||||
>
|
||||
<div
|
||||
v-else-if="!record.expected && !record.showExpected"
|
||||
class="placeholder w-full cursor-pointer text-[var(--color-text-brand)]"
|
||||
@click="edit(record, 'expected')"
|
||||
>{{ t('system.orgTemplate.expectationTip') }}</div
|
||||
>
|
||||
</template>
|
||||
<template #operation="{ record }">
|
||||
<MsTableMoreAction
|
||||
v-if="!record.internal"
|
||||
:list="moreActions"
|
||||
@select="(item:ActionsItem) => handleMoreActionSelect(item,record)"
|
||||
/>
|
||||
</template>
|
||||
</MsBaseTable>
|
||||
<a-button class="mt-2 px-0" type="text" @click="addStep">
|
||||
<template #icon>
|
||||
<icon-plus class="text-[14px]" />
|
||||
</template>
|
||||
{{ t('system.orgTemplate.addStep') }}
|
||||
</a-button>
|
||||
</div>
|
||||
<!-- 文本描述 -->
|
||||
<MsRichText v-else v-model:modelValue="form.textDescription" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
v-if="form.caseEditType === 'TEXT'"
|
||||
field="remark"
|
||||
:label="t('featureTest.featureCase.expectedResult')"
|
||||
>
|
||||
<MsRichText v-model:modelValue="form.expectedResult" />
|
||||
</a-form-item>
|
||||
<a-form-item field="remark" :label="t('featureTest.featureCase.remark')">
|
||||
<MsRichText v-model:modelValue="form.description" />
|
||||
</a-form-item>
|
||||
<a-form-item field="attachment" :label="t('featureTest.featureCase.addAttachment')">
|
||||
<div class="flex flex-col">
|
||||
<div class="mb-1">
|
||||
<a-dropdown position="tr" trigger="hover">
|
||||
<a-button type="outline">
|
||||
<template #icon> <icon-plus class="text-[14px]" /> </template
|
||||
>{{ t('system.orgTemplate.addAttachment') }}</a-button
|
||||
>
|
||||
<template #content>
|
||||
<a-upload
|
||||
ref="uploadRef"
|
||||
v-model:file-list="fileList"
|
||||
:auto-upload="false"
|
||||
:show-file-list="false"
|
||||
:before-upload="beforeUpload"
|
||||
@change="handleChange"
|
||||
>
|
||||
<template #upload-button>
|
||||
<a-button type="text" class="!text-[var(--color-text-1)]">
|
||||
<icon-upload />{{ t('featureTest.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')
|
||||
}}</a-button
|
||||
>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</div>
|
||||
<div class="!hover:bg-[rgb(var(--primary-1))] !text-[var(--color-text-4)]">{{
|
||||
t('system.orgTemplate.addAttachmentTip')
|
||||
}}</div>
|
||||
</div>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<!-- 文件列表开始 -->
|
||||
<div class="w-[90%]">
|
||||
<MsFileList ref="fileListRef" v-model:file-list="fileList" mode="static">
|
||||
<template #actions="{ item }">
|
||||
<!-- 本地文件 -->
|
||||
<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') }}
|
||||
</MsButton>
|
||||
<MsButton type="button" status="primary" class="!mr-[4px]" @click="downloadFile(item)">
|
||||
{{ t('featureTest.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') }}
|
||||
</MsButton>
|
||||
<MsButton type="button" status="primary" class="!mr-[4px]" @click="downloadFile(item)">
|
||||
{{ t('featureTest.featureCase.download') }}
|
||||
</MsButton>
|
||||
</div>
|
||||
</template>
|
||||
</MsFileList>
|
||||
</div>
|
||||
<!-- 文件列表结束 -->
|
||||
</div>
|
||||
<!-- 自定义字段开始 -->
|
||||
<div class="preview-right px-4">
|
||||
<div>
|
||||
<a-skeleton v-if="isLoading" :loading="isLoading" :animation="true">
|
||||
<a-space direction="vertical" class="w-full" size="large">
|
||||
<a-skeleton-line :rows="rowLength" :line-height="30" :line-spacing="30" />
|
||||
</a-space>
|
||||
</a-skeleton>
|
||||
<a-form v-else ref="formRef" class="rounded-[4px]" :model="form" layout="vertical">
|
||||
<a-form-item
|
||||
field="moduleId"
|
||||
asterisk-position="end"
|
||||
:label="t('system.orgTemplate.modules')"
|
||||
:rules="[{ required: true, message: t('system.orgTemplate.moduleRuleTip') }]"
|
||||
>
|
||||
<a-tree-select
|
||||
v-model="form.moduleId"
|
||||
:allow-search="true"
|
||||
:data="caseTree"
|
||||
:field-names="{
|
||||
title: 'name',
|
||||
key: 'id',
|
||||
children: 'children',
|
||||
}"
|
||||
:tree-props="{
|
||||
virtualListProps: {
|
||||
height: 200,
|
||||
},
|
||||
}"
|
||||
></a-tree-select>
|
||||
</a-form-item>
|
||||
<MsFormCreate
|
||||
v-if="formRules.length"
|
||||
ref="formCreateRef"
|
||||
v-model:api="fApi"
|
||||
:form-rule="formRules"
|
||||
:form-create-key="FormCreateKeyEnum.CASE_MANAGEMENT_FIELD"
|
||||
/>
|
||||
<a-form-item field="tags" :label="t('system.orgTemplate.tags')">
|
||||
<a-input-tag v-model="form.tags" :placeholder="t('formCreate.PleaseEnter')" allow-clear />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 自定义字段结束 -->
|
||||
</div>
|
||||
<div class=" ">
|
||||
<MsUpload
|
||||
v-model:file-list="fileList"
|
||||
accept="none"
|
||||
:auto-upload="false"
|
||||
:sub-text="acceptType === 'jar' ? '' : t('project.fileManagement.normalFileSubText', { size: 50 })"
|
||||
multiple
|
||||
draggable
|
||||
size-unit="MB"
|
||||
:max-size="50"
|
||||
:is-all-screen="true"
|
||||
class="mb-[16px]"
|
||||
@change="handleChange"
|
||||
/>
|
||||
</div>
|
||||
<AssociatedFileDrawer v-model:visible="showDrawer" @save="saveSelectAssociatedFile" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { FormInstance } from '@arco-design/web-vue';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsFormCreate from '@/components/pure/ms-form-create/form-create.vue';
|
||||
import type { FormItem } from '@/components/pure/ms-form-create/types';
|
||||
import MsRichText from '@/components/pure/ms-rich-text/MsRichText.vue';
|
||||
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
||||
import { 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 { ActionsItem } from '@/components/pure/ms-table-more-action/types';
|
||||
import MsFileList from '@/components/pure/ms-upload/fileList.vue';
|
||||
import MsUpload from '@/components/pure/ms-upload/index.vue';
|
||||
import type { MsFileItem } from '@/components/pure/ms-upload/types';
|
||||
import AssociatedFileDrawer from './associatedFileDrawer.vue';
|
||||
|
||||
import { getCaseDefaultFields, getCaseDetail } from '@/api/modules/case-management/featureCase';
|
||||
import { getProjectFieldList } from '@/api/modules/setting/template';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
import useFeatureCaseStore from '@/store/modules/case/featureCase';
|
||||
import useFormCreateStore from '@/store/modules/form-create/form-create';
|
||||
import { getGenerateId } from '@/utils';
|
||||
|
||||
import type { AssociatedList, CreateCase, StepList } from '@/models/caseManagement/featureCase';
|
||||
import type { CustomField, DefinedFieldItem } from '@/models/setting/template';
|
||||
import { FormCreateKeyEnum } from '@/enums/formCreateEnum';
|
||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||
|
||||
import {
|
||||
getCustomDetailFields,
|
||||
getTotalFieldOptionList,
|
||||
} from '@/views/setting/organization/template/components/fieldSetting';
|
||||
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
const appStore = useAppStore();
|
||||
const formCreateStore = useFormCreateStore();
|
||||
const currentProjectId = computed(() => appStore.currentProjectId);
|
||||
|
||||
const props = defineProps<{
|
||||
formModeValue: Record<string, any>; // 表单值
|
||||
}>();
|
||||
|
||||
const emit = defineEmits(['update:formModeValue', 'changeFile']);
|
||||
const acceptType = ref('none'); // 模块-上传文件类型
|
||||
|
||||
const templateFieldColumns: MsTableColumn = [
|
||||
{
|
||||
title: 'system.orgTemplate.numberIndex',
|
||||
dataIndex: 'index',
|
||||
slotName: 'index',
|
||||
width: 100,
|
||||
showDrag: false,
|
||||
showInTable: true,
|
||||
},
|
||||
{
|
||||
title: 'system.orgTemplate.useCaseStep',
|
||||
slotName: 'caseStep',
|
||||
dataIndex: 'caseStep',
|
||||
showDrag: true,
|
||||
showInTable: true,
|
||||
},
|
||||
{
|
||||
title: 'system.orgTemplate.expectedResult',
|
||||
dataIndex: 'expectedResult',
|
||||
slotName: 'expectedResult',
|
||||
showDrag: true,
|
||||
showInTable: true,
|
||||
},
|
||||
{
|
||||
title: 'system.orgTemplate.operation',
|
||||
slotName: 'operation',
|
||||
fixed: 'right',
|
||||
width: 200,
|
||||
showInTable: true,
|
||||
showDrag: false,
|
||||
},
|
||||
];
|
||||
|
||||
const { propsRes, propsEvent, setProps } = useTable(undefined, {
|
||||
tableKey: TableKeyEnum.CASE_MANAGEMENT_DETAIL_TABLE,
|
||||
columns: templateFieldColumns,
|
||||
scroll: { x: '800px' },
|
||||
selectable: false,
|
||||
noDisable: true,
|
||||
size: 'default',
|
||||
showSetting: false,
|
||||
showPagination: false,
|
||||
enableDrag: true,
|
||||
});
|
||||
|
||||
const moreActions: ActionsItem[] = [
|
||||
{
|
||||
label: 'featureTest.featureCase.copyStep',
|
||||
eventTag: 'copyStep',
|
||||
},
|
||||
{
|
||||
label: 'featureTest.featureCase.InsertStepsBefore',
|
||||
eventTag: 'InsertStepsBefore',
|
||||
},
|
||||
{
|
||||
label: 'featureTest.featureCase.afterInsertingSteps',
|
||||
eventTag: 'afterInsertingSteps',
|
||||
},
|
||||
{
|
||||
isDivider: true,
|
||||
},
|
||||
{
|
||||
label: 'common.delete',
|
||||
danger: true,
|
||||
eventTag: 'delete',
|
||||
},
|
||||
];
|
||||
|
||||
const formRef = ref<FormInstance>();
|
||||
const caseFormRef = ref<FormInstance>();
|
||||
|
||||
// 默认模版自定义字段
|
||||
const selectData = ref<DefinedFieldItem[]>([]);
|
||||
|
||||
// 步骤描述
|
||||
const stepData = ref<StepList[]>([
|
||||
{
|
||||
id: getGenerateId(),
|
||||
step: '',
|
||||
expected: '',
|
||||
showStep: false,
|
||||
showExpected: false,
|
||||
},
|
||||
]);
|
||||
|
||||
const featureCaseStore = useFeatureCaseStore();
|
||||
const modelId = computed(() => featureCaseStore.moduleId[0]);
|
||||
const caseTree = computed(() => featureCaseStore.caseTree);
|
||||
|
||||
const initForm: CreateCase = {
|
||||
projectId: currentProjectId.value,
|
||||
templateId: '',
|
||||
name: '',
|
||||
prerequisite: '',
|
||||
caseEditType: 'STEP',
|
||||
steps: '',
|
||||
textDescription: '',
|
||||
expectedResult: '',
|
||||
description: '',
|
||||
publicCase: false,
|
||||
moduleId: modelId.value,
|
||||
versionId: '',
|
||||
tags: [],
|
||||
customFields: [],
|
||||
relateFileMetaIds: [],
|
||||
};
|
||||
|
||||
const form = ref<CreateCase>({ ...initForm });
|
||||
|
||||
watch(
|
||||
() => stepData.value,
|
||||
() => {
|
||||
const res = stepData.value.map((item, index) => {
|
||||
return {
|
||||
num: index,
|
||||
desc: item.step,
|
||||
result: item.expected,
|
||||
};
|
||||
});
|
||||
form.value.steps = JSON.stringify(res);
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
// 总参数
|
||||
const params = ref<Record<string, any>>({
|
||||
request: {},
|
||||
fileList: [], // 总文件列表
|
||||
});
|
||||
|
||||
// 获取类型样式
|
||||
function getSelectTypeClass(type: string) {
|
||||
return form.value.caseEditType === type ? ['bg-[rgb(var(--primary-1))]', '!text-[rgb(var(--primary-5))]'] : [];
|
||||
}
|
||||
|
||||
// 更改类型
|
||||
const handleSelectType = (value: string | number | Record<string, any> | undefined) => {
|
||||
form.value.caseEditType = value as string;
|
||||
};
|
||||
|
||||
// 添加步骤
|
||||
const addStep = () => {
|
||||
stepData.value.push({
|
||||
id: getGenerateId(),
|
||||
step: '',
|
||||
expected: '',
|
||||
showStep: false,
|
||||
showExpected: false,
|
||||
});
|
||||
};
|
||||
|
||||
// 复制步骤
|
||||
function copyStep(record: StepList) {
|
||||
stepData.value.push({
|
||||
...record,
|
||||
id: getGenerateId(),
|
||||
});
|
||||
}
|
||||
|
||||
// 删除步骤
|
||||
function deleteStep(record: StepList) {
|
||||
stepData.value = stepData.value.filter((item: any) => item.id !== record.id);
|
||||
}
|
||||
|
||||
// 步骤之前插入步骤
|
||||
function insertStepsBefore(record: StepList) {
|
||||
const index = stepData.value.map((item: any) => item.id).indexOf(record.id);
|
||||
const insertItem = {
|
||||
id: getGenerateId(),
|
||||
step: '',
|
||||
expected: '',
|
||||
showStep: false,
|
||||
showExpected: false,
|
||||
};
|
||||
stepData.value.splice(index, 0, insertItem);
|
||||
}
|
||||
|
||||
// 步骤之后插入步骤
|
||||
function afterInsertingSteps(record: StepList) {
|
||||
const index = stepData.value.map((item: any) => item.id).indexOf(record.id);
|
||||
const insertItem = {
|
||||
id: getGenerateId(),
|
||||
step: '',
|
||||
expected: '',
|
||||
showStep: false,
|
||||
showExpected: false,
|
||||
};
|
||||
stepData.value.splice(index + 1, 0, insertItem);
|
||||
}
|
||||
|
||||
// 编辑步骤
|
||||
function edit(record: StepList, type: string) {
|
||||
if (type === 'step') {
|
||||
record.showStep = true;
|
||||
} else {
|
||||
record.showExpected = true;
|
||||
}
|
||||
}
|
||||
// 失去焦点回调
|
||||
function blurHandler(record: StepList, type: string) {
|
||||
if (type === 'step') {
|
||||
record.showStep = false;
|
||||
} else {
|
||||
record.showExpected = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 更多操作
|
||||
const handleMoreActionSelect = (item: ActionsItem, record: StepList) => {
|
||||
switch (item.eventTag) {
|
||||
case 'copyStep':
|
||||
copyStep(record);
|
||||
break;
|
||||
case 'InsertStepsBefore':
|
||||
insertStepsBefore(record);
|
||||
break;
|
||||
case 'afterInsertingSteps':
|
||||
afterInsertingSteps(record);
|
||||
break;
|
||||
default:
|
||||
deleteStep(record);
|
||||
break;
|
||||
}
|
||||
};
|
||||
// 总自定义字段
|
||||
const totalTemplateField = ref<DefinedFieldItem[]>([]);
|
||||
|
||||
const isLoading = ref<boolean>(true);
|
||||
|
||||
// 获取所有字段
|
||||
async function getAllCaseFields() {
|
||||
try {
|
||||
totalTemplateField.value = await getProjectFieldList({ scopedId: currentProjectId.value, scene: 'FUNCTIONAL' });
|
||||
totalTemplateField.value = getTotalFieldOptionList(totalTemplateField.value as DefinedFieldItem[]);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化模版默认字段
|
||||
async function initDefaultFields() {
|
||||
try {
|
||||
isLoading.value = true;
|
||||
await getAllCaseFields();
|
||||
const res = await getCaseDefaultFields(currentProjectId.value);
|
||||
|
||||
const { customFields, id } = res;
|
||||
form.value.templateId = id;
|
||||
|
||||
selectData.value = getCustomDetailFields(totalTemplateField.value as DefinedFieldItem[], customFields);
|
||||
|
||||
isLoading.value = false;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
const fileList = ref<MsFileItem[]>([]);
|
||||
|
||||
function beforeUpload() {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
// 将文件信息转换为文件格式
|
||||
function convertToFile(fileInfo: AssociatedList): MsFileItem {
|
||||
const fileName = fileInfo.fileType ? `${fileInfo.name}.${fileInfo.fileType || ''}` : `${fileInfo.name}`;
|
||||
const type = fileName.split('.')[1];
|
||||
const file = new File([new Blob()], `${fileName}`, {
|
||||
type: `application/${type}`,
|
||||
});
|
||||
Object.defineProperty(file, 'size', { value: fileInfo.size });
|
||||
return {
|
||||
enable: fileInfo.enable || false,
|
||||
file,
|
||||
name: fileName,
|
||||
percent: 0,
|
||||
status: 'done',
|
||||
uid: fileInfo.id,
|
||||
url: `http://172.16.200.18:8081/${fileInfo.filePath || ''}`,
|
||||
local: fileInfo.local,
|
||||
};
|
||||
}
|
||||
// 处理关联文件
|
||||
function saveSelectAssociatedFile(fileData: AssociatedList[]) {
|
||||
const fileResultList = fileData.map((fileInfo) => convertToFile(fileInfo));
|
||||
fileList.value.push(...fileResultList);
|
||||
}
|
||||
|
||||
const title = ref('');
|
||||
const isEdit = computed(() => !!route.query.id);
|
||||
const attachmentsList = ref([]);
|
||||
|
||||
// 后台传过来的local文件的item列表
|
||||
const oldLocalFileList = computed(() => {
|
||||
return attachmentsList.value.filter((item: any) => item.local);
|
||||
});
|
||||
|
||||
// 后台已保存本地文件
|
||||
const currentOldLocalFileList = computed(() => {
|
||||
return fileList.value.filter((item) => item.local && item.status !== 'init').map((item: any) => item.uid);
|
||||
});
|
||||
|
||||
// 已经关联过的id列表
|
||||
const associateFileIds = computed(() => {
|
||||
return attachmentsList.value.filter((item: any) => !item.local).map((item: any) => item.id);
|
||||
});
|
||||
|
||||
// 当前新增传过来的关联list
|
||||
const currentAlreadyAssociateFileList = computed(() => {
|
||||
return fileList.value
|
||||
.filter((item) => !item.local && !associateFileIds.value.includes(item.uid))
|
||||
.map((item: any) => item.uid);
|
||||
});
|
||||
|
||||
// 新增关联文件ID列表
|
||||
const newAssociateFileListIds = computed(() => {
|
||||
return fileList.value
|
||||
.filter((item: any) => !item.local && !associateFileIds.value.includes(item.uid))
|
||||
.map((item: any) => item.uid);
|
||||
});
|
||||
|
||||
// 删除本地上传的文件id
|
||||
const deleteFileMetaIds = computed(() => {
|
||||
return oldLocalFileList.value
|
||||
.filter((item: any) => !currentOldLocalFileList.value.includes(item.id))
|
||||
.map((item: any) => item.id);
|
||||
});
|
||||
|
||||
// 取消关联文件id
|
||||
const unLinkFilesIds = computed(() => {
|
||||
return associateFileIds.value.filter((id: string) => !currentAlreadyAssociateFileList.value.includes(id));
|
||||
});
|
||||
|
||||
// 处理详情字段
|
||||
function getDetailData(detailResult: CreateCase) {
|
||||
const { customFields, attachments, steps, tags } = detailResult;
|
||||
form.value = {
|
||||
...detailResult,
|
||||
tags: JSON.parse(tags as string),
|
||||
};
|
||||
// 处理自定义字段
|
||||
selectData.value = getCustomDetailFields(
|
||||
totalTemplateField.value as DefinedFieldItem[],
|
||||
customFields as CustomField[]
|
||||
);
|
||||
// 处理步骤
|
||||
if (steps) {
|
||||
stepData.value = JSON.parse(steps).map((item: any) => {
|
||||
return {
|
||||
step: item.desc,
|
||||
expected: item.result,
|
||||
};
|
||||
});
|
||||
}
|
||||
attachmentsList.value = attachments;
|
||||
// 处理文件列表
|
||||
fileList.value = attachments
|
||||
.map((fileInfo: any) => {
|
||||
return {
|
||||
...fileInfo,
|
||||
name: fileInfo.fileName,
|
||||
};
|
||||
})
|
||||
.map((fileInfo: any) => {
|
||||
return convertToFile(fileInfo);
|
||||
});
|
||||
|
||||
// 处理删除本地文件id
|
||||
}
|
||||
|
||||
// 处理详情
|
||||
async function getCaseInfo() {
|
||||
try {
|
||||
isLoading.value = true;
|
||||
await getAllCaseFields();
|
||||
const detailResult = await getCaseDetail(route.query.id as string);
|
||||
getDetailData(detailResult);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
if (isEdit.value) {
|
||||
title.value = t('featureTest.featureCase.updateCase');
|
||||
// 调用详情处理字段
|
||||
getCaseInfo();
|
||||
} else {
|
||||
title.value = t('featureTest.featureCase.creatingCase');
|
||||
initDefaultFields();
|
||||
}
|
||||
});
|
||||
// 处理关联文件和已关联文件本地文件和已上传文本文件
|
||||
function getFilesParams() {
|
||||
form.value.deleteFileMetaIds = deleteFileMetaIds.value;
|
||||
form.value.unLinkFilesIds = unLinkFilesIds.value;
|
||||
params.value.fileList = fileList.value.filter((item: any) => item.status === 'init');
|
||||
form.value.relateFileMetaIds = newAssociateFileListIds.value;
|
||||
}
|
||||
|
||||
// 监视文件列表处理关联和本地文件
|
||||
watch(
|
||||
() => fileList.value,
|
||||
(val) => {
|
||||
if (val) {
|
||||
form.value.relateFileMetaIds = fileList.value.filter((item) => !item.local).map((item) => item.uid);
|
||||
params.value.fileList = fileList.value.filter((item) => item.local && item.status === 'init');
|
||||
if (isEdit.value) {
|
||||
getFilesParams();
|
||||
}
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
// 监视表单变化
|
||||
watch(
|
||||
() => form.value,
|
||||
(val) => {
|
||||
if (val) {
|
||||
if (val) {
|
||||
params.value.request = { ...form.value };
|
||||
emit('update:formModeValue', params.value);
|
||||
featureCaseStore.setModuleId([form.value.moduleId], []);
|
||||
}
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
// 监视父组件传递过来的参数处理
|
||||
watch(
|
||||
() => props.formModeValue,
|
||||
() => {
|
||||
// 这里要处理预览的参数格式给到params
|
||||
params.value = {
|
||||
...props.formModeValue,
|
||||
};
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
const showDrawer = ref<boolean>(false);
|
||||
|
||||
function associatedFile() {
|
||||
showDrawer.value = true;
|
||||
}
|
||||
|
||||
watch(
|
||||
() => stepData.value,
|
||||
(val) => {
|
||||
setProps({ data: val });
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
function handleChange(_fileList: MsFileItem[], fileItem: MsFileItem) {
|
||||
fileList.value = _fileList.map((e) => {
|
||||
return {
|
||||
...e,
|
||||
enable: true, // 是否启用
|
||||
local: true, // 是否本地文件
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
const rowLength = ref<number>(0);
|
||||
const formRuleField = ref<FormItem[][]>([]);
|
||||
const formRules = ref<FormItem[]>([]);
|
||||
const fApi = ref<any>({});
|
||||
const formRuleList = computed(() => formCreateStore.formCreateRuleMap.get(FormCreateKeyEnum.CASE_MANAGEMENT_FIELD));
|
||||
|
||||
// 处理表单格式
|
||||
const getFormRules = () => {
|
||||
formRuleField.value = [];
|
||||
formRules.value = [];
|
||||
if (selectData.value && selectData.value.length) {
|
||||
selectData.value.forEach((item: any) => {
|
||||
const currentFormItem = item.formRules?.map((rule: any) => {
|
||||
let optionsItem = [];
|
||||
if (rule.options && rule.options.length) {
|
||||
optionsItem = rule.options.map((opt: any) => {
|
||||
return {
|
||||
text: opt.label,
|
||||
value: opt.value,
|
||||
};
|
||||
});
|
||||
}
|
||||
return {
|
||||
type: item.type,
|
||||
name: item.id,
|
||||
label: item.name,
|
||||
value: isEdit.value ? JSON.parse(rule.value) : rule.value,
|
||||
options: optionsItem,
|
||||
required: item.required,
|
||||
props: {
|
||||
modelValue: isEdit.value ? JSON.parse(rule.value) : rule.value,
|
||||
options: optionsItem,
|
||||
},
|
||||
};
|
||||
});
|
||||
formRuleField.value.push(currentFormItem as FormItem[]);
|
||||
});
|
||||
formRules.value = formRuleField.value.flatMap((item) => item);
|
||||
}
|
||||
};
|
||||
|
||||
// 监视表单右侧自定义字段改变收集自定义字段参数
|
||||
watch(
|
||||
() => formRuleList.value,
|
||||
() => {
|
||||
const customFieldsMaps: Record<string, any> = {};
|
||||
formRuleList.value?.forEach((item) => {
|
||||
customFieldsMaps[item.field as string] = item.value;
|
||||
});
|
||||
form.value.customFields = customFieldsMaps as Record<string, any>;
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
// 监视自定义字段改变处理formCreate
|
||||
watch(
|
||||
() => selectData.value,
|
||||
() => {
|
||||
getFormRules();
|
||||
rowLength.value = formRules.value.length + 2;
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
setProps({ data: stepData.value });
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
formRules.value = [];
|
||||
formRuleField.value = [];
|
||||
});
|
||||
|
||||
// 转存
|
||||
function transferFile(item: any) {}
|
||||
// 下载
|
||||
function downloadFile(item: any) {}
|
||||
// 取消关联
|
||||
function cancelAssociated(item: any) {}
|
||||
|
||||
defineExpose({
|
||||
caseFormRef,
|
||||
formRef,
|
||||
fApi,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.wrapper-preview {
|
||||
display: flex;
|
||||
.preview-left {
|
||||
width: calc(100% - 396px);
|
||||
border-right: 1px solid var(--color-text-n8);
|
||||
.changeType {
|
||||
padding: 2px 4px;
|
||||
border-radius: 4px;
|
||||
color: var(--color-text-4);
|
||||
:deep(.arco-icon-down) {
|
||||
font-size: 14px;
|
||||
}
|
||||
&:hover {
|
||||
color: rgb(var(--primary-5));
|
||||
background: rgb(var(--primary-1));
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
.preview-right {
|
||||
width: 428px;
|
||||
}
|
||||
}
|
||||
.circle {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
line-height: 16px;
|
||||
border-radius: 50%;
|
||||
text-align: center;
|
||||
color: var(--color-text-4);
|
||||
background: var(--color-text-n8);
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,366 @@
|
|||
<template>
|
||||
<a-input-search
|
||||
v-model:model-value="groupKeyword"
|
||||
:placeholder="t('featureTest.featureCase.searchTip')"
|
||||
allow-clear
|
||||
class="mb-[16px]"
|
||||
></a-input-search>
|
||||
<a-spin class="w-full" :style="{ height: `calc(100vh - 356px)` }" :loading="loading">
|
||||
<MsTree
|
||||
v-model:focus-node-key="focusNodeKey"
|
||||
:selected-keys="props.selectedKeys"
|
||||
:data="caseTree"
|
||||
:keyword="groupKeyword"
|
||||
:node-more-actions="caseMoreActions"
|
||||
:expand-all="props.isExpandAll"
|
||||
:empty-text="t('featureTest.featureCase.caseEmptyContent')"
|
||||
draggable
|
||||
:virtual-list-props="virtualListProps"
|
||||
block-node
|
||||
:field-names="{
|
||||
title: 'name',
|
||||
key: 'id',
|
||||
children: 'children',
|
||||
count: 'count',
|
||||
}"
|
||||
title-tooltip-position="left"
|
||||
@select="caseNodeSelect"
|
||||
@more-action-select="handleCaseMoreSelect"
|
||||
@more-actions-close="moreActionsClose"
|
||||
@drop="handleDrag"
|
||||
>
|
||||
<template #title="nodeData">
|
||||
<span class="text-[var(--color-text-1)]">{{ nodeData.name }}</span>
|
||||
<span class="ml-[4px] text-[var(--color-text-4)]">({{ nodeData.count || 0 }})</span>
|
||||
</template>
|
||||
<template v-if="!props.isModal" #extra="nodeData">
|
||||
<MsPopConfirm
|
||||
:visible="addSubVisible"
|
||||
:is-delete="false"
|
||||
:all-names="[]"
|
||||
:title="t('featureTest.featureCase.addSubModule')"
|
||||
:ok-text="t('common.confirm')"
|
||||
:field-config="{
|
||||
placeholder: t('featureTest.featureCase.addGroupTip'),
|
||||
}"
|
||||
:loading="confirmLoading"
|
||||
@confirm="addSubModule"
|
||||
@cancel="resetFocusNodeKey"
|
||||
>
|
||||
<MsButton type="icon" size="mini" class="ms-tree-node-extra__btn !mr-0" @click="setFocusKey(nodeData)">
|
||||
<MsIcon type="icon-icon_add_outlined" size="14" class="text-[var(--color-text-4)]" />
|
||||
</MsButton>
|
||||
</MsPopConfirm>
|
||||
<MsPopConfirm
|
||||
:title="t('featureTest.featureCase.rename')"
|
||||
:all-names="[]"
|
||||
:is-delete="false"
|
||||
:ok-text="t('common.confirm')"
|
||||
:field-config="{ field: renameCaseName }"
|
||||
:loading="confirmLoading"
|
||||
@confirm="updateNameModule"
|
||||
@cancel="resetFocusNodeKey"
|
||||
>
|
||||
<span :id="`renameSpan${nodeData.id}`" class="relative"></span>
|
||||
</MsPopConfirm>
|
||||
</template>
|
||||
</MsTree>
|
||||
</a-spin>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsPopConfirm from '@/components/pure/ms-popconfirm/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 {
|
||||
createCaseModuleTree,
|
||||
deleteCaseModuleTree,
|
||||
getCaseModuleTree,
|
||||
moveCaseModuleTree,
|
||||
updateCaseModuleTree,
|
||||
} from '@/api/modules/case-management/featureCase';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useModal from '@/hooks/useModal';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
import useFeatureCaseStore from '@/store/modules/case/featureCase';
|
||||
import { mapTree } from '@/utils';
|
||||
|
||||
import type { CreateOrUpdateModule, UpdateModule } from '@/models/caseManagement/featureCase';
|
||||
import { ModuleTreeNode } from '@/models/projectManagement/file';
|
||||
|
||||
const { t } = useI18n();
|
||||
const { openModal } = useModal();
|
||||
const appStore = useAppStore();
|
||||
const focusNodeKey = ref<string>('');
|
||||
const loading = ref(false);
|
||||
|
||||
const props = defineProps<{
|
||||
isModal?: boolean; // 是否是弹窗模式
|
||||
activeFolder?: string; // 当前选中的文件夹,弹窗模式下需要使用
|
||||
selectedKeys?: Array<string | number>; // 选中的节点 key
|
||||
isExpandAll: boolean; // 是否展开用例节点
|
||||
allNames?: string[]; // 所有的模块name列表
|
||||
modulesCount?: Record<string, number>; // 模块数量统计对象
|
||||
}>();
|
||||
|
||||
const emits = defineEmits(['update:selectedKeys', 'caseNodeSelect', 'init']);
|
||||
|
||||
const currentProjectId = computed(() => appStore.currentProjectId);
|
||||
|
||||
const groupKeyword = ref<string>('');
|
||||
|
||||
const caseTree = ref<ModuleTreeNode[]>([]);
|
||||
|
||||
const setFocusKey = (node: MsTreeNodeData) => {
|
||||
focusNodeKey.value = node.id || '';
|
||||
};
|
||||
|
||||
const caseMoreActions: ActionsItem[] = [
|
||||
{
|
||||
label: 'featureTest.featureCase.rename',
|
||||
eventTag: 'rename',
|
||||
},
|
||||
{
|
||||
label: 'featureTest.featureCase.delete',
|
||||
eventTag: 'delete',
|
||||
danger: true,
|
||||
},
|
||||
];
|
||||
|
||||
const selectedNodeKeys = ref(props.selectedKeys || []);
|
||||
|
||||
watch(
|
||||
() => props.selectedKeys,
|
||||
(val) => {
|
||||
selectedNodeKeys.value = val || [];
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => selectedNodeKeys.value,
|
||||
(val) => {
|
||||
emits('update:selectedKeys', val);
|
||||
}
|
||||
);
|
||||
const featureCaseStore = useFeatureCaseStore();
|
||||
/**
|
||||
* 初始化模块树
|
||||
* @param isSetDefaultKey 是否设置第一个节点为选中节点
|
||||
*/
|
||||
async function initModules(isSetDefaultKey = false) {
|
||||
try {
|
||||
loading.value = true;
|
||||
const res = await getCaseModuleTree(currentProjectId.value);
|
||||
caseTree.value = mapTree<ModuleTreeNode>(res, (e) => {
|
||||
return {
|
||||
...e,
|
||||
hideMoreAction: e.id === 'root',
|
||||
draggable: e.id !== 'root' && !props.isModal,
|
||||
disabled: e.id === props.activeFolder && props.isModal,
|
||||
count: props.modulesCount?.[e.id] || 0,
|
||||
};
|
||||
});
|
||||
featureCaseStore.setModulesTree(caseTree.value);
|
||||
if (isSetDefaultKey) {
|
||||
selectedNodeKeys.value = [caseTree.value[0].id];
|
||||
}
|
||||
emits(
|
||||
'init',
|
||||
caseTree.value.map((e) => e.name)
|
||||
);
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 删除节点
|
||||
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'),
|
||||
okButtonProps: {
|
||||
status: 'danger',
|
||||
},
|
||||
maskClosable: false,
|
||||
onBeforeOk: async () => {
|
||||
try {
|
||||
await deleteCaseModuleTree(node.id);
|
||||
Message.success(t('featureTest.featureCase.deleteSuccess'));
|
||||
initModules(selectedNodeKeys.value[0] === node.id);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
hideCancel: false,
|
||||
});
|
||||
};
|
||||
|
||||
const renamePopVisible = ref(false);
|
||||
const renameCaseName = ref('');
|
||||
|
||||
function resetFocusNodeKey() {
|
||||
focusNodeKey.value = '';
|
||||
renamePopVisible.value = false;
|
||||
renameCaseName.value = '';
|
||||
}
|
||||
|
||||
// 用例树节点选中事件
|
||||
const caseNodeSelect = (selectedKeys: (string | number)[], node: MsTreeNodeData) => {
|
||||
const offspringIds: string[] = [];
|
||||
mapTree(node.children || [], (e) => {
|
||||
offspringIds.push(e.id);
|
||||
return e;
|
||||
});
|
||||
emits('caseNodeSelect', selectedKeys, offspringIds);
|
||||
};
|
||||
|
||||
// 用例树节点更多事件
|
||||
const handleCaseMoreSelect = (item: ActionsItem, node: MsTreeNodeData) => {
|
||||
switch (item.eventTag) {
|
||||
case 'delete':
|
||||
deleteHandler(node);
|
||||
resetFocusNodeKey();
|
||||
break;
|
||||
case 'rename':
|
||||
renameCaseName.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 handleDrag(
|
||||
tree: MsTreeNodeData[],
|
||||
dragNode: MsTreeNodeData,
|
||||
dropNode: MsTreeNodeData,
|
||||
dropPosition: number
|
||||
) {
|
||||
try {
|
||||
loading.value = true;
|
||||
await moveCaseModuleTree({
|
||||
dragNodeId: dragNode.id as string,
|
||||
dropNodeId: dropNode.id || '',
|
||||
dropPosition,
|
||||
});
|
||||
Message.success(t('featureTest.featureCase.moduleMoveSuccess'));
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
initModules();
|
||||
}
|
||||
}
|
||||
|
||||
const moreActionsClose = () => {
|
||||
if (!renamePopVisible.value) {
|
||||
resetFocusNodeKey();
|
||||
}
|
||||
};
|
||||
|
||||
const addSubVisible = ref(false);
|
||||
const confirmLoading = ref(false);
|
||||
|
||||
// 添加子模块
|
||||
async function addSubModule(formValue?: { field: string }, cancel?: () => void) {
|
||||
try {
|
||||
confirmLoading.value = true;
|
||||
const params: CreateOrUpdateModule = {
|
||||
projectId: currentProjectId.value,
|
||||
name: formValue?.field as string,
|
||||
parentId: focusNodeKey.value,
|
||||
};
|
||||
await createCaseModuleTree(params);
|
||||
Message.success(t('featureTest.featureCase.addSuccess'));
|
||||
if (cancel) {
|
||||
cancel();
|
||||
}
|
||||
initModules();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
confirmLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 更新子模块
|
||||
async function updateNameModule(formValue?: { field: string }, cancel?: () => void) {
|
||||
try {
|
||||
confirmLoading.value = true;
|
||||
const params: UpdateModule = {
|
||||
id: focusNodeKey.value,
|
||||
name: formValue?.field as string,
|
||||
};
|
||||
await updateCaseModuleTree(params);
|
||||
Message.success(t('featureTest.featureCase.addSuccess'));
|
||||
if (cancel) {
|
||||
cancel();
|
||||
}
|
||||
initModules();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
confirmLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
const virtualListProps = computed(() => {
|
||||
return {
|
||||
height: 'calc(100vh - 360px)',
|
||||
};
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.activeFolder,
|
||||
(val) => {
|
||||
if (val === 'all') {
|
||||
initModules();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* 初始化模块文件数量
|
||||
*/
|
||||
watch(
|
||||
() => props.modulesCount,
|
||||
(obj) => {
|
||||
caseTree.value = mapTree<ModuleTreeNode>(caseTree.value, (node) => {
|
||||
return {
|
||||
...node,
|
||||
count: obj?.[node.id] || 0,
|
||||
};
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
onBeforeMount(() => {
|
||||
initModules();
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
initModules,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="less"></style>
|
|
@ -0,0 +1,208 @@
|
|||
<template>
|
||||
<MsDrawer
|
||||
v-model:visible="showDrawer"
|
||||
:mask="false"
|
||||
:title="t('featureTest.featureCase.associatedFile')"
|
||||
:ok-text="t('featureTest.featureCase.associated')"
|
||||
:ok-loading="drawerLoading"
|
||||
:width="480"
|
||||
unmount-on-close
|
||||
:show-continue="false"
|
||||
@confirm="handleDrawerConfirm"
|
||||
@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>
|
||||
</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
|
||||
><icon-up
|
||||
v-if="foldBaseFields"
|
||||
class="text-[12px] text-[var(--color-text-brand)]"
|
||||
@click="toggle('base')" /><icon-right
|
||||
v-else
|
||||
class="text-[12px] text-[var(--color-text-brand)]"
|
||||
@click="toggle('base')"
|
||||
/></span>
|
||||
</div>
|
||||
</a-checkbox>
|
||||
</div>
|
||||
<a-checkbox-group v-if="foldBaseFields" v-model="baseFields" class="checkboxContainer" @change="handleChange">
|
||||
<div class="item checkbox">
|
||||
<a-checkbox value="1">Option 1</a-checkbox>
|
||||
</div>
|
||||
<div class="item checkbox">
|
||||
<a-checkbox value="1">Option 1</a-checkbox>
|
||||
</div>
|
||||
<div class="item checkbox">
|
||||
<a-checkbox value="1">Option 1</a-checkbox>
|
||||
</div>
|
||||
<div class="item checkbox">
|
||||
<a-checkbox value="1">Option 1</a-checkbox>
|
||||
</div>
|
||||
<div class="item checkbox">
|
||||
<a-checkbox value="1">Option 1</a-checkbox>
|
||||
</div>
|
||||
</a-checkbox-group>
|
||||
<!-- 自定义字段 -->
|
||||
<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
|
||||
><icon-up
|
||||
v-if="foldCustomFields"
|
||||
class="text-[12px] text-[var(--color-text-brand)]"
|
||||
@click="toggle('custom')" /><icon-right
|
||||
v-else
|
||||
class="text-[12px] text-[var(--color-text-brand)]"
|
||||
@click="toggle('custom')"
|
||||
/></span>
|
||||
</div>
|
||||
</a-checkbox>
|
||||
</div>
|
||||
<a-checkbox-group v-if="foldCustomFields" v-model="customFields" class="checkboxContainer" @change="handleChange">
|
||||
<div class="item checkbox">
|
||||
<a-checkbox value="1">Option 1</a-checkbox>
|
||||
</div>
|
||||
<div class="item checkbox">
|
||||
<a-checkbox value="1">Option 1</a-checkbox>
|
||||
</div>
|
||||
<div class="item checkbox">
|
||||
<a-checkbox value="1">Option 1</a-checkbox>
|
||||
</div>
|
||||
<div class="item checkbox">
|
||||
<a-checkbox value="1">Option 1</a-checkbox>
|
||||
</div>
|
||||
<div class="item checkbox">
|
||||
<a-checkbox value="1">Option 1</a-checkbox>
|
||||
</div>
|
||||
</a-checkbox-group>
|
||||
<!-- 其他字段 -->
|
||||
<div>
|
||||
<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>
|
||||
<a-tooltip
|
||||
:content="t('featureTest.featureCase.otherFieldsToolTip')"
|
||||
position="top"
|
||||
:mouse-enter-delay="500"
|
||||
mini
|
||||
>
|
||||
<icon-question-circle
|
||||
class="mx-1 text-[16px] text-[var(--color-text-brand)] hover:text-[rgb(var(--primary-5))]" /></a-tooltip
|
||||
><icon-up
|
||||
v-if="foldCustomFields"
|
||||
class="text-[12px] text-[var(--color-text-brand)]"
|
||||
@click="toggle('other')" /><icon-right
|
||||
v-else
|
||||
class="text-[12px] text-[var(--color-text-brand)]"
|
||||
@click="toggle('other')"
|
||||
/></span>
|
||||
</div>
|
||||
</a-checkbox>
|
||||
</div>
|
||||
<a-checkbox-group v-if="foldOtherFields" v-model="otherFields" class="checkboxContainer" @change="handleChange">
|
||||
<div class="item checkbox">
|
||||
<a-checkbox value="1">Option 1</a-checkbox>
|
||||
</div>
|
||||
<div class="item checkbox">
|
||||
<a-checkbox value="1">Option 1</a-checkbox>
|
||||
</div>
|
||||
<div class="item checkbox">
|
||||
<a-checkbox value="1">Option 1</a-checkbox>
|
||||
</div>
|
||||
<div class="item checkbox">
|
||||
<a-checkbox value="1">Option 1</a-checkbox>
|
||||
</div>
|
||||
<div class="item checkbox">
|
||||
<a-checkbox value="1">Option 1</a-checkbox>
|
||||
</div>
|
||||
</a-checkbox-group>
|
||||
</MsDrawer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
|
||||
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps<{
|
||||
visible: boolean;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:visible', val: boolean): void;
|
||||
}>();
|
||||
|
||||
const showDrawer = ref<boolean>(false);
|
||||
const drawerLoading = ref<boolean>(false);
|
||||
|
||||
const checkedAll = ref<boolean>(false);
|
||||
const indeterminate = ref<boolean>(false);
|
||||
|
||||
function handleChangeAll() {}
|
||||
function handleChange() {}
|
||||
|
||||
function handleDrawerConfirm() {}
|
||||
|
||||
function handleDrawerCancel() {
|
||||
showDrawer.value = false;
|
||||
}
|
||||
|
||||
const foldBaseFields = ref<boolean>(true); // 默认展开
|
||||
const baseFields = ref<string[]>([]);
|
||||
|
||||
const foldCustomFields = ref<boolean>(true);
|
||||
const customFields = ref<string[]>([]);
|
||||
|
||||
const foldOtherFields = ref<boolean>(true);
|
||||
const otherFields = ref<string[]>([]);
|
||||
|
||||
function toggle(foldType: string) {
|
||||
if (foldType === 'base') {
|
||||
foldBaseFields.value = !foldBaseFields.value;
|
||||
} else if (foldType === 'custom') {
|
||||
foldCustomFields.value = !foldCustomFields.value;
|
||||
} else {
|
||||
foldOtherFields.value = !foldOtherFields.value;
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(val) => {
|
||||
showDrawer.value = val;
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => showDrawer.value,
|
||||
(val) => {
|
||||
emit('update:visible', val);
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.checkboxContainer {
|
||||
display: grid;
|
||||
margin-bottom: 16px;
|
||||
grid-template-columns: repeat(auto-fit, minmax(116px, 1fr));
|
||||
grid-gap: 16px;
|
||||
.checkbox {
|
||||
width: 90px;
|
||||
white-space: nowrap;
|
||||
@apply overflow-hidden text-ellipsis;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,706 @@
|
|||
<template>
|
||||
<div class="pageWrap">
|
||||
<MsSplitBox>
|
||||
<template #left>
|
||||
<div class="p-[24px]">
|
||||
<div class="mb-4 flex items-center">
|
||||
<div class="back" @click="handleBack"><icon-arrow-left /></div>
|
||||
<div
|
||||
>{{ t('featureTest.featureCase.recycle')
|
||||
}}<span class="ml-1 text-[var(--color-text-4)]">({{ recycleModulesCount.all }})</span></div
|
||||
>
|
||||
</div>
|
||||
<a-divider class="my-[4px]" />
|
||||
|
||||
<div class="feature-case">
|
||||
<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-count">({{ allCaseCount }})</div></div
|
||||
>
|
||||
<div class="ml-auto flex items-center">
|
||||
<a-tooltip
|
||||
:content="
|
||||
isExpandAll ? t('project.fileManagement.collapseAll') : t('project.fileManagement.expandAll')
|
||||
"
|
||||
>
|
||||
<MsButton type="icon" status="secondary" class="!mr-0 p-[4px]" @click="expandHandler">
|
||||
<MsIcon :type="isExpandAll ? 'icon-icon_folder_collapse1' : 'icon-icon_folder_expansion1'" />
|
||||
</MsButton>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<a-input-search
|
||||
v-model:model-value="groupKeyword"
|
||||
:placeholder="t('featureTest.featureCase.searchTip')"
|
||||
allow-clear
|
||||
class="mb-[16px]"
|
||||
></a-input-search>
|
||||
<a-spin class="w-full" :loading="loading">
|
||||
<MsTree
|
||||
v-model:focus-node-key="focusNodeKey"
|
||||
:selected-keys="selectedKeys"
|
||||
:data="caseTree"
|
||||
:keyword="groupKeyword"
|
||||
:expand-all="isExpandAll"
|
||||
:empty-text="t('featureTest.featureCase.caseEmptyContent')"
|
||||
draggable
|
||||
:virtual-list-props="virtualListProps"
|
||||
block-node
|
||||
:field-names="{
|
||||
title: 'name',
|
||||
key: 'id',
|
||||
children: 'children',
|
||||
count: 'count',
|
||||
}"
|
||||
title-tooltip-position="left"
|
||||
@select="caseNodeSelect"
|
||||
>
|
||||
<template #title="nodeData">
|
||||
<div @click="setFocusKey(nodeData)">
|
||||
<span class="text-[var(--color-text-1)]">{{ nodeData.name }}</span>
|
||||
<span class="ml-[4px] text-[var(--color-text-4)]">({{ nodeData.count || 0 }})</span>
|
||||
</div>
|
||||
</template>
|
||||
</MsTree>
|
||||
</a-spin>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #right>
|
||||
<div class="p-[24px]">
|
||||
<div class="page-header mb-4 h-[34px]">
|
||||
<div class="text-[var(--color-text-1)]"
|
||||
>{{ t('featureTest.featureCase.allCase') }}
|
||||
<span class="text-[var(--color-text-4)]"> ({{ recycleModulesCount.all }})</span></div
|
||||
>
|
||||
<div class="flex w-[80%] items-center justify-end">
|
||||
<a-select class="w-[240px]" :placeholder="t('featureTest.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')"
|
||||
allow-clear
|
||||
class="mx-[8px] w-[240px]"
|
||||
@search="searchList"
|
||||
@press-enter="searchList"
|
||||
></a-input-search>
|
||||
</div>
|
||||
</div>
|
||||
<ms-base-table
|
||||
v-bind="propsRes"
|
||||
:action-config="tableBatchActions"
|
||||
@selected-change="handleTableSelect"
|
||||
v-on="propsEvent"
|
||||
@batch-action="handleTableBatch"
|
||||
>
|
||||
<template #reviewStatus="{ record }">
|
||||
<MsIcon
|
||||
:type="getStatusText(record.reviewStatus)?.iconType || ''"
|
||||
class="mr-1"
|
||||
:class="[getReviewStatusClass(record.reviewStatus)]"
|
||||
></MsIcon>
|
||||
<span>{{ getStatusText(record.reviewStatus)?.statusType || '' }} </span>
|
||||
</template>
|
||||
<template #lastExecuteResult="{ record }">
|
||||
<MsIcon
|
||||
:type="getStatusText(record.lastExecuteResult)?.iconType || ''"
|
||||
class="mr-1"
|
||||
:class="[getReviewStatusClass(record.lastExecuteResult)]"
|
||||
></MsIcon>
|
||||
<span>{{ getStatusText(record.lastExecuteResult)?.statusType || '' }}</span>
|
||||
</template>
|
||||
<template #moduleId="{ record }">
|
||||
<a-tooltip :content="getModules(record.moduleId)" position="top">
|
||||
<span class="one-line-text inline-block">{{ getModules(record.moduleId) }}</span>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<template #operation="{ record }">
|
||||
<MsButton @click="recoverCase(record.id)">{{ t('featureTest.featureCase.batchRecover') }}</MsButton>
|
||||
<MsButton class="!mr-0" @click="handleBatchCleanOut(record)">{{
|
||||
t('featureTest.featureCase.batchCleanOut')
|
||||
}}</MsButton>
|
||||
</template>
|
||||
</ms-base-table>
|
||||
</div>
|
||||
</template>
|
||||
</MsSplitBox>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
/*
|
||||
* @description 功能用例-回收站
|
||||
*/
|
||||
import { computed, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
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 MsSplitBox from '@/components/pure/ms-split-box/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 MsTree from '@/components/business/ms-tree/index.vue';
|
||||
import type { MsTreeNodeData } from '@/components/business/ms-tree/types';
|
||||
|
||||
import {
|
||||
batchDeleteRecycleCase,
|
||||
deleteRecycleCaseList,
|
||||
getRecycleListRequest,
|
||||
getTrashCaseModuleTree,
|
||||
recoverRecycleCase,
|
||||
restoreCaseList,
|
||||
} from '@/api/modules/case-management/featureCase';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useModal from '@/hooks/useModal';
|
||||
import { useAppStore, useTableStore } from '@/store';
|
||||
import useFeatureCaseStore from '@/store/modules/case/featureCase';
|
||||
import { characterLimit, findNodePathByKey, mapTree } from '@/utils';
|
||||
|
||||
import type {
|
||||
BatchMoveOrCopyType,
|
||||
CaseManagementTable,
|
||||
CaseModuleQueryParams,
|
||||
} from '@/models/caseManagement/featureCase';
|
||||
import type { TableQueryParams } from '@/models/common';
|
||||
import { ModuleTreeNode } from '@/models/projectManagement/file';
|
||||
import { StatusType } from '@/enums/caseEnum';
|
||||
import { FeatureTestRouteEnum } from '@/enums/routeEnum';
|
||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||
|
||||
import { getReviewStatusClass, getStatusText } from './utils';
|
||||
import debounce from 'lodash-es/debounce';
|
||||
|
||||
const tableStore = useTableStore();
|
||||
const featureCaseStore = useFeatureCaseStore();
|
||||
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
const { openModal } = useModal();
|
||||
|
||||
const allCaseCount = ref<number>(0);
|
||||
|
||||
const activeCaseType = ref<'folder' | 'module'>('folder'); // 激活用例类型
|
||||
|
||||
const appStore = useAppStore();
|
||||
|
||||
const currentProjectId = computed(() => appStore.currentProjectId);
|
||||
|
||||
const versionOptions = ref([
|
||||
{
|
||||
id: '1001',
|
||||
name: 'v_1.0',
|
||||
},
|
||||
]);
|
||||
|
||||
const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector } = useTable(
|
||||
getRecycleListRequest,
|
||||
{
|
||||
tableKey: TableKeyEnum.FILE_MANAGEMENT_CASE_RECYCLE,
|
||||
scroll: { x: 3200 },
|
||||
selectable: true,
|
||||
showSetting: true,
|
||||
heightUsed: 340,
|
||||
enableDrag: true,
|
||||
},
|
||||
(record) => ({
|
||||
...record,
|
||||
tags: (JSON.parse(record.tags) || []).map((item: string, i: number) => {
|
||||
return {
|
||||
id: `${record.id}-${i}`,
|
||||
name: item,
|
||||
};
|
||||
}),
|
||||
})
|
||||
);
|
||||
|
||||
const columns: MsTableColumn = [
|
||||
{
|
||||
title: 'featureTest.featureCase.tableColumnID',
|
||||
dataIndex: 'id',
|
||||
width: 200,
|
||||
showInTable: true,
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
},
|
||||
showTooltip: true,
|
||||
ellipsis: true,
|
||||
showDrag: false,
|
||||
},
|
||||
{
|
||||
title: 'featureTest.featureCase.tableColumnName',
|
||||
slotName: 'name',
|
||||
dataIndex: 'name',
|
||||
showInTable: true,
|
||||
showTooltip: true,
|
||||
width: 300,
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
},
|
||||
ellipsis: true,
|
||||
showDrag: false,
|
||||
},
|
||||
{
|
||||
title: 'featureTest.featureCase.tableColumnLevel',
|
||||
dataIndex: 'level',
|
||||
showInTable: true,
|
||||
width: 200,
|
||||
showTooltip: true,
|
||||
ellipsis: true,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'featureTest.featureCase.tableColumnCaseState',
|
||||
dataIndex: 'caseState',
|
||||
showInTable: true,
|
||||
width: 200,
|
||||
showTooltip: true,
|
||||
ellipsis: true,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'featureTest.featureCase.tableColumnReviewResult',
|
||||
dataIndex: 'reviewStatus',
|
||||
slotName: 'reviewStatus',
|
||||
showInTable: true,
|
||||
width: 200,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'featureTest.featureCase.tableColumnExecutionResult',
|
||||
dataIndex: 'lastExecuteResult',
|
||||
slotName: 'lastExecuteResult',
|
||||
showInTable: true,
|
||||
width: 200,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'featureTest.featureCase.tableColumnVersion',
|
||||
slotName: 'versionId',
|
||||
dataIndex: 'versionId',
|
||||
width: 300,
|
||||
showTooltip: true,
|
||||
showInTable: true,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'featureTest.featureCase.tableColumnModule',
|
||||
slotName: 'moduleId',
|
||||
showInTable: true,
|
||||
width: 300,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'featureTest.featureCase.tableColumnTag',
|
||||
slotName: 'tags',
|
||||
dataIndex: 'tags',
|
||||
showInTable: true,
|
||||
isTag: true,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'featureTest.featureCase.tableColumnCreateUser',
|
||||
slotName: 'createUser',
|
||||
dataIndex: 'createUser',
|
||||
showInTable: true,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'featureTest.featureCase.tableColumnCreateTime',
|
||||
slotName: 'createTime',
|
||||
dataIndex: 'createTime',
|
||||
showInTable: true,
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
},
|
||||
width: 200,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'featureTest.featureCase.tableColumnUpdateUser',
|
||||
slotName: 'updateUser',
|
||||
dataIndex: 'updateUser',
|
||||
showInTable: true,
|
||||
width: 200,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'featureTest.featureCase.tableColumnUpdateTime',
|
||||
slotName: 'updateTime',
|
||||
dataIndex: 'updateTime',
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
},
|
||||
showInTable: true,
|
||||
width: 200,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'featureTest.featureCase.tableColumnActions',
|
||||
slotName: 'operation',
|
||||
dataIndex: 'operation',
|
||||
fixed: 'right',
|
||||
width: 140,
|
||||
showInTable: true,
|
||||
showDrag: false,
|
||||
},
|
||||
];
|
||||
|
||||
const tableBatchActions = {
|
||||
baseAction: [
|
||||
{
|
||||
label: 'featureTest.featureCase.batchRecover',
|
||||
eventTag: 'batchRecover',
|
||||
},
|
||||
{
|
||||
label: 'featureTest.featureCase.batchCleanOut',
|
||||
eventTag: 'batchCleanOut',
|
||||
danger: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const tableSelected = ref<(string | number)[]>([]);
|
||||
function handleTableSelect(selectArr: (string | number)[]) {
|
||||
tableSelected.value = selectArr;
|
||||
}
|
||||
|
||||
const isExpandAll = ref(false);
|
||||
|
||||
// 全部展开或折叠
|
||||
function expandHandler() {
|
||||
isExpandAll.value = !isExpandAll.value;
|
||||
}
|
||||
|
||||
const activeFolder = ref<string>('all');
|
||||
|
||||
// 获取激活用例类型样式
|
||||
function getActiveClass(type: string) {
|
||||
return activeFolder.value === type ? 'folder-text case-active' : 'folder-text';
|
||||
}
|
||||
|
||||
// 设置激活文件类型
|
||||
function setActiveFolder(type: string) {
|
||||
activeFolder.value = type;
|
||||
if (type === 'all') {
|
||||
activeCaseType.value = 'folder';
|
||||
}
|
||||
}
|
||||
|
||||
// 选中节点
|
||||
const selectedKeys = computed({
|
||||
get: () => [activeFolder.value],
|
||||
set: (val) => val,
|
||||
});
|
||||
|
||||
const offspringIds = ref<string[]>([]);
|
||||
|
||||
const selectedKeysNode = ref<(string | number)[]>([]);
|
||||
|
||||
const focusNodeKey = ref<string>('');
|
||||
// 用例树节点选中事件
|
||||
const caseNodeSelect = (selectedNodeKeys: (string | number)[] | string[], node: MsTreeNodeData) => {
|
||||
[activeFolder.value] = selectedNodeKeys as string[];
|
||||
offspringIds.value = [];
|
||||
mapTree(node.children || [], (e) => {
|
||||
offspringIds.value.push(e.id);
|
||||
return e;
|
||||
});
|
||||
focusNodeKey.value = '';
|
||||
};
|
||||
|
||||
const setFocusKey = (node: MsTreeNodeData) => {
|
||||
focusNodeKey.value = node.id || '';
|
||||
};
|
||||
|
||||
const virtualListProps = computed(() => {
|
||||
return {
|
||||
height: 'calc(100vh - 316px)',
|
||||
};
|
||||
});
|
||||
|
||||
const loading = ref(false);
|
||||
const caseTree = ref<ModuleTreeNode[]>([]);
|
||||
const recycleModulesCount = ref<Record<string, number>>({});
|
||||
const groupKeyword = ref<string>('');
|
||||
|
||||
/**
|
||||
* @param 获取回收站模块
|
||||
*/
|
||||
async function getRecycleModules(isSetDefaultKey = false) {
|
||||
try {
|
||||
loading.value = true;
|
||||
const res = await getTrashCaseModuleTree(currentProjectId.value);
|
||||
caseTree.value = mapTree<ModuleTreeNode>(res, (e) => {
|
||||
return {
|
||||
...e,
|
||||
hideMoreAction: e.id === 'root',
|
||||
draggable: false,
|
||||
disabled: false,
|
||||
count: recycleModulesCount.value?.[e.id] || 0,
|
||||
};
|
||||
});
|
||||
if (isSetDefaultKey) {
|
||||
selectedKeysNode.value = [caseTree.value[0].id];
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
const keyword = ref<string>('');
|
||||
|
||||
const searchParams = ref<TableQueryParams>({
|
||||
projectId: currentProjectId.value,
|
||||
moduleIds: [],
|
||||
});
|
||||
|
||||
// 回收站模块树count参数
|
||||
const emitTableParams: CaseModuleQueryParams = {
|
||||
keyword: keyword.value,
|
||||
moduleIds: [],
|
||||
projectId: currentProjectId.value,
|
||||
current: propsRes.value.msPagination?.current,
|
||||
pageSize: propsRes.value.msPagination?.pageSize,
|
||||
};
|
||||
|
||||
// 获取回收站模块数量
|
||||
function initRecycleModulesCount() {
|
||||
featureCaseStore.getRecycleMModulesCountCount(emitTableParams);
|
||||
}
|
||||
|
||||
const batchParams = ref<BatchActionQueryParams>({
|
||||
selectedIds: [],
|
||||
selectAll: false,
|
||||
excludeIds: [],
|
||||
currentSelectCount: 0,
|
||||
});
|
||||
|
||||
// 获取批量操作参数
|
||||
function getBatchParams(): BatchMoveOrCopyType {
|
||||
return {
|
||||
excludeIds: batchParams.value.excludeIds,
|
||||
selectAll: batchParams.value.selectAll,
|
||||
selectIds: batchParams.value.selectedIds,
|
||||
condition: {
|
||||
keyword: keyword.value,
|
||||
},
|
||||
moduleIds: searchParams.value.moduleIds,
|
||||
projectId: currentProjectId.value,
|
||||
};
|
||||
}
|
||||
|
||||
// 批量恢复
|
||||
async function handleBatchRecover() {
|
||||
try {
|
||||
await restoreCaseList(getBatchParams());
|
||||
Message.success(t('featureTest.featureCase.recoveredSuccessfully'));
|
||||
loadList();
|
||||
resetSelector();
|
||||
initRecycleModulesCount();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
// 批量删除
|
||||
async function handleBatchDelete() {
|
||||
openModal({
|
||||
type: 'error',
|
||||
title: t('featureTest.featureCase.batchDelete', { number: batchParams.value.currentSelectCount }),
|
||||
content: t('featureTest.featureCase.cleanOutDeleteTip'),
|
||||
okText: t('common.confirmDelete'),
|
||||
cancelText: t('common.cancel'),
|
||||
okButtonProps: {
|
||||
status: 'danger',
|
||||
},
|
||||
onBeforeOk: async () => {
|
||||
try {
|
||||
await batchDeleteRecycleCase(getBatchParams());
|
||||
Message.success(t('common.deleteSuccess'));
|
||||
loadList();
|
||||
resetSelector();
|
||||
initRecycleModulesCount();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
hideCancel: false,
|
||||
});
|
||||
}
|
||||
|
||||
// 批量操作
|
||||
function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) {
|
||||
batchParams.value = { ...params };
|
||||
if (event.eventTag === 'batchRecover') {
|
||||
handleBatchRecover();
|
||||
} else {
|
||||
handleBatchDelete();
|
||||
}
|
||||
}
|
||||
|
||||
// 获取对应模块路径name
|
||||
function getModules(moduleIds: string) {
|
||||
const modules = findNodePathByKey(caseTree.value, moduleIds, undefined, 'id');
|
||||
if (modules) {
|
||||
const moduleName = (modules || []).treePath.map((item: any) => item.name);
|
||||
|
||||
if (moduleName.length === 1) {
|
||||
return moduleName[0];
|
||||
}
|
||||
return `/${moduleName.join('/')}`;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取用例参数
|
||||
function getLoadListParams() {
|
||||
if (activeFolder.value === 'all') {
|
||||
searchParams.value.moduleIds = [];
|
||||
} else {
|
||||
searchParams.value.moduleIds = [activeFolder.value, ...offspringIds.value];
|
||||
}
|
||||
setLoadListParams({
|
||||
...searchParams.value,
|
||||
keyword: keyword.value,
|
||||
});
|
||||
}
|
||||
|
||||
// 初始化回收站列表
|
||||
function initRecycleList() {
|
||||
getLoadListParams();
|
||||
loadList();
|
||||
}
|
||||
|
||||
const searchList = debounce(() => {
|
||||
getLoadListParams();
|
||||
loadList();
|
||||
}, 100);
|
||||
|
||||
// 恢复用例
|
||||
async function recoverCase(id: string) {
|
||||
try {
|
||||
await recoverRecycleCase(id);
|
||||
Message.success(t('featureTest.featureCase.recoveredSuccessfully'));
|
||||
loadList();
|
||||
resetSelector();
|
||||
initRecycleModulesCount();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 彻底删除
|
||||
function handleBatchCleanOut(record: CaseManagementTable) {
|
||||
openModal({
|
||||
type: 'error',
|
||||
title: t('featureTest.featureCase.deleteCaseTitle', { name: characterLimit(record.name) }),
|
||||
content: t('featureTest.featureCase.cleanOutDeleteTip'),
|
||||
okText: t('common.confirmDelete'),
|
||||
cancelText: t('common.cancel'),
|
||||
okButtonProps: {
|
||||
status: 'danger',
|
||||
},
|
||||
onBeforeOk: async () => {
|
||||
try {
|
||||
await deleteRecycleCaseList(record.id);
|
||||
Message.success(t('common.deleteSuccess'));
|
||||
loadList();
|
||||
initRecycleModulesCount();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
hideCancel: false,
|
||||
});
|
||||
}
|
||||
// 返回
|
||||
function handleBack() {
|
||||
router.push({
|
||||
name: FeatureTestRouteEnum.FEATURE_TEST_CASE,
|
||||
});
|
||||
}
|
||||
|
||||
watch(
|
||||
() => activeFolder.value,
|
||||
() => {
|
||||
initRecycleList();
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => featureCaseStore.recycleModulesCount,
|
||||
(val) => {
|
||||
recycleModulesCount.value = { ...val };
|
||||
caseTree.value = mapTree<ModuleTreeNode>(caseTree.value, (node) => {
|
||||
return {
|
||||
...node,
|
||||
count: val?.[node.id] || 0,
|
||||
};
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
initRecycleList();
|
||||
getRecycleModules();
|
||||
initRecycleModulesCount();
|
||||
});
|
||||
tableStore.initColumn(TableKeyEnum.FILE_MANAGEMENT_CASE_RECYCLE, columns, 'drawer');
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.pageWrap {
|
||||
min-width: 1000px;
|
||||
height: calc(100vh - 136px);
|
||||
border-radius: var(--border-radius-large);
|
||||
@apply bg-white;
|
||||
.back {
|
||||
margin-right: 8px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 1px solid #ffffff;
|
||||
background: linear-gradient(90deg, rgb(var(--primary-9)) 3.36%, #ffffff 100%);
|
||||
box-shadow: 0 0 7px rgb(15 0 78 / 9%);
|
||||
.arco-icon {
|
||||
color: rgb(var(--primary-5));
|
||||
}
|
||||
@apply flex cursor-pointer items-center rounded-full;
|
||||
}
|
||||
.case {
|
||||
padding: 8px 4px;
|
||||
border-radius: var(--border-radius-small);
|
||||
@apply flex cursor-pointer items-center justify-between;
|
||||
&:hover {
|
||||
background-color: rgb(var(--primary-1));
|
||||
}
|
||||
.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);
|
||||
}
|
||||
.case-active {
|
||||
.folder-icon,
|
||||
.folder-name,
|
||||
.folder-count {
|
||||
color: rgb(var(--primary-5));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.page-header {
|
||||
@apply flex items-center justify-between;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,93 @@
|
|||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
import { StatusType } from '@/enums/caseEnum';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
// 获取列表对应的状态图标
|
||||
const statusIconMap = [
|
||||
{
|
||||
key: 'UN_REVIEWED',
|
||||
icon: StatusType.UN_REVIEWED,
|
||||
statusText: t('featureTest.featureCase.notReviewed'),
|
||||
},
|
||||
{
|
||||
key: 'UNDER_REVIEWED',
|
||||
icon: StatusType.UNDER_REVIEWED,
|
||||
statusText: t('featureTest.featureCase.reviewing'),
|
||||
},
|
||||
{
|
||||
key: 'PASS',
|
||||
icon: StatusType.PASS,
|
||||
statusText: t('featureTest.featureCase.passed'),
|
||||
},
|
||||
{
|
||||
key: 'UN_PASS',
|
||||
icon: StatusType.UN_PASS,
|
||||
statusText: t('featureTest.featureCase.notPass'),
|
||||
},
|
||||
{
|
||||
key: 'RE_REVIEWED',
|
||||
icon: StatusType.RE_REVIEWED,
|
||||
statusText: t('featureTest.featureCase.retrial'),
|
||||
},
|
||||
{
|
||||
key: 'UN_EXECUTED',
|
||||
icon: StatusType.UN_EXECUTED,
|
||||
statusText: t('featureTest.featureCase.nonExecution'),
|
||||
},
|
||||
{
|
||||
key: 'PASSED',
|
||||
icon: StatusType.PASSED,
|
||||
statusText: t('featureTest.featureCase.passed'),
|
||||
},
|
||||
{
|
||||
key: 'FAILED',
|
||||
icon: StatusType.FAILED,
|
||||
statusText: t('featureTest.featureCase.failure'),
|
||||
},
|
||||
{
|
||||
key: 'BLOCKED',
|
||||
icon: StatusType.BLOCKED,
|
||||
statusText: t('featureTest.featureCase.chokeUp'),
|
||||
},
|
||||
{
|
||||
key: 'SKIPPED',
|
||||
icon: StatusType.SKIPPED,
|
||||
statusText: t('featureTest.featureCase.skip'),
|
||||
},
|
||||
];
|
||||
|
||||
/** *
|
||||
*
|
||||
* @description 获取对应的状态文本
|
||||
* @param {status} 列表状态
|
||||
*/
|
||||
export function getStatusText(status: keyof typeof StatusType) {
|
||||
const currentStatus = statusIconMap.find((item) => item.key === status);
|
||||
return {
|
||||
iconType: currentStatus?.icon,
|
||||
statusType: currentStatus?.statusText,
|
||||
};
|
||||
}
|
||||
/** *
|
||||
*
|
||||
* @description 获取状态对应颜色
|
||||
* @param {status} 列表状态
|
||||
*/
|
||||
export function getReviewStatusClass(status: keyof typeof StatusType) {
|
||||
const grayColor = ['UN_REVIEWED', 'UN_EXECUTED'];
|
||||
const yellowColor = ['RE_REVIEWED', 'BLOCKED'];
|
||||
const blueColor = ['UNDER_REVIEWED', 'SKIPPED'];
|
||||
if (grayColor.includes(status)) {
|
||||
return 'text-[var(--color-text-brand)]';
|
||||
}
|
||||
if (yellowColor.includes(status)) {
|
||||
return 'text-[rgb(var(--warning-6))]';
|
||||
}
|
||||
if (blueColor.includes(status)) {
|
||||
return 'text-[rgb(var(--link-6))]';
|
||||
}
|
||||
}
|
||||
|
||||
export default {};
|
|
@ -0,0 +1,319 @@
|
|||
<template>
|
||||
<div class="mb-[16px]">
|
||||
<a-button type="primary" class="mr-[12px]" @click="caseDetail">
|
||||
{{ t('featureTest.featureCase.creatingCase') }}
|
||||
</a-button>
|
||||
<a-button type="outline"> {{ t('featureTest.featureCase.importCase') }} </a-button>
|
||||
</div>
|
||||
<div class="pageWrap">
|
||||
<MsSplitBox>
|
||||
<template #left>
|
||||
<div class="p-[24px] pb-0">
|
||||
<div class="feature-case h-[100%]">
|
||||
<div class="case h-[38px]">
|
||||
<div class="flex items-center" :class="getActiveClass('public')">
|
||||
<MsIcon type="icon-icon_folder_outlined-1" class="folder-icon" />
|
||||
<div class="folder-name mx-[4px]">{{ t('featureTest.featureCase.publicCase') }}</div>
|
||||
<div class="folder-count">({{ publicCaseCount }})</div></div
|
||||
>
|
||||
<div class="back"><icon-arrow-right /></div>
|
||||
</div>
|
||||
<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-count">({{ modulesCount.all }})</div></div
|
||||
>
|
||||
<div class="ml-auto flex items-center">
|
||||
<a-tooltip
|
||||
:content="
|
||||
isExpandAll ? t('project.fileManagement.collapseAll') : t('project.fileManagement.expandAll')
|
||||
"
|
||||
>
|
||||
<MsButton type="icon" status="secondary" class="!mr-0 p-[4px]" @click="expandHandler">
|
||||
<MsIcon :type="isExpandAll ? 'icon-icon_folder_collapse1' : 'icon-icon_folder_expansion1'" />
|
||||
</MsButton>
|
||||
</a-tooltip>
|
||||
<MsPopConfirm
|
||||
ref="confirmRef"
|
||||
v-model:visible="addSubVisible"
|
||||
:is-delete="false"
|
||||
:title="t('featureTest.featureCase.addSubModule')"
|
||||
:all-names="rootModulesName"
|
||||
:loading="confirmLoading"
|
||||
:ok-text="t('common.confirm')"
|
||||
:field-config="{
|
||||
placeholder: t('featureTest.featureCase.addGroupTip'),
|
||||
}"
|
||||
@confirm="confirmHandler"
|
||||
>
|
||||
<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>
|
||||
</MsPopConfirm>
|
||||
</div>
|
||||
</div>
|
||||
<a-divider class="my-[8px]" />
|
||||
<FeatureCaseTree
|
||||
ref="caseTreeRef"
|
||||
v-model:selected-keys="selectedKeys"
|
||||
:all-names="rootModulesName"
|
||||
:active-folder="activeFolder"
|
||||
:is-expand-all="isExpandAll"
|
||||
:modules-count="modulesCount"
|
||||
@case-node-select="caseNodeSelect"
|
||||
@init="setRootModules"
|
||||
></FeatureCaseTree>
|
||||
<div class="b-0 absolute w-[88%]">
|
||||
<a-divider class="!my-0 !mb-2" />
|
||||
<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-count">({{ recycleModulesCount.all }})</div></div
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #right>
|
||||
<div class="p-[24px]">
|
||||
<CaseTable
|
||||
:active-folder="activeFolder"
|
||||
:offspring-ids="offspringIds"
|
||||
:active-folder-type="activeCaseType"
|
||||
:modules-count="modulesCount"
|
||||
@init="initModulesCount"
|
||||
></CaseTable>
|
||||
</div>
|
||||
</template>
|
||||
</MsSplitBox>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* @description 功能测试-功能用例
|
||||
*/
|
||||
import { computed, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
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 MsSplitBox from '@/components/pure/ms-split-box/index.vue';
|
||||
import CaseTable from './components/caseTable.vue';
|
||||
import FeatureCaseTree from './components/caseTree.vue';
|
||||
|
||||
import { createCaseModuleTree } from '@/api/modules/case-management/featureCase';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
import useFeatureCaseStore from '@/store/modules/case/featureCase';
|
||||
|
||||
import type { CaseModuleQueryParams, CreateOrUpdateModule } from '@/models/caseManagement/featureCase';
|
||||
import { FeatureTestRouteEnum } from '@/enums/routeEnum';
|
||||
|
||||
import Message from '@arco-design/web-vue/es/message';
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const appStore = useAppStore();
|
||||
const { t } = useI18n();
|
||||
const currentProjectId = computed(() => appStore.currentProjectId);
|
||||
|
||||
const isExpandAll = ref(false);
|
||||
const activeCaseType = ref<'folder' | 'module'>('folder'); // 激活用例类型
|
||||
const rootModulesName = ref<string[]>([]); // 根模块名称列表
|
||||
|
||||
const publicCaseCount = ref<number>(0); // 公共用例数量
|
||||
|
||||
// 全部展开或折叠
|
||||
const expandHandler = () => {
|
||||
isExpandAll.value = !isExpandAll.value;
|
||||
};
|
||||
|
||||
const activeFolder = ref<string>('all');
|
||||
|
||||
// 选中节点
|
||||
const selectedKeys = computed({
|
||||
get: () => [activeFolder.value],
|
||||
set: (val) => val,
|
||||
});
|
||||
|
||||
const offspringIds = ref<string[]>([]);
|
||||
|
||||
// 设置当前激活用例类型公共用例|全部用例|回收站
|
||||
const setActiveFolder = (type: string) => {
|
||||
activeFolder.value = type;
|
||||
if (['public', 'all', 'recycle'].includes(type)) {
|
||||
activeCaseType.value = 'folder';
|
||||
}
|
||||
if (type === 'recycle') {
|
||||
router.push({
|
||||
name: FeatureTestRouteEnum.FEATURE_TEST_CASE_RECYCLE,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 获取激活用例类型样式
|
||||
const getActiveClass = (type: string) => {
|
||||
return activeFolder.value === type ? 'folder-text case-active' : 'folder-text';
|
||||
};
|
||||
|
||||
const featureCaseStore = useFeatureCaseStore();
|
||||
// 处理用例树节点选中
|
||||
function caseNodeSelect(keys: string[], _offspringIds: string[]) {
|
||||
[activeFolder.value] = keys;
|
||||
activeCaseType.value = 'module';
|
||||
offspringIds.value = [..._offspringIds];
|
||||
featureCaseStore.setModuleId(keys, offspringIds.value);
|
||||
}
|
||||
|
||||
const confirmLoading = ref(false);
|
||||
const confirmRef = ref();
|
||||
const addSubVisible = ref(false);
|
||||
const caseTreeRef = ref();
|
||||
|
||||
// 添加子模块
|
||||
const confirmHandler = async () => {
|
||||
try {
|
||||
confirmLoading.value = true;
|
||||
const { field } = confirmRef.value.form;
|
||||
if (!confirmRef.value.isPass) {
|
||||
return;
|
||||
}
|
||||
const params: CreateOrUpdateModule = {
|
||||
projectId: currentProjectId.value,
|
||||
name: field,
|
||||
parentId: 'none',
|
||||
};
|
||||
await createCaseModuleTree(params);
|
||||
Message.success(t('featureTest.featureCase.addSuccess'));
|
||||
caseTreeRef.value.initModules();
|
||||
addSubVisible.value = false;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
confirmLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 设置根模块名称列表
|
||||
* @param names 根模块名称列表
|
||||
*/
|
||||
function setRootModules(names: string[]) {
|
||||
rootModulesName.value = names;
|
||||
}
|
||||
|
||||
// 表格搜索参数
|
||||
const tableFilterParams = ref<CaseModuleQueryParams>({
|
||||
moduleIds: [],
|
||||
projectId: '',
|
||||
});
|
||||
|
||||
const modulesCount = computed(() => {
|
||||
return featureCaseStore.modulesCount;
|
||||
});
|
||||
|
||||
const recycleModulesCount = computed(() => {
|
||||
return featureCaseStore.recycleModulesCount;
|
||||
});
|
||||
|
||||
/**
|
||||
* 右侧表格数据刷新后,若当前展示的是模块,则刷新模块树的统计数量
|
||||
*/
|
||||
function initModulesCount(params: CaseModuleQueryParams) {
|
||||
featureCaseStore.getCaseModulesCountCount(params);
|
||||
featureCaseStore.getRecycleMModulesCountCount(params);
|
||||
tableFilterParams.value = { ...params };
|
||||
}
|
||||
|
||||
// 创建用例
|
||||
function caseDetail() {
|
||||
router.push({
|
||||
name: FeatureTestRouteEnum.FEATURE_TEST_CASE_DETAIL,
|
||||
});
|
||||
}
|
||||
|
||||
// 设置默认选中状态
|
||||
router.beforeEach((to: any, from: any, next) => {
|
||||
const routeEnumValues = Object.values(FeatureTestRouteEnum);
|
||||
if (!routeEnumValues.includes(to.name)) {
|
||||
// 当前路由不在枚举中,清空仓库的状态值
|
||||
featureCaseStore.setIsAlreadySuccess(false);
|
||||
}
|
||||
next();
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
if (featureCaseStore.operatingState) {
|
||||
[activeFolder.value] = featureCaseStore.moduleId;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.pageWrap {
|
||||
min-width: 1000px;
|
||||
height: calc(100vh - 136px);
|
||||
border-radius: var(--border-radius-large);
|
||||
@apply bg-white;
|
||||
.case {
|
||||
padding: 8px 4px;
|
||||
border-radius: var(--border-radius-small);
|
||||
@apply flex cursor-pointer items-center justify-between;
|
||||
&:hover {
|
||||
background-color: rgb(var(--primary-1));
|
||||
}
|
||||
.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);
|
||||
}
|
||||
.case-active {
|
||||
.folder-icon,
|
||||
.folder-name,
|
||||
.folder-count {
|
||||
color: rgb(var(--primary-5));
|
||||
}
|
||||
}
|
||||
.back {
|
||||
margin-right: 8px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 1px solid #ffffff;
|
||||
background: linear-gradient(90deg, rgb(var(--primary-9)) 3.36%, #ffffff 100%);
|
||||
box-shadow: 0 0 7px rgb(15 0 78 / 9%);
|
||||
.arco-icon {
|
||||
color: rgb(var(--primary-5));
|
||||
}
|
||||
@apply flex cursor-pointer items-center rounded-full;
|
||||
}
|
||||
}
|
||||
}
|
||||
.recycle {
|
||||
@apply absolute bottom-0 bg-white pb-4;
|
||||
:deep(.arco-divider-horizontal) {
|
||||
margin: 8px 0;
|
||||
}
|
||||
.recycle-bin {
|
||||
@apply bottom-0 flex items-center bg-white;
|
||||
.recycle-count {
|
||||
margin-left: 4px;
|
||||
color: var(--color-text-4);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,108 @@
|
|||
export default {
|
||||
'featureTest.featureCase.creatingCase': 'Create Case',
|
||||
'featureTest.featureCase.importCase': 'Import Case',
|
||||
'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':
|
||||
'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.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':
|
||||
'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':
|
||||
'After deletion, the data will not be recovered, please operate with caution!',
|
||||
'featureTest.featureCase.pleaseEnterInputTags': 'Please enter content Enter add label',
|
||||
};
|
|
@ -0,0 +1,107 @@
|
|||
export default {
|
||||
'featureTest.featureCase.creatingCase': '创建用例',
|
||||
'featureTest.featureCase.importCase': '导入用例',
|
||||
'featureTest.featureCase.publicCase': '公共用例库',
|
||||
'featureTest.featureCase.allCase': '全部用例',
|
||||
'featureTest.featureCase.searchTip': '请输入分组名称',
|
||||
'featureTest.featureCase.caseEmptyContent': '暂无用例数据,请点击上方按钮创建或导入',
|
||||
'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': '请输入内容回车添加标签',
|
||||
};
|
|
@ -1,147 +0,0 @@
|
|||
<template>
|
||||
<div class="page-header h-[34px]">
|
||||
<div class="text-[var(--color-text-1)]"
|
||||
>{{ t('featureTest.featureCase.allCase') }}
|
||||
<span class="text-[var(--color-text-4)]"> ({{ allCaseCount }})</span></div
|
||||
>
|
||||
<div class="flex w-[80%] items-center justify-end">
|
||||
<a-select class="w-[240px]" :placeholder="t('featureTest.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')"
|
||||
allow-clear
|
||||
class="mx-[8px] w-[240px]"
|
||||
></a-input-search>
|
||||
<MsTag
|
||||
:type="isExpandFilter ? 'primary' : 'default'"
|
||||
:theme="isExpandFilter ? 'lightOutLine' : 'outline'"
|
||||
size="large"
|
||||
class="-mt-[3px] min-w-[64px] cursor-pointer"
|
||||
>
|
||||
<span :class="!isExpandFilter ? 'text-[var(--color-text-4)]' : ''" @click="isExpandFilterHandler"
|
||||
><icon-filter class="mr-[4px]" :style="{ 'font-size': '16px' }" />{{
|
||||
t('featureTest.featureCase.filter')
|
||||
}}</span
|
||||
>
|
||||
</MsTag>
|
||||
<a-radio-group v-model:model-value="showType" type="button" class="file-show-type ml-[4px]">
|
||||
<a-radio value="list" class="show-type-icon p-[2px]"><MsIcon type="icon-icon_view-list_outlined" /></a-radio>
|
||||
<a-radio value="xmind" class="show-type-icon p-[2px]"><MsIcon type="icon-icon_mindnote_outlined" /></a-radio>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
<FilterPanel v-show="isExpandFilter"></FilterPanel>
|
||||
<MinderEditor
|
||||
:import-json="importJson"
|
||||
:tags="['模块', '用例', '前置条件', '备注', '步骤', '预期结果']"
|
||||
tag-enable
|
||||
sequence-enable
|
||||
@node-click="handleNodeClick"
|
||||
/>
|
||||
<MsDrawer v-model:visible="visible" :width="480" :mask="false">
|
||||
{{ nodeData.text }}
|
||||
</MsDrawer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
|
||||
import MinderEditor from '@/components/pure/minder-editor/minderEditor.vue';
|
||||
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
|
||||
import MsTag from '@/components/pure/ms-tag/ms-tag.vue';
|
||||
import FilterPanel from '@/components/business/ms-filter-panel/searchForm.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
const versionOptions = ref([
|
||||
{
|
||||
id: '1001',
|
||||
name: 'v_1.0',
|
||||
},
|
||||
]);
|
||||
|
||||
const keyword = ref<string>();
|
||||
|
||||
const showType = ref<string>('list');
|
||||
|
||||
const allCaseCount = ref<number>(100);
|
||||
|
||||
const isExpandFilter = ref<boolean>(false);
|
||||
|
||||
// 是否展开||折叠高级筛选
|
||||
const isExpandFilterHandler = () => {
|
||||
isExpandFilter.value = !isExpandFilter.value;
|
||||
};
|
||||
|
||||
const visible = ref<boolean>(false);
|
||||
const nodeData = ref<any>({});
|
||||
|
||||
const importJson = ref<any>({});
|
||||
|
||||
function handleNodeClick(data: any) {
|
||||
if (data.resource && data.resource.includes('用例')) {
|
||||
visible.value = true;
|
||||
nodeData.value = data;
|
||||
}
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
importJson.value = {
|
||||
root: {
|
||||
data: {
|
||||
text: '测试用例',
|
||||
id: 'xxxx',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
data: {
|
||||
id: 'sdasdas',
|
||||
text: '模块 1',
|
||||
resource: ['模块'],
|
||||
},
|
||||
},
|
||||
{
|
||||
data: {
|
||||
id: 'dasdasda',
|
||||
text: '模块 2',
|
||||
expandState: 'collapse',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
data: {
|
||||
id: 'frihofiuho3f',
|
||||
text: '用例 1',
|
||||
resource: ['用例'],
|
||||
},
|
||||
},
|
||||
{
|
||||
data: {
|
||||
id: 'df09348f034f',
|
||||
text: ' 用例 2',
|
||||
resource: ['用例'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
template: 'default',
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.page-header {
|
||||
@apply flex items-center justify-between;
|
||||
}
|
||||
.filter-panel {
|
||||
background: var(--color-text-n9);
|
||||
@apply mt-1 rounded-md p-3;
|
||||
.condition-text {
|
||||
color: var(--color-text-2);
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,293 +0,0 @@
|
|||
<template>
|
||||
<MsTree
|
||||
v-model:focus-node-key="focusNodeKey"
|
||||
:selected-keys="props.selectedKeys"
|
||||
:data="caseTree"
|
||||
:keyword="groupKeyword"
|
||||
:node-more-actions="caseMoreActions"
|
||||
:expand-all="props.isExpandAll"
|
||||
:empty-text="t('featureTest.featureCase.caseEmptyContent')"
|
||||
draggable
|
||||
:virtual-list-props="virtualListProps"
|
||||
block-node
|
||||
@select="caseNodeSelect"
|
||||
@more-action-select="handleCaseMoreSelect"
|
||||
@more-actions-close="moreActionsClose"
|
||||
>
|
||||
<template #title="nodeData">
|
||||
<span class="text-[var(--color-text-1)]">{{ nodeData.title }}</span>
|
||||
<span class="ml-[4px] text-[var(--color-text-4)]">({{ nodeData.count }})</span>
|
||||
</template>
|
||||
<template #extra="nodeData">
|
||||
<MsPopConfirm
|
||||
:is-delete="false"
|
||||
:all-names="[]"
|
||||
:title="t('featureTest.featureCase.addSubModule')"
|
||||
@cancel="resetFocusNodeKey"
|
||||
>
|
||||
<MsButton type="icon" size="mini" class="ms-tree-node-extra__btn !mr-0" @click="setFocusKey(nodeData)">
|
||||
<MsIcon type="icon-icon_add_outlined" size="14" class="text-[var(--color-text-4)]" />
|
||||
</MsButton>
|
||||
</MsPopConfirm>
|
||||
<MsPopConfirm
|
||||
:title="t('featureTest.featureCase.rename')"
|
||||
:all-names="[]"
|
||||
:is-delete="false"
|
||||
:field-config="{ field: renameCaseName }"
|
||||
@cancel="resetFocusNodeKey"
|
||||
>
|
||||
<span :id="`renameSpan${nodeData.key}`" class="relative"></span>
|
||||
</MsPopConfirm>
|
||||
</template>
|
||||
</MsTree>
|
||||
<div class="recycle w-[88%]">
|
||||
<a-divider class="mb-[16px]" />
|
||||
<div class="recycle-bin pt-2">
|
||||
<MsIcon type="icon-icon_delete-trash_outlined" size="16" class="mx-[10px] text-[var(--color-text-4)]" />
|
||||
<div class="text-[var(--color-text-1)]">{{ t('featureTest.featureCase.recycle') }}</div>
|
||||
<div class="recycle-count">({{ recycleCount }})</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsPopConfirm from '@/components/pure/ms-popconfirm/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 { useI18n } from '@/hooks/useI18n';
|
||||
import useModal from '@/hooks/useModal';
|
||||
|
||||
const { t } = useI18n();
|
||||
const { openModal } = useModal();
|
||||
|
||||
const focusNodeKey = ref<string | number>('');
|
||||
|
||||
const props = defineProps<{
|
||||
selectedKeys?: Array<string | number>; // 选中的节点 key
|
||||
isExpandAll: boolean; // 是否展开用例节点
|
||||
}>();
|
||||
|
||||
const emits = defineEmits(['update:selectedKeys', 'caseNodeSelect']);
|
||||
|
||||
const groupKeyword = ref<string>('');
|
||||
|
||||
const caseTree = ref([
|
||||
{
|
||||
title: 'Trunk',
|
||||
key: 'node1',
|
||||
count: 18,
|
||||
children: [
|
||||
{
|
||||
title: 'Leaf',
|
||||
key: 'node2',
|
||||
count: 28,
|
||||
},
|
||||
{
|
||||
title: 'Leaf',
|
||||
key: 'node4',
|
||||
count: 138,
|
||||
},
|
||||
{
|
||||
title: 'Leaf',
|
||||
key: 'node5',
|
||||
count: 108,
|
||||
},
|
||||
{
|
||||
title: 'Leaf',
|
||||
key: 'node4',
|
||||
count: 138,
|
||||
},
|
||||
{
|
||||
title: 'Leaf',
|
||||
key: 'node5',
|
||||
count: 108,
|
||||
},
|
||||
{
|
||||
title: 'Leaf',
|
||||
key: 'node4',
|
||||
count: 138,
|
||||
},
|
||||
{
|
||||
title: 'Leaf',
|
||||
key: 'node5',
|
||||
count: 108,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Trunk',
|
||||
key: 'node3',
|
||||
count: 180,
|
||||
children: [
|
||||
{
|
||||
title: 'Leaf',
|
||||
key: 'node4',
|
||||
count: 138,
|
||||
},
|
||||
{
|
||||
title: 'Leaf',
|
||||
key: 'node5',
|
||||
count: 108,
|
||||
},
|
||||
{
|
||||
title: 'Leaf',
|
||||
key: 'node4',
|
||||
count: 138,
|
||||
},
|
||||
{
|
||||
title: 'Leaf',
|
||||
key: 'node5',
|
||||
count: 108,
|
||||
},
|
||||
{
|
||||
title: 'Leaf',
|
||||
key: 'node4',
|
||||
count: 138,
|
||||
},
|
||||
{
|
||||
title: 'Leaf',
|
||||
key: 'node5',
|
||||
count: 108,
|
||||
},
|
||||
{
|
||||
title: 'Leaf',
|
||||
key: 'node4',
|
||||
count: 138,
|
||||
},
|
||||
{
|
||||
title: 'Leaf',
|
||||
key: 'node5',
|
||||
count: 108,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Trunk',
|
||||
key: 'node6',
|
||||
children: [],
|
||||
count: 0,
|
||||
},
|
||||
]);
|
||||
|
||||
const caseMoreActions: ActionsItem[] = [
|
||||
{
|
||||
label: 'featureTest.featureCase.rename',
|
||||
eventTag: 'rename',
|
||||
},
|
||||
{
|
||||
label: 'featureTest.featureCase.delete',
|
||||
eventTag: 'delete',
|
||||
danger: true,
|
||||
},
|
||||
];
|
||||
|
||||
const renameCaseName = ref('');
|
||||
|
||||
const selectedNodeKeys = ref(props.selectedKeys || []);
|
||||
|
||||
const renamePopVisible = ref(false);
|
||||
|
||||
// 用例树节点选中事件
|
||||
const caseNodeSelect = (selectedKeys: (string | number)[]) => {
|
||||
emits('caseNodeSelect', selectedKeys);
|
||||
};
|
||||
|
||||
// 删除节点
|
||||
const deleteHandler = (node: MsTreeNodeData) => {
|
||||
openModal({
|
||||
type: 'error',
|
||||
title: t('featureTest.featureCase.deleteTipTitle', { name: node.title }),
|
||||
content: t('featureTest.featureCase.deleteCaseTipContent'),
|
||||
okText: t('featureTest.featureCase.deleteConfirm'),
|
||||
okButtonProps: {
|
||||
status: 'danger',
|
||||
},
|
||||
maskClosable: false,
|
||||
onBeforeOk: async () => {
|
||||
try {
|
||||
Message.success(t('featureTest.featureCase.deleteSuccess'));
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
hideCancel: false,
|
||||
});
|
||||
};
|
||||
|
||||
function resetFocusNodeKey() {
|
||||
focusNodeKey.value = '';
|
||||
renamePopVisible.value = false;
|
||||
renameCaseName.value = '';
|
||||
}
|
||||
|
||||
// 用例树节点更多事件
|
||||
const handleCaseMoreSelect = (item: ActionsItem, node: MsTreeNodeData) => {
|
||||
switch (item.eventTag) {
|
||||
case 'delete':
|
||||
deleteHandler(node);
|
||||
resetFocusNodeKey();
|
||||
break;
|
||||
case 'rename':
|
||||
renameCaseName.value = node.title || '';
|
||||
renamePopVisible.value = true;
|
||||
document.querySelector(`#renameSpan${node.key}`)?.dispatchEvent(new Event('click'));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const moreActionsClose = () => {
|
||||
if (!renamePopVisible.value) {
|
||||
resetFocusNodeKey();
|
||||
}
|
||||
};
|
||||
|
||||
const setFocusKey = (node: MsTreeNodeData) => {
|
||||
focusNodeKey.value = node.key || '';
|
||||
};
|
||||
|
||||
const recycleCount = ref<number>(100);
|
||||
|
||||
const virtualListProps = computed(() => {
|
||||
return {
|
||||
height: 'calc(100vh - 376px)',
|
||||
};
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.selectedKeys,
|
||||
(val) => {
|
||||
selectedNodeKeys.value = val || [];
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => selectedNodeKeys.value,
|
||||
(val) => {
|
||||
emits('update:selectedKeys', val);
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.recycle {
|
||||
@apply absolute bottom-0 bg-white pb-4;
|
||||
:deep(.arco-divider-horizontal) {
|
||||
margin: 8px 0;
|
||||
}
|
||||
.recycle-bin {
|
||||
@apply bottom-0 flex items-center bg-white;
|
||||
.recycle-count {
|
||||
margin-left: 4px;
|
||||
color: var(--color-text-4);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,173 +0,0 @@
|
|||
<template>
|
||||
<div class="mb-[16px]">
|
||||
<a-button type="primary" class="mr-[12px]"> {{ t('featureTest.featureCase.creatingCase') }} </a-button>
|
||||
<a-button type="outline"> {{ t('featureTest.featureCase.importCase') }} </a-button>
|
||||
</div>
|
||||
<div class="pageWrap">
|
||||
<MsSplitBox>
|
||||
<template #left>
|
||||
<div class="p-[24px]">
|
||||
<div class="feature-case">
|
||||
<div class="case h-[38px]">
|
||||
<div class="flex items-center" :class="getActiveClass('public')" @click="selectActive('public')">
|
||||
<MsIcon type="icon-icon_folder_outlined-1" class="folder-icon" />
|
||||
<div class="folder-name mx-[4px]">{{ t('featureTest.featureCase.publicCase') }}</div>
|
||||
<div class="folder-count">({{ publicCaseCount }})</div></div
|
||||
>
|
||||
<div class="back"><icon-arrow-right /></div>
|
||||
</div>
|
||||
<a-divider class="my-[8px]" />
|
||||
<a-input-search class="mb-4" :placeholder="t('featureTest.featureCase.searchTip')" />
|
||||
<div class="case h-[38px]">
|
||||
<div class="flex items-center" :class="getActiveClass('all')" @click="selectActive('all')">
|
||||
<MsIcon type="icon-icon_folder_filled1" class="folder-icon" />
|
||||
<div class="folder-name mx-[4px]">{{ t('featureTest.featureCase.allCase') }}</div>
|
||||
<div class="folder-count">(100)</div></div
|
||||
>
|
||||
<div class="ml-auto flex items-center">
|
||||
<a-tooltip
|
||||
:content="
|
||||
isExpandAll ? t('project.fileManagement.collapseAll') : t('project.fileManagement.expandAll')
|
||||
"
|
||||
>
|
||||
<MsButton type="icon" status="secondary" class="!mr-0 p-[4px]" @click="expandHandler">
|
||||
<MsIcon :type="isExpandAll ? 'icon-icon_folder_collapse1' : 'icon-icon_folder_expansion1'" />
|
||||
</MsButton>
|
||||
</a-tooltip>
|
||||
<MsPopConfirm
|
||||
:is-delete="false"
|
||||
:title="t('featureTest.featureCase.addSubModule')"
|
||||
:all-names="[]"
|
||||
:loading="confirmLoading"
|
||||
@confirm="confirmHandler"
|
||||
>
|
||||
<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>
|
||||
</MsPopConfirm>
|
||||
</div>
|
||||
</div>
|
||||
<a-divider class="my-[8px]" />
|
||||
<FeatureCaseTree
|
||||
v-model:selected-keys="selectedKeys"
|
||||
:is-expand-all="isExpandAll"
|
||||
@case-node-select="caseNodeSelect"
|
||||
></FeatureCaseTree>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #right>
|
||||
<div class="p-[24px]">
|
||||
<CaseTable></CaseTable>
|
||||
</div>
|
||||
</template>
|
||||
</MsSplitBox>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* @description 功能测试-功能用例
|
||||
*/
|
||||
import { computed, ref } from '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 MsSplitBox from '@/components/pure/ms-split-box/index.vue';
|
||||
import CaseTable from './components/caseTable.vue';
|
||||
import FeatureCaseTree from './components/featureCaseTree.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const isExpandAll = ref(false);
|
||||
|
||||
const activeCase = ref<string | number>('public'); // 激活用例
|
||||
|
||||
const publicCaseCount = ref<number>(100); // 公共用例数量
|
||||
|
||||
// 设置当前激活用例类型
|
||||
const selectActive = (type: string) => {
|
||||
activeCase.value = type;
|
||||
};
|
||||
|
||||
// 获取激活用例样式
|
||||
const getActiveClass = (type: string) => {
|
||||
return activeCase.value === type ? 'folder-text case-active' : 'folder-text';
|
||||
};
|
||||
|
||||
const expandHandler = () => {
|
||||
isExpandAll.value = !isExpandAll.value;
|
||||
};
|
||||
|
||||
// 选中节点
|
||||
const selectedKeys = computed({
|
||||
get: () => [activeCase.value],
|
||||
set: (val) => val,
|
||||
});
|
||||
|
||||
// 处理用例树节点选中
|
||||
function caseNodeSelect(keys: (string | number)[]) {
|
||||
[activeCase.value] = keys;
|
||||
}
|
||||
|
||||
const confirmLoading = ref(false);
|
||||
|
||||
const confirmHandler = () => {
|
||||
try {
|
||||
confirmLoading.value = true;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
confirmLoading.value = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.pageWrap {
|
||||
min-width: 1000px;
|
||||
height: calc(100vh - 136px);
|
||||
border-radius: var(--border-radius-large);
|
||||
@apply bg-white;
|
||||
.case {
|
||||
@apply flex cursor-pointer items-center justify-between;
|
||||
.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);
|
||||
}
|
||||
.case-active {
|
||||
.folder-icon,
|
||||
.folder-name,
|
||||
.folder-count {
|
||||
color: rgb(var(--primary-5));
|
||||
}
|
||||
}
|
||||
.back {
|
||||
margin-right: 8px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 1px solid #ffffff;
|
||||
background: linear-gradient(90deg, rgb(var(--primary-9)) 3.36%, #ffffff 100%);
|
||||
box-shadow: 0 0 7px rgb(15 0 78 / 9%);
|
||||
.arco-icon {
|
||||
color: rgb(var(--primary-5));
|
||||
}
|
||||
@apply flex cursor-pointer items-center rounded-full;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,26 +0,0 @@
|
|||
export default {
|
||||
'featureTest.featureCase.creatingCase': 'Create Case',
|
||||
'featureTest.featureCase.importCase': 'Import Case',
|
||||
'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':
|
||||
'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',
|
||||
};
|
|
@ -1,25 +0,0 @@
|
|||
export default {
|
||||
'featureTest.featureCase.creatingCase': '创建用例',
|
||||
'featureTest.featureCase.importCase': '导入用例',
|
||||
'featureTest.featureCase.publicCase': '公共用例库',
|
||||
'featureTest.featureCase.allCase': '全部用例',
|
||||
'featureTest.featureCase.searchTip': '请输入分组名称',
|
||||
'featureTest.featureCase.caseEmptyContent': '暂无用例数据,请点击上方按钮创建或导入',
|
||||
'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': '删除成功',
|
||||
};
|
|
@ -1,3 +0,0 @@
|
|||
<template> Feature Test is waiting for development </template>
|
||||
|
||||
<script setup></script>
|
|
@ -211,9 +211,9 @@
|
|||
openModal({
|
||||
type: 'error',
|
||||
title: t('system.orgTemplate.deleteTemplateTitle', { name: characterLimit(record.name) }),
|
||||
content: t('system.userGroup.beforeDeleteUserGroup'),
|
||||
okText: t('system.userGroup.confirmDelete'),
|
||||
cancelText: t('system.userGroup.cancel'),
|
||||
content: t('system.orgTemplate.deleteProjectTemplateTip'),
|
||||
okText: t('common.confirmDelete'),
|
||||
cancelText: t('common.cancel'),
|
||||
okButtonProps: {
|
||||
status: 'danger',
|
||||
},
|
||||
|
|
|
@ -136,7 +136,7 @@
|
|||
import { useAppStore, useTableStore } from '@/store';
|
||||
import { characterLimit } from '@/utils';
|
||||
|
||||
import type { AddorUpdateMemberModel, BatchAddProjectModel, LinkList, MemberItem } from '@/models/setting/member';
|
||||
import type { AddOrUpdateMemberModel, BatchAddProjectModel, LinkList, MemberItem } from '@/models/setting/member';
|
||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||
|
||||
const tableStore = useTableStore();
|
||||
|
@ -153,7 +153,7 @@
|
|||
showTooltip: true,
|
||||
ellipsis: true,
|
||||
sortIndex: 0,
|
||||
showDrag: true,
|
||||
showDrag: false,
|
||||
},
|
||||
{
|
||||
title: 'organization.member.tableColunmName',
|
||||
|
@ -243,7 +243,7 @@
|
|||
const addMemberVisible = ref<boolean>(false);
|
||||
const AddMemberRef = ref();
|
||||
|
||||
const addOrEditMember = (type: string, record: AddorUpdateMemberModel = {}) => {
|
||||
const addOrEditMember = (type: string, record: AddOrUpdateMemberModel = {}) => {
|
||||
addMemberVisible.value = true;
|
||||
AddMemberRef.value.type = type;
|
||||
if (type === 'edit') {
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
>
|
||||
<div v-if="sceneType === 'BUG'" class="optionsKey">
|
||||
<a-checkbox v-model="fieldForm.enableOptionKey"
|
||||
>选项KEY值
|
||||
>{{ t('system.orgTemplate.optionKeyValue') }}
|
||||
<a-tooltip :content="t('system.orgTemplate.thirdPartyPlatforms')"
|
||||
><icon-question-circle
|
||||
:style="{ 'font-size': '16px' }"
|
||||
|
|
|
@ -118,7 +118,6 @@
|
|||
() => props.cardItem,
|
||||
(val) => {
|
||||
if (val) {
|
||||
debugger;
|
||||
templateCardInfo.value = { ...props.cardItem };
|
||||
}
|
||||
},
|
||||
|
|
|
@ -164,4 +164,10 @@ export default {
|
|||
'system.orgTemplate.defectContentTip':
|
||||
'You can set the default value for the defect content and use it when creating',
|
||||
'system.orgTemplate.templateNameRules': 'Please enter a template name',
|
||||
'system.orgTemplate.deleteProjectTemplateTip':
|
||||
'The existing use cases of this template will inherit the default template after deleting it. Are you sure to delete it',
|
||||
'system.orgTemplate.moduleRuleTip': 'Please select module',
|
||||
'system.orgTemplate.modules': 'module',
|
||||
'system.orgTemplate.tags': 'tags',
|
||||
'system.orgTemplate.optionKeyValue': 'Option KEY value',
|
||||
};
|
||||
|
|
|
@ -156,4 +156,9 @@ export default {
|
|||
'system.orgTemplate.defectNameTip': '可为缺陷名称设置默认值,创建时统一使用',
|
||||
'system.orgTemplate.defectContentTip': '可为缺陷内容设置默认值,创建时统一使用',
|
||||
'system.orgTemplate.templateNameRules': '请输入模板名称',
|
||||
'system.orgTemplate.deleteProjectTemplateTip': '删除后,该模版已有的用例会继承默认模版,确认删除吗?',
|
||||
'system.orgTemplate.moduleRuleTip': '请选择模块',
|
||||
'system.orgTemplate.modules': '模块',
|
||||
'system.orgTemplate.tags': '标签',
|
||||
'system.orgTemplate.optionKeyValue': '选项KEY值',
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue