fix: 全局用例&模板&部分权限补充

This commit is contained in:
xinxin.wu 2024-03-01 19:11:29 +08:00 committed by Craftsman
parent ceafebe073
commit c810f8b8d3
24 changed files with 158 additions and 55 deletions

View File

@ -157,7 +157,7 @@
<script setup lang="ts">
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 MsIcon from '@/components/pure/ms-icon-font/index.vue';
@ -241,22 +241,36 @@
});
function handleChange(_fileList: MsFileItem[], fileItem: MsFileItem) {
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,
}));
//
const isRepeat = _fileList.filter((item) => item.name === fileItem.name).length > 1;
debugger;
if (isRepeat) {
Message.error(t('ms.add.attachment.repeatFileTip'));
innerFileList.value = _fileList.reduce((prev: MsFileItem[], current: MsFileItem) => {
const isExist = prev.find((item: any) => item.name === current.name);
if (!isExist) {
prev.push(current);
}
return prev;
}, []);
} 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() {

View File

@ -7,4 +7,5 @@ export default {
'ms.add.attachment.remove': 'Remove',
'ms.add.attachment.cancelAssociate': 'Disassociate',
'ms.add.attachment.saveAs': 'Save',
'ms.add.attachment.repeatFileTip': 'File already exists.',
};

View File

@ -7,4 +7,5 @@ export default {
'ms.add.attachment.remove': '移除',
'ms.add.attachment.cancelAssociate': '取消关联',
'ms.add.attachment.saveAs': '转存',
'ms.add.attachment.repeatFileTip': '文件重复',
};

View File

@ -23,7 +23,7 @@ export const SELECT = {
options: [],
props: {
'multiple': false,
'placeholder': t('formCreate.PleaseSelect'),
// 'placeholder': t('formCreate.PleaseSelect'),
'options': [],
'modelValue': '',
'allow-clear': true,
@ -38,7 +38,7 @@ export const MULTIPLE_SELECT = {
options: [],
props: {
'multiple': true,
'placeholder': t('formCreate.PleaseSelect'),
// 'placeholder': t('formCreate.PleaseSelect'),
'options': [],
'modelValue': [],
'allow-clear': true,
@ -69,7 +69,7 @@ export const MEMBER = {
options: [],
props: {
'multiple': false,
'placeholder': t('formCreate.PleaseSelect'),
// 'placeholder': t('formCreate.PleaseSelect'),
'modelValue': '',
'allow-clear': true,
},
@ -83,7 +83,7 @@ export const MULTIPLE_MEMBER = {
options: [],
props: {
'multiple': true,
'placeholder': t('formCreate.PleaseSelect'),
// 'placeholder': t('formCreate.PleaseSelect'),
'options': [],
'modelValue': [],
'allow-clear': true,
@ -96,7 +96,7 @@ export const DATE = {
title: '',
value: '',
props: {
'placeholder': t('formCreate.PleaseSelect'),
// 'placeholder': t('formCreate.PleaseSelect'),
'format': 'YYYY/MM/DD',
'show-time': false,
},
@ -108,7 +108,7 @@ export const DATETIME = {
title: '',
value: '',
props: {
'placeholder': t('formCreate.PleaseSelect'),
// 'placeholder': t('formCreate.PleaseSelect'),
'format': 'YYYY/MM/DD HH:mm:ss',
'show-time': true,
'show-now-btn': true,

View File

@ -56,11 +56,11 @@
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(
'YYYY-MM-DD HH:mm:ss'
)}`
`${formatFileSize(item.file.size)} ${item.createUserName || ''} ${getUploadDesc(item)} ${dayjs(
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" />
{{ t('ms.upload.uploadSuccess') }}
</div>
@ -165,12 +165,15 @@
handleReupload?: (item: MsFileItem) => void;
showDelete?: boolean; //
handleView?: (item: MsFileItem) => void; //
showUploadTypeDesc?: boolean; // &
}>(),
{
mode: 'remote',
showTab: true,
showDelete: true,
showMode: 'fileList',
boolean: false,
showUploadTypeDesc: false,
}
);
const emit = defineEmits<{
@ -220,6 +223,19 @@
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(() => {
switch (fileListTab.value) {
case 'waiting':

View File

@ -148,11 +148,12 @@
}
const fileFormatMatch = file.name.match(/\.([a-zA-Z0-9]+)$/);
const fileFormatType = fileFormatMatch ? fileFormatMatch[1] : 'none';
//
if (props.accept !== getFileEnum(fileFormatType) && props.accept !== 'none') {
Message.error(props.fileTypeTip ? props.fileTypeTip : t('ms.upload.fileTypeValidate', { type: props.accept }));
return Promise.resolve(false);
}
//
return Promise.resolve(true);
}

View File

@ -7,6 +7,7 @@ export default {
'ms.upload.reUpload': 'Reupload',
'ms.upload.preview': 'Preview',
'ms.upload.uploadAt': 'Uploaded at',
'ms.upload.associatedAt': 'Associated at',
'ms.upload.fail': 'Failed',
'ms.upload.delete': 'Delete',
'ms.upload.uploadSuccess': 'Upload successful',

View File

@ -7,6 +7,7 @@ export default {
'ms.upload.reUpload': '重新上传',
'ms.upload.preview': '预览',
'ms.upload.uploadAt': '上传于',
'ms.upload.associatedAt': '关联于',
'ms.upload.uploadFail': '上传失败',
'ms.upload.uploadSuccess': '上传成功',
'ms.upload.delete': '删除',

View File

@ -43,7 +43,7 @@ export enum ProjectManagementRouteEnum {
PROJECT_MANAGEMENT_TEMPLATE = 'projectManagementTemplate',
PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT = 'projectManagementTemplateManagement',
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_WORKFLOW = 'projectManagementTemplateManagementWorkFlow',
PROJECT_MANAGEMENT_TEMPLATE_FIELD_SETTING = 'projectManagementTemplateFiledSetting',

View File

@ -122,7 +122,7 @@ const ProjectManagement: AppRouteRecordRaw = {
},
// 項目管理模板
{
path: 'templateManager',
path: 'template',
name: ProjectManagementRouteEnum.PROJECT_MANAGEMENT_TEMPLATE,
component: () => import('@/views/project-management/template/index.vue'),
meta: {
@ -133,7 +133,7 @@ const ProjectManagement: AppRouteRecordRaw = {
},
// 模板列表-模板字段设置
{
path: 'filedSetting',
path: 'templateFiledSetting',
name: ProjectManagementRouteEnum.PROJECT_MANAGEMENT_TEMPLATE_FIELD_SETTING,
component: () => import('@/views/project-management/template/components/projectFieldSetting.vue'),
meta: {
@ -175,9 +175,9 @@ const ProjectManagement: AppRouteRecordRaw = {
],
},
},
// 项目-模板-创建模板和模板详情
// 项目-模板-用例模板
{
path: 'templateCaseDetail/:mode?',
path: 'templateManagementCaseDetail/:mode?',
name: ProjectManagementRouteEnum.PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT_CASE_DETAIL,
component: () => import('@/views/project-management/template/components/detail.vue'),
meta: {
@ -205,7 +205,7 @@ const ProjectManagement: AppRouteRecordRaw = {
},
// 项目-模板-接口模板
{
path: 'templateApiDetail/:mode?',
path: 'templateManagementApiDetail/:mode?',
name: ProjectManagementRouteEnum.PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT_API_DETAIL,
component: () => import('@/views/project-management/template/components/detail.vue'),
meta: {
@ -233,7 +233,7 @@ const ProjectManagement: AppRouteRecordRaw = {
},
// 项目-模板-缺陷模板
{
path: 'templateBugDetail/:mode?',
path: 'templateManagementBugDetail/:mode?',
name: ProjectManagementRouteEnum.PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT_BUG_DETAIL,
component: () => import('@/views/project-management/template/components/detail.vue'),
meta: {

View File

@ -29,6 +29,7 @@ const Setting: AppRouteRecordRaw = {
'SYSTEM_SERVICE_INTEGRATION:READ',
'ORGANIZATION_TEMPLATE:READ',
'ORGANIZATION_LOG:READ',
'SYSTEM_TASK_CENTER:READ',
],
},
children: [
@ -50,6 +51,7 @@ const Setting: AppRouteRecordRaw = {
'SYSTEM_AUTH:READ',
'SYSTEM_PLUGIN:READ',
'SYSTEM_LOG:READ',
'SYSTEM_TASK_CENTER:READ',
],
hideChildrenInMenu: true,
},
@ -157,7 +159,7 @@ const Setting: AppRouteRecordRaw = {
component: () => import('@/views/setting/system/taskCenter/index.vue'),
meta: {
locale: 'menu.projectManagement.taskCenter',
roles: ['*'],
roles: ['SYSTEM_TASK_CENTER:READ'],
isTopMenu: true,
},
},
@ -187,6 +189,8 @@ const Setting: AppRouteRecordRaw = {
'SYSTEM_SERVICE_INTEGRATION:READ',
'ORGANIZATION_TEMPLATE:READ',
'ORGANIZATION_LOG:READ',
'ORGANIZATION_TASK_CENTER::READ',
'ORGANIZATION_TASK_CENTER::READ',
],
hideChildrenInMenu: true,
},
@ -305,7 +309,7 @@ const Setting: AppRouteRecordRaw = {
query: ['type'],
},
{
name: SettingRouteEnum.SETTING_ORGANIZATION_TEMPLATE_MANAGEMENT,
name: SettingRouteEnum.SETTING_ORGANIZATION_TEMPLATE_MANAGEMENT_CASE_DETAIL,
locale: 'system.orgTemplate.createCaseTemplate',
editTag: 'id',
editLocale: 'system.orgTemplate.updateCaseTemplate',
@ -408,7 +412,7 @@ const Setting: AppRouteRecordRaw = {
component: () => import('@/views/setting/organization/taskCenter/index.vue'),
meta: {
locale: 'menu.projectManagement.taskCenter',
roles: ['*'],
roles: ['ORGANIZATION_TASK_CENTER::READ'],
isTopMenu: true,
},
},

View File

@ -4,6 +4,7 @@
:title="title"
:is-edit="isEdit"
has-breadcrumb
:hide-continue="!isEdit"
@save="saveHandler"
@save-and-continue="saveHandler(true)"
>
@ -15,7 +16,7 @@
<template #footerRight>
<div class="flex justify-end gap-[16px]">
<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') }}
</a-button>
<a-button v-if="!isFormReviewCase" type="primary" @click="saveHandler(false)">

View File

@ -632,24 +632,29 @@
{
label: 'common.edit',
eventTag: 'batchEdit',
permission: ['FUNCTIONAL_CASE:READ+UPDATE'],
},
{
label: 'caseManagement.featureCase.moveTo',
eventTag: 'batchMoveTo',
permission: ['FUNCTIONAL_CASE:READ+UPDATE'],
},
{
label: 'caseManagement.featureCase.copyTo',
eventTag: 'batchCopyTo',
permission: ['FUNCTIONAL_CASE:READ+ADD'],
},
],
moreAction: [
{
label: 'caseManagement.featureCase.addDemand',
eventTag: 'addDemand',
permission: ['FUNCTIONAL_CASE:READ+UPDATE'],
},
{
label: 'caseManagement.featureCase.associatedDemand',
eventTag: 'associatedDemand',
permission: ['FUNCTIONAL_CASE:READ+UPDATE'],
},
// {
// label: 'caseManagement.featureCase.generatingDependencies',

View File

@ -80,7 +80,7 @@
</a-form>
<!-- 文件列表开始 -->
<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 }">
<!-- 本地文件 -->
<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);
if (fileIds.length) {
checkUpdateFileIds.value = await checkFileIsUpdateRequest(fileIds);
getDetailData(detailResult);
}
getDetailData(detailResult);
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
@ -650,6 +650,7 @@
}
function handleChange(_fileList: MsFileItem[]) {
//
fileList.value = _fileList.map((e) => {
return {
...e,

View File

@ -42,6 +42,7 @@
:show-file-list="false"
:auto-upload="false"
:disabled="confirmLoading"
:file-type-tip="fileTypeTip"
></MsUpload>
<!-- 版本暂时不上 -->
<!-- <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 isDisabled = ref<boolean>(false);

View File

@ -218,6 +218,9 @@
<template #createUserName="{ record }">
<span type="text" class="px-0">{{ record.createUserName || '-' }}</span>
</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 }">
<a-tooltip
@ -253,6 +256,7 @@
*/
import { computed, ref } from 'vue';
import { Message } from '@arco-design/web-vue';
import dayjs from 'dayjs';
import { CustomTypeMaps, MsAdvanceFilter } from '@/components/pure/ms-advance-filter';
import { FilterFormItem, FilterResult, FilterType } from '@/components/pure/ms-advance-filter/type';
@ -285,6 +289,7 @@
import { useAppStore, useTableStore } from '@/store';
import useFeatureCaseStore from '@/store/modules/case/featureCase';
import { characterLimit, findNodeByKey, findNodePathByKey, mapTree } from '@/utils';
import { hasAnyPermission } from '@/utils/permission';
import type { BatchMoveOrCopyType, CaseManagementTable, CustomAttributes } from '@/models/caseManagement/featureCase';
import type { ModuleTreeNode, TableQueryParams } from '@/models/common';
@ -326,6 +331,9 @@
}),
})
);
const hasOperationPermission = computed(() => hasAnyPermission(['FUNCTIONAL_CASE:READ+DELETE']));
const columns: MsTableColumn = [
{
'title': 'caseManagement.featureCase.tableColumnID',
@ -473,13 +481,13 @@
showDrag: true,
},
{
title: 'caseManagement.featureCase.tableColumnActions',
title: hasOperationPermission.value ? 'caseManagement.featureCase.tableColumnActions' : '',
slotName: 'operation',
dataIndex: 'operation',
fixed: 'right',
width: 260,
showInTable: true,
showDrag: false,
width: hasOperationPermission.value ? 260 : 50,
},
];
@ -488,11 +496,13 @@
{
label: 'caseManagement.featureCase.batchRecover',
eventTag: 'batchRecover',
permission: ['FUNCTIONAL_CASE:READ+DELETE'],
},
{
label: 'caseManagement.featureCase.batchCleanOut',
eventTag: 'batchCleanOut',
danger: true,
permission: ['FUNCTIONAL_CASE:READ+DELETE'],
},
],
};

View File

@ -3,7 +3,13 @@
v-model:visible="transferVisible"
title-align="start"
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>
<a-tree-select
@ -104,4 +110,10 @@
);
</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>

View File

@ -101,6 +101,7 @@ export function convertToFile(fileInfo: AssociatedList): MsFileItem {
});
Object.defineProperty(file, 'size', { value: fileInfo.size });
const { id, createUserName, createTime, local, isUpdateFlag, associateId } = fileInfo;
debugger;
return {
enable: fileInfo.enable || false,
file,

View File

@ -116,7 +116,8 @@ export default {
'caseManagement.featureCase.recoveredSuccessfully': 'Recovered successfully',
'caseManagement.featureCase.cleanOutDeleteTip':
'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.copy': 'Copy',
'caseManagement.featureCase.copyCase': 'Copy case',
@ -262,4 +263,6 @@ export default {
'caseManagement.featureCase.jira': 'JIRA',
'caseManagement.featureCase.searchPlaceholder': 'Search by ID, name, or tag',
'caseManagement.featureCase.ModuleOwned': 'Module owned',
'caseManagement.featureCase.excelImportTip': 'Only xls/xlsx files are supported',
'caseManagement.featureCase.xmindImportTip': 'Only xmind files are supported',
};

View File

@ -258,4 +258,6 @@ export default {
'caseManagement.featureCase.jira': 'JIRA',
'caseManagement.featureCase.searchPlaceholder': '通过ID、名称或标签搜索',
'caseManagement.featureCase.ModuleOwned': '所属模块',
'caseManagement.featureCase.excelImportTip': '仅支持xls/xlsx格式的文件',
'caseManagement.featureCase.xmindImportTip': '仅支持xmind格式的文件',
};

View File

@ -77,7 +77,7 @@
ref="projectMemberRef"
v-model:visible="addMemberVisible"
:user-group-options="userGroupOptions"
@success="loadList()"
@success="initData()"
/>
<MsBatchModal
ref="batchModalRef"
@ -115,7 +115,7 @@
import { useI18n } from '@/hooks/useI18n';
import useModal from '@/hooks/useModal';
import { useAppStore, useTableStore } from '@/store';
import { characterLimit, formatPhoneNumber } from '@/utils';
import { characterLimit, formatPhoneNumber, sleep } from '@/utils';
import { hasAnyPermission } from '@/utils/permission';
import type {
@ -206,7 +206,6 @@
showSetting: true,
heightUsed: 288,
showJumpMethod: true,
columns,
scroll: {
x: 1200,
},
@ -230,7 +229,7 @@
const roleIds = ref<string>('');
const initData = async () => {
setLoadListParams({ ...searchParams.value });
await loadList();
loadList();
};
const searchHandler = () => {
@ -394,12 +393,12 @@
];
};
const memberTableRef = ref();
initOptions();
onMounted(() => {
onBeforeMount(() => {
initData();
initOptions();
memberTableRef.value.initColumn(columns);
});
tableStore.initColumn(TableKeyEnum.PROJECT_MEMBER, columns, 'drawer');
</script>

View File

@ -55,7 +55,10 @@
</template>
<template #operation="{ record }">
<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"
@click="stop(record)"
>{{ t('project.taskCenter.stop') }}</MsButton
@ -94,6 +97,7 @@
import { useI18n } from '@/hooks/useI18n';
import useModal from '@/hooks/useModal';
import { characterLimit } from '@/utils';
import { hasAnyPermission } from '@/utils/permission';
import { BatchApiParams } from '@/models/common';
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({
system: {
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,
{
columns,

View File

@ -526,7 +526,12 @@
required: item.required,
},
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,
@ -583,6 +588,8 @@
}
onMounted(async () => {
selectData.value = [];
totalTemplateField.value = [];
await getClassifyField();
getFieldOptionList();
if (isEdit.value) {

View File

@ -18,7 +18,7 @@
allow-clear
/>
<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')
}}</span>
<a-tooltip position="bottom">