fix: 全局用例&模板&部分权限补充
This commit is contained in:
parent
ceafebe073
commit
c810f8b8d3
|
@ -157,7 +157,7 @@
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useVModel } from '@vueuse/core';
|
import { useVModel } from '@vueuse/core';
|
||||||
import { TagData } from '@arco-design/web-vue';
|
import { Message, TagData } from '@arco-design/web-vue';
|
||||||
|
|
||||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||||
|
@ -241,22 +241,36 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
function handleChange(_fileList: MsFileItem[], fileItem: MsFileItem) {
|
function handleChange(_fileList: MsFileItem[], fileItem: MsFileItem) {
|
||||||
innerFileList.value = _fileList.map((item) => ({ ...item, local: true }));
|
// 校验本地文件是否重复
|
||||||
if (props.multiple) {
|
const isRepeat = _fileList.filter((item) => item.name === fileItem.name).length > 1;
|
||||||
inputFiles.value = _fileList.map((item) => ({
|
debugger;
|
||||||
...item,
|
if (isRepeat) {
|
||||||
value: item?.uid || '',
|
Message.error(t('ms.add.attachment.repeatFileTip'));
|
||||||
label: item?.name || '',
|
innerFileList.value = _fileList.reduce((prev: MsFileItem[], current: MsFileItem) => {
|
||||||
local: true,
|
const isExist = prev.find((item: any) => item.name === current.name);
|
||||||
}));
|
if (!isExist) {
|
||||||
|
prev.push(current);
|
||||||
|
}
|
||||||
|
return prev;
|
||||||
|
}, []);
|
||||||
} else {
|
} else {
|
||||||
inputFileName.value = fileItem.name || '';
|
innerFileList.value = _fileList.map((item) => ({ ...item, local: true }));
|
||||||
|
if (props.multiple) {
|
||||||
|
inputFiles.value = _fileList.map((item) => ({
|
||||||
|
...item,
|
||||||
|
value: item?.uid || '',
|
||||||
|
label: item?.name || '',
|
||||||
|
local: true,
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
inputFileName.value = fileItem.name || '';
|
||||||
|
}
|
||||||
|
emit('change', _fileList, { ...fileItem, local: true });
|
||||||
|
nextTick(() => {
|
||||||
|
// 在 emit 文件上去之后再关闭菜单
|
||||||
|
buttonDropDownVisible.value = false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
emit('change', _fileList, { ...fileItem, local: true });
|
|
||||||
nextTick(() => {
|
|
||||||
// 在 emit 文件上去之后再关闭菜单
|
|
||||||
buttonDropDownVisible.value = false;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function associatedFile() {
|
function associatedFile() {
|
||||||
|
|
|
@ -7,4 +7,5 @@ export default {
|
||||||
'ms.add.attachment.remove': 'Remove',
|
'ms.add.attachment.remove': 'Remove',
|
||||||
'ms.add.attachment.cancelAssociate': 'Disassociate',
|
'ms.add.attachment.cancelAssociate': 'Disassociate',
|
||||||
'ms.add.attachment.saveAs': 'Save',
|
'ms.add.attachment.saveAs': 'Save',
|
||||||
|
'ms.add.attachment.repeatFileTip': 'File already exists.',
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,4 +7,5 @@ export default {
|
||||||
'ms.add.attachment.remove': '移除',
|
'ms.add.attachment.remove': '移除',
|
||||||
'ms.add.attachment.cancelAssociate': '取消关联',
|
'ms.add.attachment.cancelAssociate': '取消关联',
|
||||||
'ms.add.attachment.saveAs': '转存',
|
'ms.add.attachment.saveAs': '转存',
|
||||||
|
'ms.add.attachment.repeatFileTip': '文件重复',
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,7 +23,7 @@ export const SELECT = {
|
||||||
options: [],
|
options: [],
|
||||||
props: {
|
props: {
|
||||||
'multiple': false,
|
'multiple': false,
|
||||||
'placeholder': t('formCreate.PleaseSelect'),
|
// 'placeholder': t('formCreate.PleaseSelect'),
|
||||||
'options': [],
|
'options': [],
|
||||||
'modelValue': '',
|
'modelValue': '',
|
||||||
'allow-clear': true,
|
'allow-clear': true,
|
||||||
|
@ -38,7 +38,7 @@ export const MULTIPLE_SELECT = {
|
||||||
options: [],
|
options: [],
|
||||||
props: {
|
props: {
|
||||||
'multiple': true,
|
'multiple': true,
|
||||||
'placeholder': t('formCreate.PleaseSelect'),
|
// 'placeholder': t('formCreate.PleaseSelect'),
|
||||||
'options': [],
|
'options': [],
|
||||||
'modelValue': [],
|
'modelValue': [],
|
||||||
'allow-clear': true,
|
'allow-clear': true,
|
||||||
|
@ -69,7 +69,7 @@ export const MEMBER = {
|
||||||
options: [],
|
options: [],
|
||||||
props: {
|
props: {
|
||||||
'multiple': false,
|
'multiple': false,
|
||||||
'placeholder': t('formCreate.PleaseSelect'),
|
// 'placeholder': t('formCreate.PleaseSelect'),
|
||||||
'modelValue': '',
|
'modelValue': '',
|
||||||
'allow-clear': true,
|
'allow-clear': true,
|
||||||
},
|
},
|
||||||
|
@ -83,7 +83,7 @@ export const MULTIPLE_MEMBER = {
|
||||||
options: [],
|
options: [],
|
||||||
props: {
|
props: {
|
||||||
'multiple': true,
|
'multiple': true,
|
||||||
'placeholder': t('formCreate.PleaseSelect'),
|
// 'placeholder': t('formCreate.PleaseSelect'),
|
||||||
'options': [],
|
'options': [],
|
||||||
'modelValue': [],
|
'modelValue': [],
|
||||||
'allow-clear': true,
|
'allow-clear': true,
|
||||||
|
@ -96,7 +96,7 @@ export const DATE = {
|
||||||
title: '',
|
title: '',
|
||||||
value: '',
|
value: '',
|
||||||
props: {
|
props: {
|
||||||
'placeholder': t('formCreate.PleaseSelect'),
|
// 'placeholder': t('formCreate.PleaseSelect'),
|
||||||
'format': 'YYYY/MM/DD',
|
'format': 'YYYY/MM/DD',
|
||||||
'show-time': false,
|
'show-time': false,
|
||||||
},
|
},
|
||||||
|
@ -108,7 +108,7 @@ export const DATETIME = {
|
||||||
title: '',
|
title: '',
|
||||||
value: '',
|
value: '',
|
||||||
props: {
|
props: {
|
||||||
'placeholder': t('formCreate.PleaseSelect'),
|
// 'placeholder': t('formCreate.PleaseSelect'),
|
||||||
'format': 'YYYY/MM/DD HH:mm:ss',
|
'format': 'YYYY/MM/DD HH:mm:ss',
|
||||||
'show-time': true,
|
'show-time': true,
|
||||||
'show-now-btn': true,
|
'show-now-btn': true,
|
||||||
|
|
|
@ -56,11 +56,11 @@
|
||||||
class="flex items-center gap-[8px] text-[12px] leading-[16px] text-[var(--color-text-4)]"
|
class="flex items-center gap-[8px] text-[12px] leading-[16px] text-[var(--color-text-4)]"
|
||||||
>
|
>
|
||||||
{{
|
{{
|
||||||
`${formatFileSize(item.file.size)} ${item.createUserName || ''} ${t('ms.upload.uploadAt')} ${dayjs(item.createTime).format(
|
`${formatFileSize(item.file.size)} ${item.createUserName || ''} ${getUploadDesc(item)} ${dayjs(
|
||||||
'YYYY-MM-DD HH:mm:ss'
|
item.createTime
|
||||||
)}`
|
).format('YYYY-MM-DD HH:mm:ss')}`
|
||||||
}}
|
}}
|
||||||
<div class="flex items-center">
|
<div v-if="showUploadSuccess(item)" class="flex items-center">
|
||||||
<MsIcon type="icon-icon_succeed_colorful" />
|
<MsIcon type="icon-icon_succeed_colorful" />
|
||||||
{{ t('ms.upload.uploadSuccess') }}
|
{{ t('ms.upload.uploadSuccess') }}
|
||||||
</div>
|
</div>
|
||||||
|
@ -165,12 +165,15 @@
|
||||||
handleReupload?: (item: MsFileItem) => void;
|
handleReupload?: (item: MsFileItem) => void;
|
||||||
showDelete?: boolean; // 是否展示删除按钮
|
showDelete?: boolean; // 是否展示删除按钮
|
||||||
handleView?: (item: MsFileItem) => void; // 是否自定义预览
|
handleView?: (item: MsFileItem) => void; // 是否自定义预览
|
||||||
|
showUploadTypeDesc?: boolean; // 自定义上传类型关联于&上传于
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
mode: 'remote',
|
mode: 'remote',
|
||||||
showTab: true,
|
showTab: true,
|
||||||
showDelete: true,
|
showDelete: true,
|
||||||
showMode: 'fileList',
|
showMode: 'fileList',
|
||||||
|
boolean: false,
|
||||||
|
showUploadTypeDesc: false,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
|
@ -220,6 +223,19 @@
|
||||||
return innerFileList.value.filter((e) => e.status && e.status === UploadStatus.error);
|
return innerFileList.value.filter((e) => e.status && e.status === UploadStatus.error);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function getUploadDesc(item: MsFileItem) {
|
||||||
|
if (props.showUploadTypeDesc) {
|
||||||
|
return item.local ? t('ms.upload.uploadAt') : t('ms.upload.associatedAt');
|
||||||
|
}
|
||||||
|
return t('ms.upload.uploadAt');
|
||||||
|
}
|
||||||
|
function showUploadSuccess(item: MsFileItem) {
|
||||||
|
if (props.showUploadTypeDesc) {
|
||||||
|
return !!item.local;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
const filterFileList = computed(() => {
|
const filterFileList = computed(() => {
|
||||||
switch (fileListTab.value) {
|
switch (fileListTab.value) {
|
||||||
case 'waiting':
|
case 'waiting':
|
||||||
|
|
|
@ -148,11 +148,12 @@
|
||||||
}
|
}
|
||||||
const fileFormatMatch = file.name.match(/\.([a-zA-Z0-9]+)$/);
|
const fileFormatMatch = file.name.match(/\.([a-zA-Z0-9]+)$/);
|
||||||
const fileFormatType = fileFormatMatch ? fileFormatMatch[1] : 'none';
|
const fileFormatType = fileFormatMatch ? fileFormatMatch[1] : 'none';
|
||||||
|
// 校验类型
|
||||||
if (props.accept !== getFileEnum(fileFormatType) && props.accept !== 'none') {
|
if (props.accept !== getFileEnum(fileFormatType) && props.accept !== 'none') {
|
||||||
Message.error(props.fileTypeTip ? props.fileTypeTip : t('ms.upload.fileTypeValidate', { type: props.accept }));
|
Message.error(props.fileTypeTip ? props.fileTypeTip : t('ms.upload.fileTypeValidate', { type: props.accept }));
|
||||||
return Promise.resolve(false);
|
return Promise.resolve(false);
|
||||||
}
|
}
|
||||||
|
// 校验名称重复
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ export default {
|
||||||
'ms.upload.reUpload': 'Reupload',
|
'ms.upload.reUpload': 'Reupload',
|
||||||
'ms.upload.preview': 'Preview',
|
'ms.upload.preview': 'Preview',
|
||||||
'ms.upload.uploadAt': 'Uploaded at',
|
'ms.upload.uploadAt': 'Uploaded at',
|
||||||
|
'ms.upload.associatedAt': 'Associated at',
|
||||||
'ms.upload.fail': 'Failed',
|
'ms.upload.fail': 'Failed',
|
||||||
'ms.upload.delete': 'Delete',
|
'ms.upload.delete': 'Delete',
|
||||||
'ms.upload.uploadSuccess': 'Upload successful',
|
'ms.upload.uploadSuccess': 'Upload successful',
|
||||||
|
|
|
@ -7,6 +7,7 @@ export default {
|
||||||
'ms.upload.reUpload': '重新上传',
|
'ms.upload.reUpload': '重新上传',
|
||||||
'ms.upload.preview': '预览',
|
'ms.upload.preview': '预览',
|
||||||
'ms.upload.uploadAt': '上传于',
|
'ms.upload.uploadAt': '上传于',
|
||||||
|
'ms.upload.associatedAt': '关联于',
|
||||||
'ms.upload.uploadFail': '上传失败',
|
'ms.upload.uploadFail': '上传失败',
|
||||||
'ms.upload.uploadSuccess': '上传成功',
|
'ms.upload.uploadSuccess': '上传成功',
|
||||||
'ms.upload.delete': '删除',
|
'ms.upload.delete': '删除',
|
||||||
|
|
|
@ -43,7 +43,7 @@ export enum ProjectManagementRouteEnum {
|
||||||
PROJECT_MANAGEMENT_TEMPLATE = 'projectManagementTemplate',
|
PROJECT_MANAGEMENT_TEMPLATE = 'projectManagementTemplate',
|
||||||
PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT = 'projectManagementTemplateManagement',
|
PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT = 'projectManagementTemplateManagement',
|
||||||
PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT_CASE_DETAIL = 'projectManagementTemplateManagementCaseDetail',
|
PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT_CASE_DETAIL = 'projectManagementTemplateManagementCaseDetail',
|
||||||
PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT_API_DETAIL = 'projectManagementTemplateManagementCaseDetail',
|
PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT_API_DETAIL = 'projectManagementTemplateManagementApiDetail',
|
||||||
PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT_BUG_DETAIL = 'projectManagementTemplateManagementBugDetail',
|
PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT_BUG_DETAIL = 'projectManagementTemplateManagementBugDetail',
|
||||||
PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT_WORKFLOW = 'projectManagementTemplateManagementWorkFlow',
|
PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT_WORKFLOW = 'projectManagementTemplateManagementWorkFlow',
|
||||||
PROJECT_MANAGEMENT_TEMPLATE_FIELD_SETTING = 'projectManagementTemplateFiledSetting',
|
PROJECT_MANAGEMENT_TEMPLATE_FIELD_SETTING = 'projectManagementTemplateFiledSetting',
|
||||||
|
|
|
@ -122,7 +122,7 @@ const ProjectManagement: AppRouteRecordRaw = {
|
||||||
},
|
},
|
||||||
// 項目管理模板
|
// 項目管理模板
|
||||||
{
|
{
|
||||||
path: 'templateManager',
|
path: 'template',
|
||||||
name: ProjectManagementRouteEnum.PROJECT_MANAGEMENT_TEMPLATE,
|
name: ProjectManagementRouteEnum.PROJECT_MANAGEMENT_TEMPLATE,
|
||||||
component: () => import('@/views/project-management/template/index.vue'),
|
component: () => import('@/views/project-management/template/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
@ -133,7 +133,7 @@ const ProjectManagement: AppRouteRecordRaw = {
|
||||||
},
|
},
|
||||||
// 模板列表-模板字段设置
|
// 模板列表-模板字段设置
|
||||||
{
|
{
|
||||||
path: 'filedSetting',
|
path: 'templateFiledSetting',
|
||||||
name: ProjectManagementRouteEnum.PROJECT_MANAGEMENT_TEMPLATE_FIELD_SETTING,
|
name: ProjectManagementRouteEnum.PROJECT_MANAGEMENT_TEMPLATE_FIELD_SETTING,
|
||||||
component: () => import('@/views/project-management/template/components/projectFieldSetting.vue'),
|
component: () => import('@/views/project-management/template/components/projectFieldSetting.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
@ -175,9 +175,9 @@ const ProjectManagement: AppRouteRecordRaw = {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// 项目-模板-创建模板和模板详情
|
// 项目-模板-用例模板
|
||||||
{
|
{
|
||||||
path: 'templateCaseDetail/:mode?',
|
path: 'templateManagementCaseDetail/:mode?',
|
||||||
name: ProjectManagementRouteEnum.PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT_CASE_DETAIL,
|
name: ProjectManagementRouteEnum.PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT_CASE_DETAIL,
|
||||||
component: () => import('@/views/project-management/template/components/detail.vue'),
|
component: () => import('@/views/project-management/template/components/detail.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
@ -205,7 +205,7 @@ const ProjectManagement: AppRouteRecordRaw = {
|
||||||
},
|
},
|
||||||
// 项目-模板-接口模板
|
// 项目-模板-接口模板
|
||||||
{
|
{
|
||||||
path: 'templateApiDetail/:mode?',
|
path: 'templateManagementApiDetail/:mode?',
|
||||||
name: ProjectManagementRouteEnum.PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT_API_DETAIL,
|
name: ProjectManagementRouteEnum.PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT_API_DETAIL,
|
||||||
component: () => import('@/views/project-management/template/components/detail.vue'),
|
component: () => import('@/views/project-management/template/components/detail.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
@ -233,7 +233,7 @@ const ProjectManagement: AppRouteRecordRaw = {
|
||||||
},
|
},
|
||||||
// 项目-模板-缺陷模板
|
// 项目-模板-缺陷模板
|
||||||
{
|
{
|
||||||
path: 'templateBugDetail/:mode?',
|
path: 'templateManagementBugDetail/:mode?',
|
||||||
name: ProjectManagementRouteEnum.PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT_BUG_DETAIL,
|
name: ProjectManagementRouteEnum.PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT_BUG_DETAIL,
|
||||||
component: () => import('@/views/project-management/template/components/detail.vue'),
|
component: () => import('@/views/project-management/template/components/detail.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
|
@ -29,6 +29,7 @@ const Setting: AppRouteRecordRaw = {
|
||||||
'SYSTEM_SERVICE_INTEGRATION:READ',
|
'SYSTEM_SERVICE_INTEGRATION:READ',
|
||||||
'ORGANIZATION_TEMPLATE:READ',
|
'ORGANIZATION_TEMPLATE:READ',
|
||||||
'ORGANIZATION_LOG:READ',
|
'ORGANIZATION_LOG:READ',
|
||||||
|
'SYSTEM_TASK_CENTER:READ',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
|
@ -50,6 +51,7 @@ const Setting: AppRouteRecordRaw = {
|
||||||
'SYSTEM_AUTH:READ',
|
'SYSTEM_AUTH:READ',
|
||||||
'SYSTEM_PLUGIN:READ',
|
'SYSTEM_PLUGIN:READ',
|
||||||
'SYSTEM_LOG:READ',
|
'SYSTEM_LOG:READ',
|
||||||
|
'SYSTEM_TASK_CENTER:READ',
|
||||||
],
|
],
|
||||||
hideChildrenInMenu: true,
|
hideChildrenInMenu: true,
|
||||||
},
|
},
|
||||||
|
@ -157,7 +159,7 @@ const Setting: AppRouteRecordRaw = {
|
||||||
component: () => import('@/views/setting/system/taskCenter/index.vue'),
|
component: () => import('@/views/setting/system/taskCenter/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
locale: 'menu.projectManagement.taskCenter',
|
locale: 'menu.projectManagement.taskCenter',
|
||||||
roles: ['*'],
|
roles: ['SYSTEM_TASK_CENTER:READ'],
|
||||||
isTopMenu: true,
|
isTopMenu: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -187,6 +189,8 @@ const Setting: AppRouteRecordRaw = {
|
||||||
'SYSTEM_SERVICE_INTEGRATION:READ',
|
'SYSTEM_SERVICE_INTEGRATION:READ',
|
||||||
'ORGANIZATION_TEMPLATE:READ',
|
'ORGANIZATION_TEMPLATE:READ',
|
||||||
'ORGANIZATION_LOG:READ',
|
'ORGANIZATION_LOG:READ',
|
||||||
|
'ORGANIZATION_TASK_CENTER::READ',
|
||||||
|
'ORGANIZATION_TASK_CENTER::READ',
|
||||||
],
|
],
|
||||||
hideChildrenInMenu: true,
|
hideChildrenInMenu: true,
|
||||||
},
|
},
|
||||||
|
@ -305,7 +309,7 @@ const Setting: AppRouteRecordRaw = {
|
||||||
query: ['type'],
|
query: ['type'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: SettingRouteEnum.SETTING_ORGANIZATION_TEMPLATE_MANAGEMENT,
|
name: SettingRouteEnum.SETTING_ORGANIZATION_TEMPLATE_MANAGEMENT_CASE_DETAIL,
|
||||||
locale: 'system.orgTemplate.createCaseTemplate',
|
locale: 'system.orgTemplate.createCaseTemplate',
|
||||||
editTag: 'id',
|
editTag: 'id',
|
||||||
editLocale: 'system.orgTemplate.updateCaseTemplate',
|
editLocale: 'system.orgTemplate.updateCaseTemplate',
|
||||||
|
@ -408,7 +412,7 @@ const Setting: AppRouteRecordRaw = {
|
||||||
component: () => import('@/views/setting/organization/taskCenter/index.vue'),
|
component: () => import('@/views/setting/organization/taskCenter/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
locale: 'menu.projectManagement.taskCenter',
|
locale: 'menu.projectManagement.taskCenter',
|
||||||
roles: ['*'],
|
roles: ['ORGANIZATION_TASK_CENTER::READ'],
|
||||||
isTopMenu: true,
|
isTopMenu: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
:title="title"
|
:title="title"
|
||||||
:is-edit="isEdit"
|
:is-edit="isEdit"
|
||||||
has-breadcrumb
|
has-breadcrumb
|
||||||
|
:hide-continue="!isEdit"
|
||||||
@save="saveHandler"
|
@save="saveHandler"
|
||||||
@save-and-continue="saveHandler(true)"
|
@save-and-continue="saveHandler(true)"
|
||||||
>
|
>
|
||||||
|
@ -15,7 +16,7 @@
|
||||||
<template #footerRight>
|
<template #footerRight>
|
||||||
<div class="flex justify-end gap-[16px]">
|
<div class="flex justify-end gap-[16px]">
|
||||||
<a-button type="secondary" @click="cancelHandler">{{ t('mscard.defaultCancelText') }}</a-button>
|
<a-button type="secondary" @click="cancelHandler">{{ t('mscard.defaultCancelText') }}</a-button>
|
||||||
<a-button v-if="!isFormReviewCase" type="secondary" @click="saveHandler(true)">
|
<a-button v-if="!isEdit" type="secondary" @click="saveHandler(true)">
|
||||||
{{ t('mscard.defaultSaveAndContinueText') }}
|
{{ t('mscard.defaultSaveAndContinueText') }}
|
||||||
</a-button>
|
</a-button>
|
||||||
<a-button v-if="!isFormReviewCase" type="primary" @click="saveHandler(false)">
|
<a-button v-if="!isFormReviewCase" type="primary" @click="saveHandler(false)">
|
||||||
|
|
|
@ -632,24 +632,29 @@
|
||||||
{
|
{
|
||||||
label: 'common.edit',
|
label: 'common.edit',
|
||||||
eventTag: 'batchEdit',
|
eventTag: 'batchEdit',
|
||||||
|
permission: ['FUNCTIONAL_CASE:READ+UPDATE'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'caseManagement.featureCase.moveTo',
|
label: 'caseManagement.featureCase.moveTo',
|
||||||
eventTag: 'batchMoveTo',
|
eventTag: 'batchMoveTo',
|
||||||
|
permission: ['FUNCTIONAL_CASE:READ+UPDATE'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'caseManagement.featureCase.copyTo',
|
label: 'caseManagement.featureCase.copyTo',
|
||||||
eventTag: 'batchCopyTo',
|
eventTag: 'batchCopyTo',
|
||||||
|
permission: ['FUNCTIONAL_CASE:READ+ADD'],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
moreAction: [
|
moreAction: [
|
||||||
{
|
{
|
||||||
label: 'caseManagement.featureCase.addDemand',
|
label: 'caseManagement.featureCase.addDemand',
|
||||||
eventTag: 'addDemand',
|
eventTag: 'addDemand',
|
||||||
|
permission: ['FUNCTIONAL_CASE:READ+UPDATE'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'caseManagement.featureCase.associatedDemand',
|
label: 'caseManagement.featureCase.associatedDemand',
|
||||||
eventTag: 'associatedDemand',
|
eventTag: 'associatedDemand',
|
||||||
|
permission: ['FUNCTIONAL_CASE:READ+UPDATE'],
|
||||||
},
|
},
|
||||||
// {
|
// {
|
||||||
// label: 'caseManagement.featureCase.generatingDependencies',
|
// label: 'caseManagement.featureCase.generatingDependencies',
|
||||||
|
|
|
@ -80,7 +80,7 @@
|
||||||
</a-form>
|
</a-form>
|
||||||
<!-- 文件列表开始 -->
|
<!-- 文件列表开始 -->
|
||||||
<div class="w-[90%]">
|
<div class="w-[90%]">
|
||||||
<MsFileList ref="fileListRef" v-model:file-list="fileList" mode="static">
|
<MsFileList ref="fileListRef" v-model:file-list="fileList" mode="static" :show-upload-type-desc="true">
|
||||||
<template #actions="{ item }">
|
<template #actions="{ item }">
|
||||||
<!-- 本地文件 -->
|
<!-- 本地文件 -->
|
||||||
<div v-if="item.local || item.status === 'init'" class="flex flex-nowrap">
|
<div v-if="item.local || item.status === 'init'" class="flex flex-nowrap">
|
||||||
|
@ -563,8 +563,8 @@
|
||||||
const fileIds = (detailResult.attachments || []).map((item: any) => item.id);
|
const fileIds = (detailResult.attachments || []).map((item: any) => item.id);
|
||||||
if (fileIds.length) {
|
if (fileIds.length) {
|
||||||
checkUpdateFileIds.value = await checkFileIsUpdateRequest(fileIds);
|
checkUpdateFileIds.value = await checkFileIsUpdateRequest(fileIds);
|
||||||
|
getDetailData(detailResult);
|
||||||
}
|
}
|
||||||
getDetailData(detailResult);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
@ -650,6 +650,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleChange(_fileList: MsFileItem[]) {
|
function handleChange(_fileList: MsFileItem[]) {
|
||||||
|
// 校验本地文件重复
|
||||||
fileList.value = _fileList.map((e) => {
|
fileList.value = _fileList.map((e) => {
|
||||||
return {
|
return {
|
||||||
...e,
|
...e,
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
:show-file-list="false"
|
:show-file-list="false"
|
||||||
:auto-upload="false"
|
:auto-upload="false"
|
||||||
:disabled="confirmLoading"
|
:disabled="confirmLoading"
|
||||||
|
:file-type-tip="fileTypeTip"
|
||||||
></MsUpload>
|
></MsUpload>
|
||||||
<!-- 版本暂时不上 -->
|
<!-- 版本暂时不上 -->
|
||||||
<!-- <a-form-item field="post" :label="t('caseManagement.featureCase.selectVersion')">
|
<!-- <a-form-item field="post" :label="t('caseManagement.featureCase.selectVersion')">
|
||||||
|
@ -131,6 +132,12 @@
|
||||||
// },
|
// },
|
||||||
// ]);
|
// ]);
|
||||||
|
|
||||||
|
const fileTypeTip = computed(() => {
|
||||||
|
return props.validateType === 'Excel'
|
||||||
|
? t('caseManagement.featureCase.excelImportTip')
|
||||||
|
: t('caseManagement.featureCase.xmindImportTip');
|
||||||
|
});
|
||||||
|
|
||||||
const isRecover = ref<boolean>(false);
|
const isRecover = ref<boolean>(false);
|
||||||
|
|
||||||
const isDisabled = ref<boolean>(false);
|
const isDisabled = ref<boolean>(false);
|
||||||
|
|
|
@ -218,6 +218,9 @@
|
||||||
<template #createUserName="{ record }">
|
<template #createUserName="{ record }">
|
||||||
<span type="text" class="px-0">{{ record.createUserName || '-' }}</span>
|
<span type="text" class="px-0">{{ record.createUserName || '-' }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
<template #deleteTime="{ record }">
|
||||||
|
{{ dayjs(record.deleteTime).format('YYYY-MM-DD HH:mm:ss') || '-' }}
|
||||||
|
</template>
|
||||||
<!-- 回收站自定义字段 -->
|
<!-- 回收站自定义字段 -->
|
||||||
<template v-for="item in customFieldsColumns" :key="item.slotName" #[item.slotName]="{ record }">
|
<template v-for="item in customFieldsColumns" :key="item.slotName" #[item.slotName]="{ record }">
|
||||||
<a-tooltip
|
<a-tooltip
|
||||||
|
@ -253,6 +256,7 @@
|
||||||
*/
|
*/
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import { Message } from '@arco-design/web-vue';
|
import { Message } from '@arco-design/web-vue';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
import { CustomTypeMaps, MsAdvanceFilter } from '@/components/pure/ms-advance-filter';
|
import { CustomTypeMaps, MsAdvanceFilter } from '@/components/pure/ms-advance-filter';
|
||||||
import { FilterFormItem, FilterResult, FilterType } from '@/components/pure/ms-advance-filter/type';
|
import { FilterFormItem, FilterResult, FilterType } from '@/components/pure/ms-advance-filter/type';
|
||||||
|
@ -285,6 +289,7 @@
|
||||||
import { useAppStore, useTableStore } from '@/store';
|
import { useAppStore, useTableStore } from '@/store';
|
||||||
import useFeatureCaseStore from '@/store/modules/case/featureCase';
|
import useFeatureCaseStore from '@/store/modules/case/featureCase';
|
||||||
import { characterLimit, findNodeByKey, findNodePathByKey, mapTree } from '@/utils';
|
import { characterLimit, findNodeByKey, findNodePathByKey, mapTree } from '@/utils';
|
||||||
|
import { hasAnyPermission } from '@/utils/permission';
|
||||||
|
|
||||||
import type { BatchMoveOrCopyType, CaseManagementTable, CustomAttributes } from '@/models/caseManagement/featureCase';
|
import type { BatchMoveOrCopyType, CaseManagementTable, CustomAttributes } from '@/models/caseManagement/featureCase';
|
||||||
import type { ModuleTreeNode, TableQueryParams } from '@/models/common';
|
import type { ModuleTreeNode, TableQueryParams } from '@/models/common';
|
||||||
|
@ -326,6 +331,9 @@
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const hasOperationPermission = computed(() => hasAnyPermission(['FUNCTIONAL_CASE:READ+DELETE']));
|
||||||
|
|
||||||
const columns: MsTableColumn = [
|
const columns: MsTableColumn = [
|
||||||
{
|
{
|
||||||
'title': 'caseManagement.featureCase.tableColumnID',
|
'title': 'caseManagement.featureCase.tableColumnID',
|
||||||
|
@ -473,13 +481,13 @@
|
||||||
showDrag: true,
|
showDrag: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'caseManagement.featureCase.tableColumnActions',
|
title: hasOperationPermission.value ? 'caseManagement.featureCase.tableColumnActions' : '',
|
||||||
slotName: 'operation',
|
slotName: 'operation',
|
||||||
dataIndex: 'operation',
|
dataIndex: 'operation',
|
||||||
fixed: 'right',
|
fixed: 'right',
|
||||||
width: 260,
|
|
||||||
showInTable: true,
|
showInTable: true,
|
||||||
showDrag: false,
|
showDrag: false,
|
||||||
|
width: hasOperationPermission.value ? 260 : 50,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -488,11 +496,13 @@
|
||||||
{
|
{
|
||||||
label: 'caseManagement.featureCase.batchRecover',
|
label: 'caseManagement.featureCase.batchRecover',
|
||||||
eventTag: 'batchRecover',
|
eventTag: 'batchRecover',
|
||||||
|
permission: ['FUNCTIONAL_CASE:READ+DELETE'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'caseManagement.featureCase.batchCleanOut',
|
label: 'caseManagement.featureCase.batchCleanOut',
|
||||||
eventTag: 'batchCleanOut',
|
eventTag: 'batchCleanOut',
|
||||||
danger: true,
|
danger: true,
|
||||||
|
permission: ['FUNCTIONAL_CASE:READ+DELETE'],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,7 +3,13 @@
|
||||||
v-model:visible="transferVisible"
|
v-model:visible="transferVisible"
|
||||||
title-align="start"
|
title-align="start"
|
||||||
unmount-on-close
|
unmount-on-close
|
||||||
class="ms-modal-upload ms-modal-small"
|
:mask-closable="false"
|
||||||
|
modal-class="shadowModal"
|
||||||
|
:mask="false"
|
||||||
|
:modal-style="{
|
||||||
|
'box-shadow': '0px 4px 10px -1px rgba(100, 100, 102, 0.15)',
|
||||||
|
}"
|
||||||
|
class="ms-modal-form ms-modal-small"
|
||||||
>
|
>
|
||||||
<template #title> {{ t('caseManagement.featureCase.selectTransferDirectory') }} </template>
|
<template #title> {{ t('caseManagement.featureCase.selectTransferDirectory') }} </template>
|
||||||
<a-tree-select
|
<a-tree-select
|
||||||
|
@ -104,4 +110,10 @@
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped lang="less">
|
||||||
|
// :deep(.arco-modal.shadowModal) {
|
||||||
|
// border-radius: 6px;
|
||||||
|
// border: 1px solid red;
|
||||||
|
// box-shadow: 0 4px 10px -1px rgba(100 100 102/ 15%) !important;
|
||||||
|
// }
|
||||||
|
</style>
|
||||||
|
|
|
@ -101,6 +101,7 @@ export function convertToFile(fileInfo: AssociatedList): MsFileItem {
|
||||||
});
|
});
|
||||||
Object.defineProperty(file, 'size', { value: fileInfo.size });
|
Object.defineProperty(file, 'size', { value: fileInfo.size });
|
||||||
const { id, createUserName, createTime, local, isUpdateFlag, associateId } = fileInfo;
|
const { id, createUserName, createTime, local, isUpdateFlag, associateId } = fileInfo;
|
||||||
|
debugger;
|
||||||
return {
|
return {
|
||||||
enable: fileInfo.enable || false,
|
enable: fileInfo.enable || false,
|
||||||
file,
|
file,
|
||||||
|
|
|
@ -116,7 +116,8 @@ export default {
|
||||||
'caseManagement.featureCase.recoveredSuccessfully': 'Recovered successfully',
|
'caseManagement.featureCase.recoveredSuccessfully': 'Recovered successfully',
|
||||||
'caseManagement.featureCase.cleanOutDeleteTip':
|
'caseManagement.featureCase.cleanOutDeleteTip':
|
||||||
'After deletion, the data will not be recovered, please operate with caution!',
|
'After deletion, the data will not be recovered, please operate with caution!',
|
||||||
'caseManagement.featureCase.cleanOutDeleteOnRecycleTip': 'After deletion, the case will not be recovered, please operate with caution!',
|
'caseManagement.featureCase.cleanOutDeleteOnRecycleTip':
|
||||||
|
'After deletion, the case will not be recovered, please operate with caution!',
|
||||||
'caseManagement.featureCase.pleaseEnterInputTags': 'Please enter content Enter add label',
|
'caseManagement.featureCase.pleaseEnterInputTags': 'Please enter content Enter add label',
|
||||||
'caseManagement.featureCase.copy': 'Copy',
|
'caseManagement.featureCase.copy': 'Copy',
|
||||||
'caseManagement.featureCase.copyCase': 'Copy case',
|
'caseManagement.featureCase.copyCase': 'Copy case',
|
||||||
|
@ -262,4 +263,6 @@ export default {
|
||||||
'caseManagement.featureCase.jira': 'JIRA',
|
'caseManagement.featureCase.jira': 'JIRA',
|
||||||
'caseManagement.featureCase.searchPlaceholder': 'Search by ID, name, or tag',
|
'caseManagement.featureCase.searchPlaceholder': 'Search by ID, name, or tag',
|
||||||
'caseManagement.featureCase.ModuleOwned': 'Module owned',
|
'caseManagement.featureCase.ModuleOwned': 'Module owned',
|
||||||
|
'caseManagement.featureCase.excelImportTip': 'Only xls/xlsx files are supported',
|
||||||
|
'caseManagement.featureCase.xmindImportTip': 'Only xmind files are supported',
|
||||||
};
|
};
|
||||||
|
|
|
@ -258,4 +258,6 @@ export default {
|
||||||
'caseManagement.featureCase.jira': 'JIRA',
|
'caseManagement.featureCase.jira': 'JIRA',
|
||||||
'caseManagement.featureCase.searchPlaceholder': '通过ID、名称或标签搜索',
|
'caseManagement.featureCase.searchPlaceholder': '通过ID、名称或标签搜索',
|
||||||
'caseManagement.featureCase.ModuleOwned': '所属模块',
|
'caseManagement.featureCase.ModuleOwned': '所属模块',
|
||||||
|
'caseManagement.featureCase.excelImportTip': '仅支持xls/xlsx格式的文件',
|
||||||
|
'caseManagement.featureCase.xmindImportTip': '仅支持xmind格式的文件',
|
||||||
};
|
};
|
||||||
|
|
|
@ -77,7 +77,7 @@
|
||||||
ref="projectMemberRef"
|
ref="projectMemberRef"
|
||||||
v-model:visible="addMemberVisible"
|
v-model:visible="addMemberVisible"
|
||||||
:user-group-options="userGroupOptions"
|
:user-group-options="userGroupOptions"
|
||||||
@success="loadList()"
|
@success="initData()"
|
||||||
/>
|
/>
|
||||||
<MsBatchModal
|
<MsBatchModal
|
||||||
ref="batchModalRef"
|
ref="batchModalRef"
|
||||||
|
@ -115,7 +115,7 @@
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useModal from '@/hooks/useModal';
|
import useModal from '@/hooks/useModal';
|
||||||
import { useAppStore, useTableStore } from '@/store';
|
import { useAppStore, useTableStore } from '@/store';
|
||||||
import { characterLimit, formatPhoneNumber } from '@/utils';
|
import { characterLimit, formatPhoneNumber, sleep } from '@/utils';
|
||||||
import { hasAnyPermission } from '@/utils/permission';
|
import { hasAnyPermission } from '@/utils/permission';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
|
@ -206,7 +206,6 @@
|
||||||
showSetting: true,
|
showSetting: true,
|
||||||
heightUsed: 288,
|
heightUsed: 288,
|
||||||
showJumpMethod: true,
|
showJumpMethod: true,
|
||||||
columns,
|
|
||||||
scroll: {
|
scroll: {
|
||||||
x: 1200,
|
x: 1200,
|
||||||
},
|
},
|
||||||
|
@ -230,7 +229,7 @@
|
||||||
const roleIds = ref<string>('');
|
const roleIds = ref<string>('');
|
||||||
const initData = async () => {
|
const initData = async () => {
|
||||||
setLoadListParams({ ...searchParams.value });
|
setLoadListParams({ ...searchParams.value });
|
||||||
await loadList();
|
loadList();
|
||||||
};
|
};
|
||||||
|
|
||||||
const searchHandler = () => {
|
const searchHandler = () => {
|
||||||
|
@ -394,12 +393,12 @@
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
const memberTableRef = ref();
|
const memberTableRef = ref();
|
||||||
|
initOptions();
|
||||||
|
|
||||||
onMounted(() => {
|
onBeforeMount(() => {
|
||||||
initData();
|
initData();
|
||||||
initOptions();
|
|
||||||
memberTableRef.value.initColumn(columns);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
tableStore.initColumn(TableKeyEnum.PROJECT_MEMBER, columns, 'drawer');
|
tableStore.initColumn(TableKeyEnum.PROJECT_MEMBER, columns, 'drawer');
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,10 @@
|
||||||
</template>
|
</template>
|
||||||
<template #operation="{ record }">
|
<template #operation="{ record }">
|
||||||
<MsButton
|
<MsButton
|
||||||
v-if="['PENDING', 'RUNNING', 'RERUNNING'].includes(record.status)"
|
v-if="
|
||||||
|
['PENDING', 'RUNNING', 'RERUNNING'].includes(record.status) &&
|
||||||
|
hasAnyPermission(permissionsMap[props.group].stop)
|
||||||
|
"
|
||||||
class="!mr-0"
|
class="!mr-0"
|
||||||
@click="stop(record)"
|
@click="stop(record)"
|
||||||
>{{ t('project.taskCenter.stop') }}</MsButton
|
>{{ t('project.taskCenter.stop') }}</MsButton
|
||||||
|
@ -94,6 +97,7 @@
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useModal from '@/hooks/useModal';
|
import useModal from '@/hooks/useModal';
|
||||||
import { characterLimit } from '@/utils';
|
import { characterLimit } from '@/utils';
|
||||||
|
import { hasAnyPermission } from '@/utils/permission';
|
||||||
|
|
||||||
import { BatchApiParams } from '@/models/common';
|
import { BatchApiParams } from '@/models/common';
|
||||||
import { ExecutionMethodsLabel, TaskCenterEnum } from '@/enums/taskCenter';
|
import { ExecutionMethodsLabel, TaskCenterEnum } from '@/enums/taskCenter';
|
||||||
|
@ -121,6 +125,18 @@
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const permissionsMap = {
|
||||||
|
organization: {
|
||||||
|
stop: ['ORGANIZATION_TASK_CENTER::READ+STOP'],
|
||||||
|
},
|
||||||
|
system: {
|
||||||
|
stop: ['ORGANIZATION_TASK_CENTER::READ+STOP'],
|
||||||
|
},
|
||||||
|
project: {
|
||||||
|
stop: ['PROJECT_API_REPORT:READ'],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
const loadRealMap = ref({
|
const loadRealMap = ref({
|
||||||
system: {
|
system: {
|
||||||
list: getRealSysApiCaseList,
|
list: getRealSysApiCaseList,
|
||||||
|
@ -203,7 +219,7 @@
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector, setProps } = useTable(
|
const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector } = useTable(
|
||||||
loadRealMap.value[props.group].list,
|
loadRealMap.value[props.group].list,
|
||||||
{
|
{
|
||||||
columns,
|
columns,
|
||||||
|
|
|
@ -526,7 +526,12 @@
|
||||||
required: item.required,
|
required: item.required,
|
||||||
},
|
},
|
||||||
value: item.defaultValue,
|
value: item.defaultValue,
|
||||||
props: { ...currentFormRules.props, options: selectOptions, modelValue: item.defaultValue },
|
props: {
|
||||||
|
...currentFormRules.props,
|
||||||
|
options: selectOptions,
|
||||||
|
modelValue: item.defaultValue,
|
||||||
|
placeholder: t('system.orgTemplate.defaultValue'),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
fApi: null,
|
fApi: null,
|
||||||
|
@ -583,6 +588,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
selectData.value = [];
|
||||||
|
totalTemplateField.value = [];
|
||||||
await getClassifyField();
|
await getClassifyField();
|
||||||
getFieldOptionList();
|
getFieldOptionList();
|
||||||
if (isEdit.value) {
|
if (isEdit.value) {
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
allow-clear
|
allow-clear
|
||||||
/>
|
/>
|
||||||
<span class="absolute right-0 top-1 flex items-center">
|
<span class="absolute right-0 top-1 flex items-center">
|
||||||
<span class="text-[rgb(var(--primary-5))]b float-left cursor-pointer" @click="openGithub">{{
|
<span class="float-left cursor-pointer text-[rgb(var(--primary-5))]" @click="openGithub">{{
|
||||||
t('system.plugin.getPlugin')
|
t('system.plugin.getPlugin')
|
||||||
}}</span>
|
}}</span>
|
||||||
<a-tooltip position="bottom">
|
<a-tooltip position="bottom">
|
||||||
|
|
Loading…
Reference in New Issue