feat(全局): 表格组件增加快速创建插槽&部分组件调整&部分页面调整&文件管理页面部分接口

This commit is contained in:
baiqi 2023-10-26 15:45:48 +08:00 committed by Craftsman
parent 683d4fb729
commit 0065b4c28c
34 changed files with 993 additions and 1238 deletions

View File

@ -37,7 +37,7 @@
"dependencies": {
"@7polo/kity": "2.0.8",
"@7polo/kityminder-core": "1.4.53",
"@arco-design/web-vue": "^2.52.0",
"@arco-design/web-vue": "^2.52.1",
"@arco-themes/vue-ms-theme-default": "^0.0.30",
"@form-create/arco-design": "^3.1.23",
"@halo-dev/richtext-editor": "0.0.0-alpha.32",

View File

@ -1,831 +1,96 @@
import MSR from '@/api/http/index';
import { FileDetailUrl, FileListUrl } from '@/api/requrls/project-management/fileManagement';
import {
AddModuleUrl,
BatchDownloadFileUrl,
DeleteFileUrl,
DeleteModuleUrl,
DownloadFileUrl,
FilePageUrl,
GetModuleCountUrl,
GetModuleUrl,
MoveModuleUrl,
ReuploadFileUrl,
UpdateFileUrl,
UpdateModuleUrl,
UploadFileUrl,
} from '@/api/requrls/project-management/fileManagement';
import type { CommonList, TableQueryParams } from '@/models/common';
import type { CommonList } from '@/models/common';
import type {
AddModuleParams,
BatchFileApiParams,
FileItem,
FileListQueryParams,
ModuleCount,
ModuleTreeNode,
MoveModuleParams,
ReuploadFileParams,
UpdateFileParams,
UpdateModuleParams,
UploadFileParams,
} from '@/models/projectManagement/file';
const fileList = [
{
id: 100001,
name: 'JAR',
url: 'https://github.com/metersphere/metersphere/blob/v2.10/.gitignore',
type: 'JAR',
desc: 'fwihflhlofihlasjkhfdlkasjdhgaksuidhoasidoasidasopidapsoidaps',
storage: 'minio',
tag: ['dsadasd'],
size: '12MB',
enable: true,
fileVersion: 'v2.10',
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000002,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000003,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000004,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000005,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000006,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000007,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000008,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000009,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000010,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000011,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000012,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000013,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000014,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000015,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000016,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000017,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000018,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000019,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000020,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 100001,
name: 'JAR',
url: 'https://github.com/metersphere/metersphere/blob/v2.10/.gitignore',
type: 'JAR',
desc: 'fwihflhlofihlasjkhfdlkasjdhgaksuidhoasidoasidasopidapsoidaps',
storage: 'minio',
tag: ['dsadasd'],
size: '12MB',
enable: true,
fileVersion: 'v2.10',
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000002,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000003,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000004,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000005,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000006,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000007,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000008,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000009,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000010,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 100001,
name: 'JAR',
url: 'https://github.com/metersphere/metersphere/blob/v2.10/.gitignore',
type: 'JAR',
desc: 'fwihflhlofihlasjkhfdlkasjdhgaksuidhoasidoasidasopidapsoidaps',
storage: 'minio',
tag: ['dsadasd'],
size: '12MB',
enable: true,
fileVersion: 'v2.10',
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000002,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000003,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000004,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000005,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000006,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000007,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000008,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000009,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1000010,
name: 'PNG',
url: 'http://localhost:5173/front/base-display/get/logo-platform',
type: 'PNG',
desc: 'sfakjdghkjrugheoirugkblasjblsdjkhflksdjfsldkjklnjkhkljds',
storage: 'github',
gitBranch: 'master',
gitVersion: 'v2.10',
gitPath: '/asdas/xas/xas/fd/f/',
tag: ['asfasdfas'],
size: '12MB',
enable: false,
fileModule: 'XXX',
creator: '创建人',
updater: '更新人',
updateTime: 18975439859,
createTime: 18975439859,
},
];
// 获取文件列表
export function getFileList(data: TableQueryParams): Promise<CommonList<any>> {
// return MSR.post<CommonList<any>>({ url: FileListUrl, data });
return Promise.resolve({
total: 100,
list: fileList,
pageSize: 10,
current: 1,
});
export function getFileList(data: FileListQueryParams) {
return MSR.post<CommonList<FileItem>>({ url: FilePageUrl, data });
}
// 获取文件详情
export function getFileDetail(id: string | number) {
// return MSR.post<CommonList<any>>({ url: FileDetailUrl, data });
return Promise.resolve(fileList.find((item) => item.id === id));
// 获取文件列表
export function getModulesCount(data: FileListQueryParams) {
return MSR.post<ModuleCount>({ url: GetModuleCountUrl, data });
}
// 获取文件关联用例列表
export function getFileCases(data: TableQueryParams) {
// return MSR.post<CommonList<any>>({ url: FileDetailUrl, data });
return Promise.resolve({
total: 1,
list: [
{
id: 1,
name: '用例名称 xxxx',
type: '功能',
fileVersion: '93f9384yf9',
updateTime: 18975439859,
createTime: 18975439859,
},
{
id: 1,
name: '用例名称 12433421',
type: '接口',
fileVersion: '93f9384yf9',
updateTime: 18975439859,
createTime: 18975439859,
},
],
pageSize: 10,
current: 1,
});
// 上传文件
export function uploadFile(data: UploadFileParams) {
return MSR.uploadFile({ url: UploadFileUrl }, { request: data.request, fileList: [data.file] });
}
// 获取文件版本列表
export function getFileVersions(data: TableQueryParams) {
// return MSR.post<CommonList<any>>({ url: FileDetailUrl, data });
return Promise.resolve({
total: 1,
list: [
{
id: 1,
version: 'd08hf034f3',
record: 'fuih03h4f0ihoiw',
creator: '创建人',
createTime: 18975439859,
},
{
id: 1,
version: 'd08hf034f3',
record: 'fuih03h4f0ihoiw',
creator: '创建人',
createTime: 18975439859,
},
],
pageSize: 10,
current: 1,
});
// 更新文件信息
export function updateFile(data: UpdateFileParams) {
return MSR.post({ url: UpdateFileUrl, data });
}
// 重新上传文件
export function reuploadFile(data: ReuploadFileParams) {
return MSR.uploadFile({ url: ReuploadFileUrl }, { request: data.request, fileList: [data.file] });
}
// 删除文件
export function deleteFile(data: BatchFileApiParams) {
return MSR.post({ url: DeleteFileUrl, data });
}
// 下载文件
export function downloadFile(id: string) {
return MSR.get({ url: DownloadFileUrl, params: id }, { isTransformResponse: false });
}
// 批量下载文件
export function batchDownloadFile(data: BatchFileApiParams) {
return MSR.post({ url: BatchDownloadFileUrl, data }, { isTransformResponse: false });
}
// 更新模块
export function updateModule(data: UpdateModuleParams) {
return MSR.post({ url: UpdateModuleUrl, data });
}
// 移动模块
export function moveModule(data: MoveModuleParams) {
return MSR.post({ url: MoveModuleUrl, data });
}
// 添加模块
export function addModule(data: AddModuleParams) {
return MSR.post({ url: AddModuleUrl, data });
}
// 查找模块
export function getModules(id: string) {
return MSR.get<ModuleTreeNode[]>({ url: GetModuleUrl, params: id });
}
// 删除模块
export function deleteModule(id: string) {
return MSR.get({ url: DeleteModuleUrl, params: id });
}

View File

@ -1,2 +1,13 @@
export const FileListUrl = '/project/member/get-member/option';
export const FileDetailUrl = '/project/member/get-member/option';
export const UploadFileUrl = '/project/file/upload'; // 上传文件
export const UpdateFileUrl = '/project/file/update'; // 更新文件
export const ReuploadFileUrl = '/project/file/re-upload'; // 重新上传文件
export const FilePageUrl = '/project/file/page'; // 分页查询文件列表
export const DeleteFileUrl = '/project/file/delete'; // 删除文件
export const DownloadFileUrl = '/project/file/download'; // 下载文件
export const BatchDownloadFileUrl = '/project/file/batch-download'; // 批量下载文件
export const UpdateModuleUrl = '/project/file-module/update'; // 更新模块
export const MoveModuleUrl = '/project/file-module/move'; // 移动模块
export const AddModuleUrl = '/project/file-module/add'; // 添加模块
export const GetModuleUrl = '/project/file-module/tree'; // 查找模块
export const DeleteModuleUrl = '/project/file-module/delete'; // 删除模块
export const GetModuleCountUrl = '/project/file/module/count'; // 模块统计文件数量

View File

@ -28,7 +28,7 @@
</template>
<script setup lang="ts">
import { computed, nextTick, onMounted, type Ref, ref, watch, watchEffect } from 'vue';
import { nextTick, onMounted, type Ref, ref, watch, watchEffect } from 'vue';
import { useResizeObserver } from '@vueuse/core';
import { debounce } from 'lodash-es';
@ -95,13 +95,12 @@
const listPage = ref(0);
const listTotal = ref(0);
const remoteList = ref<any[]>([]);
const noMore = computed(() => {
return listSize.value * (listPage.value - 1) + remoteList.value.length >= listTotal.value;
});
const noMore = ref(false);
const isInit = ref(false);
const topLoading = ref(false);
const bottomLoading = ref(false);
const isLoadError = ref(false); // TODO:
/**
* 加载上一页
@ -129,23 +128,30 @@
/**
* 加载下一页
* @param isReload 是否重新加载列表
*/
async function loadNextList() {
async function loadNextList(isReload = false) {
try {
if (props.mode === 'remote' && typeof props.remoteFunc === 'function') {
bottomLoading.value = true;
listPage.value += 1;
if (isReload) {
listPage.value = 1;
}
const res = await props.remoteFunc({
current: listPage.value,
pageSize: listSize.value,
...(props.remoteParams || {}),
});
remoteList.value = res.list;
remoteList.value = isReload ? res.list : remoteList.value.concat(res.list);
listTotal.value = res.total;
bottomLoading.value = false;
noMore.value = listSize.value * (listPage.value - 1) + remoteList.value.length >= listTotal.value;
}
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
isLoadError.value = true;
} finally {
bottomLoading.value = false;
}
@ -188,7 +194,7 @@
debounce((entries) => {
const entry = entries[0];
const { width, height } = entry.contentRect;
if (isInit.value) {
if (isInit.value && !isLoadError.value && !noMore.value) {
computedListSize(width, height);
}
}, 300)
@ -207,12 +213,26 @@
if (isArrivedTop.value && !isArrivedBottom.value && listPage.value > 1 && !topLoading.value) {
// 1
loadPrevList();
} else if (isArrivedBottom.value && !isArrivedTop.value && !noMore.value && !bottomLoading.value) {
} else if (
isArrivedBottom.value &&
!isArrivedTop.value &&
!noMore.value &&
!bottomLoading.value &&
!isLoadError.value
) {
// 1
loadNextList();
}
}
});
function reload() {
loadNextList(true);
}
defineExpose({
reload,
});
</script>
<style lang="less" scoped>

View File

@ -100,11 +100,6 @@
async function initDetail() {
try {
loading.value = true;
await new Promise((resolve) => {
setTimeout(() => {
resolve(true);
}, 3000);
});
detail.value = await props.getDetailFunc(activeDetailId.value);
emit('loaded', detail.value);
} catch (error) {
@ -195,6 +190,12 @@
initDetail();
}
);
defineExpose({
initDetail,
openPrevDetail,
openNextDetail,
});
</script>
<style lang="less" scoped></style>

View File

@ -4,11 +4,17 @@
<div class="ms-thumbnail-card-more">
<MsTableMoreAction v-if="props.moreActions" :list="props.moreActions" @select="handleMoreActionSelect" />
</div>
<img v-if="fileType === 'image'" :src="props.url" class="absolute top-0" />
<MsIcon v-else :type="FileIconMap[fileType][UploadStatus.done]" class="absolute top-0 h-full w-full p-[24px]" />
<div class="ms-thumbnail-card-footer">
{{ props.footerText }}
</div>
<a-image v-if="fileType === 'image'" :src="props.url" class="absolute top-0 h-full w-full" :preview="false" />
<MsIcon
v-else
:type="FileIconMap[fileType][UploadStatus.done]"
class="absolute top-0 h-full w-full p-[24px] text-[var(--color-text-4)]"
/>
<a-tooltip :content="props.footerText" :mouse-enter-delay="300" position="bl" mini>
<div class="ms-thumbnail-card-footer one-line-text">
{{ props.footerText }}
</div>
</a-tooltip>
</div>
</div>
</template>
@ -58,14 +64,14 @@
<style lang="less" scoped>
.ms-thumbnail-card {
@apply relative w-full;
@apply relative w-full overflow-hidden;
border-radius: var(--border-radius-small);
aspect-ratio: 1/1;
.ms-thumbnail-card-content {
@apply absolute bottom-0 left-0 right-0 top-0 inline-block flex-grow cursor-pointer overflow-hidden;
@apply absolute bottom-0 left-0 right-0 top-0 inline-block flex-grow cursor-pointer;
min-width: 102px;
border-radius: var(--border-radius-small);
background-color: var(--color-text-n9);
transition: all 0.2s;
&::before {
@ -96,7 +102,7 @@
@apply absolute w-full text-center;
bottom: 0;
padding: 2px 0;
padding: 2px 4px;
font-size: 12px;
font-weight: 500;
color: #ffffff;

View File

@ -54,7 +54,6 @@
title: 'title',
children: 'children',
disabled: 'disabled',
isLeaf: 'isLeaf',
}),
}
);

View File

@ -109,7 +109,7 @@
const emit = defineEmits<{
(e: 'select', selectedKeys: Array<string | number>, node: MsTreeNodeData): void;
(
e: 'dragOver',
e: 'drop',
tree: MsTreeNodeData[],
dragNode: MsTreeNodeData, //
dropNode: MsTreeNodeData, //
@ -137,14 +137,13 @@
node.icon = () => h('span', { class: 'hidden' });
}
if (
node[props.fieldNames.isLeaf] ||
node[props.fieldNames.isLeaf || 'isLeaf'] ||
!node[props.fieldNames.children] ||
node[props.fieldNames.children]?.length === 0
) {
// icon线 switcherIcon 线 icon
node[props.showLine ? 'switcherIcon' : 'icon'] = () => h('span', { class: 'hidden' });
}
node.disabled = false;
return node;
});
nextTick(() => {
@ -268,7 +267,7 @@
arr.splice(dropPosition < 0 ? index : index + 1, 0, dragNode);
});
}
emit('dragOver', originalTreeData.value, dragNode, dropNode, dropPosition);
emit('drop', originalTreeData.value, dragNode, dropNode, dropPosition);
}
/**
@ -304,7 +303,7 @@
() => innerFocusNodeKey.value,
(val) => {
if (val.toString() !== '') {
focusEl.value = treeRef.value?.$el.querySelector(`[data-key=${val}]`);
focusEl.value = treeRef.value?.$el.querySelector(`[data-key="${val}"]`);
if (focusEl.value) {
focusEl.value.style.backgroundColor = 'rgb(var(--primary-1))';
}
@ -362,6 +361,9 @@
&:hover {
background-color: rgb(var(--primary-1));
}
.arco-tree-node-indent-block {
width: 1px;
}
.arco-tree-node-minus-icon,
.arco-tree-node-plus-icon {
border: 1px solid var(--color-text-4);
@ -379,6 +381,9 @@
color: var(--color-text-4);
}
}
.arco-tree-node-title-highlight {
background-color: transparent;
}
.arco-tree-node-title {
&:hover {
background-color: rgb(var(--primary-1));
@ -386,7 +391,11 @@
@apply block;
}
}
.arco-tree-node-title-text {
width: calc(100% - 8px);
}
.arco-tree-node-drag-icon {
right: 4px;
.arco-icon {
font-size: 14px;
}

View File

@ -4,7 +4,6 @@ export interface MsTreeFieldNames extends TreeFieldNames {
key: string;
title: string;
children: string;
isLeaf: string;
[key: string]: any;
}

View File

@ -275,7 +275,6 @@
color: var(--color-text-1) !important;
&:hover,
.arco-menu-indent-list:hover,
.arco-icon:hover {
background-color: rgb(var(--primary-1)) !important;
}

View File

@ -38,8 +38,8 @@
v-model.trim="addTagInput"
size="mini"
:error="!!tagInputError"
@keyup.enter="handleAdd(item)"
@blur="handleAdd(item)"
@keyup.enter="handleAddTag(item)"
@blur="handleAddTag(item)"
>
<template #suffix>
<icon-loading v-if="tagInputLoading" class="text-[rgb(var(--primary-5))]" />
@ -159,7 +159,11 @@
const tagInputLoading = ref(false);
const tagInputError = ref('');
async function handleAdd(item: Description) {
/**
* 添加标签
* @param item 当前标签项
*/
async function handleAddTag(item: Description) {
if (Array.isArray(item.value) && item.value.includes(addTagInput.value)) {
tagInputError.value = t('ms.description.addTagRepeat');
return;
@ -169,12 +173,17 @@
tagInputLoading.value = true;
if (props.addTagFunc && typeof props.addTagFunc === 'function') {
await props.addTagFunc(addTagInput.value);
if (Array.isArray(item.value)) {
item.value.push(addTagInput.value);
} else {
item.value = [addTagInput.value];
}
} else {
emit('addTag', addTagInput.value);
}
showTagInput.value = false;
} catch (error) {
// eslint-disable-next-line prettier/prettier
// eslint-disable-next-line no-console
console.log(error);
tagInputError.value = (error as Error).message;
} finally {

View File

@ -10,6 +10,9 @@
props.mask ? '' : 'ms-drawer-no-mask',
props.noContentPadding ? 'ms-drawer-no-content-padding' : '',
]"
:drawer-style="{
minWidth: props.minWidth,
}"
@cancel="handleCancel"
@close="handleClose"
>
@ -88,7 +91,8 @@
cancelText?: string;
saveContinueText?: string;
showContinue?: boolean;
width: number;
width: number | string;
minWidth?: string; //
noContentPadding?: boolean; //
}

View File

@ -1,5 +1,8 @@
<template>
<div class="ms-base-table">
<div :class="['ms-base-table', $slots.quickCreate ? 'ms-base-table--hasQuickCreate' : '']">
<div v-if="$slots.quickCreate" class="ms-base-table-quickCreate">
<slot name="quickCreate"></slot>
</div>
<a-table
v-bind="$attrs"
:row-class="getRowClass"
@ -452,6 +455,24 @@
}
}
}
.ms-base-table--hasQuickCreate {
:deep(.arco-table-body) {
padding-top: 54px;
}
:deep(.arco-table-tr:first-child) {
.arco-table-td {
border-top: 1px solid var(--color-text-n8);
}
}
.ms-base-table-quickCreate {
@apply absolute left-0 flex w-full items-center;
top: 55px;
z-index: 11;
padding: 16px;
background-color: var(--color-text-n9);
}
}
:deep(.ms-table-select-all) {
.dropdown-icon {
background: none !important;

View File

@ -1,8 +1,8 @@
import { TableChangeExtra, TableColumnData, TableData, TableDraggable } from '@arco-design/web-vue';
import { TableQueryParams } from '@/models/common';
import type { TableQueryParams } from '@/models/common';
import { ColumnEditTypeEnum, SelectAllEnum } from '@/enums/tableEnum';
import type { TableChangeExtra, TableColumnData, TableData, TableDraggable } from '@arco-design/web-vue';
export interface MsPaginationI {
current: number;
pageSize: number;

View File

@ -113,6 +113,8 @@
const props = defineProps<{
fileList: MsFileItem[];
uploadFunc: (params: any) => Promise<any>; //
requestParams?: Record<string, any>; //
route?: string; //
routeQuery?: Record<string, string>; //
handleDelete?: (item: MsFileItem) => void;
@ -183,6 +185,7 @@
*/
function startUpload() {
emit('start');
asyncTaskStore.setUploadFunc(props.uploadFunc, props.requestParams);
asyncTaskStore.startUpload(innerFileList.value, props.route, props.routeQuery);
}
@ -234,7 +237,7 @@
if (typeof props.handleReupload === 'function') {
props.handleReupload(item);
} else {
item.status = UploadStatus.init;
item.status = UploadStatus.init; //
if (asyncTaskStore.uploadFileTask.uploadQueue.length > 0) {
// push
asyncTaskStore.uploadFileTask.uploadQueue.push(item);

View File

@ -32,6 +32,10 @@ export const FileIconMap: FileIconMapping = {
[UploadStatus.init]: 'icon-icon_file-sql_colorful_ash',
[UploadStatus.done]: 'icon-icon_file-sql_colorful1',
},
plain: {
[UploadStatus.init]: 'icon-icon_file-text_colorful_ash',
[UploadStatus.done]: 'icon-icon_file-text_colorful1',
},
txt: {
[UploadStatus.init]: 'icon-icon_file-text_colorful_ash',
[UploadStatus.done]: 'icon-icon_file-text_colorful1',

View File

@ -4,6 +4,7 @@ export enum UploadAcceptEnum {
pdf = '.pdf',
ppt = '.pptx,.ppt',
txt = '.txt',
plain = '.plain',
video = '.mp4',
sql = '.sql',
csv = '.csv',

View File

@ -2,8 +2,7 @@
<router-view v-slot="{ Component, route }">
<transition name="fade" mode="out-in" appear>
<!-- transition内必须有且只有一个根元素不然会导致二级路由的组件无法渲染 -->
<!-- eslint-disable-next-line vue/require-toggle-inside-transition -->
<div class="page-content">
<div v-show="true" class="page-content">
<component :is="Component" v-if="!route.meta.isCache" :key="route.fullPath" />
<keep-alive v-else>
<component :is="Component" :key="route.fullPath" />

View File

@ -0,0 +1,77 @@
import { BatchApiParams, TableQueryParams } from '@/models/common';
// 文件列表查询参数
export interface FileListQueryParams extends TableQueryParams {
moduleIds: string[];
fileType: string;
projectId: string;
}
// 模块统计文件数量
export interface ModuleCount {
[key: string]: number;
}
// 文件列表项
export interface FileItem {
id: string;
name: string;
fileType: string; // 文件类型
tags: string[]; // 标签
description: string;
updateUser: string;
updateTime: number;
previewSrc: string; // 预览地址
size: number;
}
// 上传文件参数
export interface UploadFileParams {
request: {
projectId: string;
moduleId: string; // 模块ID
};
file: File;
}
// 更新文件参数
export interface UpdateFileParams {
id: string;
name?: string;
tags?: string[];
description?: string;
moduleId?: string;
}
// 重新上传文件参数
export interface ReuploadFileParams {
request: {
fileId: string;
};
file: File;
}
// 批量操作文件参数
export interface BatchFileApiParams extends BatchApiParams {
projectId: string;
fileType: string;
moduleIds: string[];
}
// 更新模块参数
export interface UpdateModuleParams {
id: string;
name: string;
}
// 移动模块参数
export interface MoveModuleParams {
dragNodeId: string; // 拖拽的节点ID
dropNodeId: string; // 拖拽的节点释放的节点ID
dropPosition: number; // 拖拽的节点释放的位置,-1 为前面1为后面0为内部
}
// 添加模块参数
export interface AddModuleParams {
projectId: string;
name: string;
parentId: string;
}
// 模块树节点
export interface ModuleTreeNode {
id: string;
name: string;
type: string;
children: ModuleTreeNode[];
}

View File

@ -23,6 +23,8 @@ const useAsyncTaskStore = defineStore('asyncTask', {
isBackstageUpload: false, // 是否后台上传,后台上传会展示全局提示类型的进度提示
isHideMessage: false, // 后台上传时展示的消息提示在点击关闭后无需再弹
fileList: [], // 文件总队列,包含已经上传的历史记录(不做持久化存储,刷新丢失)
uploadFunc: undefined, // 上传文件时,自定义上传方法
requestParams: undefined, // 上传文件时,额外的请求参数
uploadQueue: [], // 每次添加的上传队列,用于展示每次任务的进度使用
eachTaskQueue: [], // 上传队列,每个文件上传完成后会从队列中移除,初始值为上传队列的副本
singleProgress: 0, // 单个上传文件的上传进度,非总进度,是每个文件在上传时的模拟进度
@ -67,6 +69,14 @@ const useAsyncTaskStore = defineStore('asyncTask', {
},
},
actions: {
setUploadFunc(uploadFunc: (params: any) => Promise<any>, requestParams?: Record<string, any>) {
this.$patch({
uploadFileTask: {
uploadFunc,
requestParams,
},
});
},
beforeEachUpload(fileItem?: MsFileItem, route?: string, routeQuery?: Record<string, any>) {
const { t } = useI18n();
const { uploadFileTask } = this;
@ -161,6 +171,8 @@ const useAsyncTaskStore = defineStore('asyncTask', {
uploadFileTask: {
isBackstageUpload: false,
isHideMessage: false,
uploadFunc: undefined,
requestParams: undefined,
},
});
}
@ -168,12 +180,14 @@ const useAsyncTaskStore = defineStore('asyncTask', {
async uploadFileFromQueue(fileItem?: MsFileItem, route?: string, routeQuery?: Record<string, any>) {
this.beforeEachUpload(fileItem, route, routeQuery);
try {
// TODO: 模拟上传,待接口联调后替换为真实上传逻辑
await new Promise((resolve) => {
setTimeout(() => {
resolve(null);
}, 3000);
});
if (this.uploadFileTask.uploadFunc) {
await this.uploadFileTask.uploadFunc({
request: { ...this.uploadFileTask.requestParams },
file: unref(fileItem)?.file,
});
} else {
throw new Error('uploadFunc is not defined');
}
if (fileItem) {
fileItem.status = UploadStatus.done;
fileItem.uploadedTime = Date.now();
@ -219,6 +233,8 @@ const useAsyncTaskStore = defineStore('asyncTask', {
fileList: [],
uploadQueue: [],
singleProgress: 0,
uploadFunc: undefined,
requestParams: undefined,
},
});
},

View File

@ -41,6 +41,8 @@ export interface UploadFileTaskState {
isBackstageUpload: boolean; // 是否后台上传,后台上传会展示全局提示类型的进度提示
isHideMessage: boolean; // 后台上传时展示的消息提示在点击关闭后无需再弹
fileList: MsFileItem[]; // 文件总队列,包含已经上传的历史记录(不做持久化存储,刷新丢失)
uploadFunc?: (params: any) => Promise<any>; // 上传文件时,自定义上传方法
requestParams?: Record<string, any>; // 上传文件时,额外的请求参数
eachTaskQueue: MsFileItem[]; // 每次添加的上传队列,用于展示每次任务的进度使用
uploadQueue: MsFileItem[]; // 上传队列,每个文件上传完成后会从队列中移除,初始值为上传队列的副本
singleProgress: number; // 单个上传文件的上传进度,非总进度,是每个文件在上传时的模拟进度

View File

@ -77,6 +77,7 @@ export const rgbToHex = (rgb: string) => {
/**
*
* @param type
* @param content
* @param fileName
*/
@ -190,7 +191,7 @@ export function mapTree<T>(
tree: TreeNode<T> | TreeNode<T>[] | T | T[],
customNodeFn: (node: TreeNode<T>) => TreeNode<T> | null = (node) => node,
customChildrenKey = 'children'
): TreeNode<T>[] {
): T[] {
if (!Array.isArray(tree)) {
tree = [tree];
}
@ -308,3 +309,25 @@ export const getGenerateId = () => {
const generateId = timestamp + randomDigits;
return generateId.substring(0, 16);
};
/**
*
* @param byte
* @param fileName
*/
export const downloadByteFile = (byte: BlobPart, fileName: string) => {
// 创建一个Blob对象
const blob = new Blob([byte], { type: 'application/octet-stream' });
// 创建一个URL对象用于生成下载链接
const url = window.URL.createObjectURL(blob);
// 创建一个虚拟的<a>标签来触发下载
const link = document.createElement('a');
link.href = url;
link.download = fileName; // 设置下载文件的名称
document.body.appendChild(link);
link.click();
// 释放URL对象
window.URL.revokeObjectURL(url);
document.body.removeChild(link);
};

View File

@ -1,12 +1,13 @@
<template>
<MsDetailDrawer
ref="detailDrawerRef"
v-model:visible="innerVisible"
:width="960"
:footer="false"
:title="t('project.fileManagement.detail')"
:detail-id="props.fileId"
:detail-index="props.activeFileIndex"
:get-detail-func="getFileDetail"
:get-detail-func="async () => ({})"
:pagination="props.pagination"
:table-data="props.tableData"
:page-change="props.pageChange"
@ -56,13 +57,15 @@
</a-skeleton>
<template v-else>
<div class="mb-[16px] w-[102px]">
<MsPreviewCard
mode="hover"
:type="detail?.type"
:url="detail?.url"
:footer-text="t('project.fileManagement.replaceFile')"
@click="handleFileIconClick"
/>
<a-spin :loading="replaceLoading">
<MsPreviewCard
mode="hover"
:type="detail?.type"
:url="detail?.url"
:footer-text="t('project.fileManagement.replaceFile')"
@click="handleFileIconClick"
/>
</a-spin>
</div>
<MsDescription
:descriptions="fileDescriptions"
@ -87,9 +90,10 @@
</a-tooltip>
<template v-if="item.key === 'name'">
<popConfirm
mode="rename"
mode="fileRename"
:field-config="{ placeholder: t('project.fileManagement.fileNamePlaceholder') }"
:all-names="[]"
@rename-finish="detailDrawerRef?.initDetail"
>
<MsButton class="!mr-0 ml-[8px]">{{ t('common.rename') }}</MsButton>
</popConfirm>
@ -105,7 +109,7 @@
</template>
<template v-if="item.key === 'desc'">
<popConfirm
mode="rename"
mode="fileUpdateDesc"
:title="t('project.fileManagement.desc')"
:field-config="{
field: detail.desc,
@ -114,6 +118,7 @@
isTextArea: true,
}"
:all-names="[]"
@update-desc-finish="detailDrawerRef?.initDetail"
>
<MsButton class="ml-[8px]"><MsIcon type="icon-icon_edit_outlined"></MsIcon></MsButton>
</popConfirm>
@ -142,7 +147,7 @@
</a-input-search>
</div>
<div class="p-[16px]">
<ms-base-table
<!-- <ms-base-table
v-if="activeTab === 'case'"
v-bind="caseTableProps"
no-disable
@ -161,7 +166,7 @@
no-disable
v-on="versionTableEvent"
>
</ms-base-table>
</ms-base-table> -->
</div>
</div>
</div>
@ -187,7 +192,7 @@
import MsPreviewCard from '@/components/business/ms-thumbnail-card/index.vue';
import popConfirm from './popConfirm.vue';
import { getFileCases, getFileDetail, getFileVersions } from '@/api/modules/project-management/fileManagement';
import { reuploadFile, updateFile } from '@/api/modules/project-management/fileManagement';
import { useI18n } from '@/hooks/useI18n';
import useLocale from '@/locale/useLocale';
import { downloadUrlFile } from '@/utils';
@ -196,7 +201,7 @@
const props = defineProps<{
visible: boolean;
fileId: string | number;
fileId: string;
activeFileIndex: number;
tableData: any[];
pagination?: MsPaginationI;
@ -211,6 +216,7 @@
const innerVisible = ref(false);
const fileDescriptions = ref<Description[]>([]);
const detailDrawerRef = ref<InstanceType<typeof MsDetailDrawer>>();
watch(
() => props.visible,
@ -242,8 +248,8 @@
const fileType = ref('unknown');
function loadedFile(detail: any) {
if (detail.type) {
fileType.value = getFileEnum(`/${detail.type.toLowerCase()}`);
if (detail.fileType) {
fileType.value = getFileEnum(`/${detail.fileType.toLowerCase()}`);
}
fileDescriptions.value = [
{
@ -258,7 +264,7 @@
},
{
label: t('project.fileManagement.type'),
value: detail.type,
value: detail.fileType,
},
{
label: t('project.fileManagement.size'),
@ -307,11 +313,27 @@
}
}
const replaceLoading = ref(false);
watch(
() => newFile.value,
(data) => {
async (data) => {
if (data) {
Message.success(t('project.fileManagement.replaceFileSuccess'));
try {
replaceLoading.value = true;
await reuploadFile({
request: {
fileId: props.fileId,
},
file: data,
});
Message.success(t('project.fileManagement.replaceFileSuccess'));
detailDrawerRef.value?.initDetail();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
} finally {
replaceLoading.value = false;
}
}
}
);
@ -328,117 +350,116 @@
const previewVisible = ref(false);
async function addFileTag(val: string) {
await new Promise((resolve) => {
setTimeout(() => {
resolve(true);
}, 2000);
await updateFile({
id: props.fileId,
tags: [val],
});
}
const activeTab = ref('case');
const caseColumns: MsTableColumn = [
{
title: 'project.fileManagement.id',
dataIndex: 'id',
width: 100,
},
{
title: 'project.fileManagement.name',
dataIndex: 'name',
showTooltip: true,
width: 200,
},
{
title: 'project.fileManagement.type',
dataIndex: 'type',
},
{
title: 'project.fileManagement.fileVersion',
dataIndex: 'fileVersion',
},
{
title: 'common.operation',
slotName: 'action',
fixed: 'right',
width: 130,
},
];
const {
propsRes: caseTableProps,
propsEvent: caseTableEvent,
loadList: loadCaseList,
setKeyword,
} = useTable(getFileCases, {
tableKey: TableKeyEnum.FILE_MANAGEMENT_CASE,
scroll: { x: 800 },
columns: caseColumns,
selectable: true,
showSelectAll: true,
size: 'default',
});
// const caseColumns: MsTableColumn = [
// {
// title: 'project.fileManagement.id',
// dataIndex: 'id',
// width: 100,
// },
// {
// title: 'project.fileManagement.name',
// dataIndex: 'name',
// showTooltip: true,
// width: 200,
// },
// {
// title: 'project.fileManagement.type',
// dataIndex: 'type',
// },
// {
// title: 'project.fileManagement.fileVersion',
// dataIndex: 'fileVersion',
// },
// {
// title: 'common.operation',
// slotName: 'action',
// fixed: 'right',
// width: 130,
// },
// ];
// const {
// propsRes: caseTableProps,
// propsEvent: caseTableEvent,
// loadList: loadCaseList,
// setKeyword,
// } = useTable(getFileCases, {
// tableKey: TableKeyEnum.FILE_MANAGEMENT_CASE,
// scroll: { x: 800 },
// columns: caseColumns,
// selectable: true,
// showSelectAll: true,
// size: 'default',
// });
const caseBatchActions = {
baseAction: [
{
label: 'project.fileManagement.updateCaseFile',
eventTag: 'updateCaseFile',
},
],
};
// const caseBatchActions = {
// baseAction: [
// {
// label: 'project.fileManagement.updateCaseFile',
// eventTag: 'updateCaseFile',
// },
// ],
// };
const keyword = ref('');
function searchCase() {
setKeyword(keyword.value);
loadCaseList();
// setKeyword(keyword.value);
// loadCaseList();
}
function updateCase(record: any) {
console.log(record);
}
const versionColumns: MsTableColumn = [
{
title: 'project.fileManagement.fileVersion',
dataIndex: 'fileVersion',
},
{
title: 'project.fileManagement.record',
dataIndex: 'record',
showTooltip: true,
},
{
title: 'project.fileManagement.creator',
dataIndex: 'creator',
showTooltip: true,
},
{
title: 'project.fileManagement.createTime',
dataIndex: 'createTime',
width: 180,
},
];
const {
propsRes: versionTableProps,
propsEvent: versionTableEvent,
loadList: loadVersionList,
} = useTable(getFileVersions, {
tableKey: TableKeyEnum.FILE_MANAGEMENT_VERSION,
scroll: { x: '100%' },
columns: versionColumns,
selectable: false,
});
// const versionColumns: MsTableColumn = [
// {
// title: 'project.fileManagement.fileVersion',
// dataIndex: 'fileVersion',
// },
// {
// title: 'project.fileManagement.record',
// dataIndex: 'record',
// showTooltip: true,
// },
// {
// title: 'project.fileManagement.creator',
// dataIndex: 'creator',
// showTooltip: true,
// },
// {
// title: 'project.fileManagement.createTime',
// dataIndex: 'createTime',
// width: 180,
// },
// ];
// const {
// propsRes: versionTableProps,
// propsEvent: versionTableEvent,
// loadList: loadVersionList,
// } = useTable(getFileVersions, {
// tableKey: TableKeyEnum.FILE_MANAGEMENT_VERSION,
// scroll: { x: '100%' },
// columns: versionColumns,
// selectable: false,
// });
watchEffect(() => {
if (innerVisible.value) {
if (activeTab.value === 'case') {
loadCaseList();
} else {
loadVersionList();
}
}
});
// watchEffect(() => {
// if (innerVisible.value) {
// if (activeTab.value === 'case') {
// loadCaseList();
// } else {
// loadVersionList();
// }
// }
// });
</script>
<style lang="less" scoped>

View File

@ -5,36 +5,66 @@
allow-clear
class="mb-[16px]"
></a-input>
<MsTree
v-model:focus-node-key="focusNodeKey"
:selected-keys="props.selectedKeys"
:data="folderTree"
:keyword="moduleKeyword"
:node-more-actions="folderMoreActions"
:expand-all="props.isExpandAll"
:empty-text="t('project.fileManagement.noFolder')"
:draggable="!props.isModal"
:virtual-list-props="virtualListProps"
block-node
@select="folderNodeSelect"
@more-action-select="handleFolderMoreSelect"
@more-actions-close="moreActionsClose"
>
<template #title="nodeData">
<span class="text-[var(--color-text-1)]">{{ nodeData.title }}</span>
<span v-if="!props.isModal" class="ml-[4px] text-[var(--color-text-4)]">({{ nodeData.count }})</span>
</template>
<template v-if="!props.isModal" #extra="nodeData">
<popConfirm mode="add" :all-names="[]" @close="resetFocusNodeKey">
<MsButton type="icon" size="mini" class="ms-tree-node-extra__btn !mr-0" @click="setFocusNodeKe(nodeData)">
<MsIcon type="icon-icon_add_outlined" size="14" class="text-[var(--color-text-4)]" />
</MsButton>
</popConfirm>
<popConfirm mode="rename" :field-config="{ field: renameFolderTitle }" :all-names="[]" @close="resetFocusNodeKey">
<span :id="`renameSpan${nodeData.key}`" class="relative"></span>
</popConfirm>
</template>
</MsTree>
<a-spin class="min-h-[400px] w-full" :loading="loading">
<MsTree
v-model:focus-node-key="focusNodeKey"
:selected-keys="props.selectedKeys"
:data="folderTree"
:keyword="moduleKeyword"
:node-more-actions="folderMoreActions"
:expand-all="props.isExpandAll"
:empty-text="t('project.fileManagement.noFolder')"
:draggable="!props.isModal"
:virtual-list-props="virtualListProps"
:field-names="{
title: 'name',
key: 'id',
children: 'children',
count: 'count',
}"
block-node
@select="folderNodeSelect"
@more-action-select="handleFolderMoreSelect"
@more-actions-close="moreActionsClose"
@drop="handleDrop"
>
<template #title="nodeData">
<div class="inline-flex w-full">
<a-tooltip :content="nodeData.name" :mouse-enter-delay="300" position="left">
<div class="one-line-text w-[calc(100%-32px)] text-[var(--color-text-1)]">{{ nodeData.name }}</div>
</a-tooltip>
<div v-if="!props.isModal" class="ml-[4px] text-[var(--color-text-4)]">({{ nodeData.count || 0 }})</div>
</div>
</template>
<template v-if="!props.isModal" #extra="nodeData">
<!-- 默认模块的 id 是root默认模块不可编辑不可添加子模块 -->
<popConfirm
v-if="nodeData.id !== 'root'"
mode="add"
:all-names="(nodeData.children || []).map((e: ModuleTreeNode) => e.name || '')"
:parent-id="nodeData.id"
@close="resetFocusNodeKey"
@add-finish="() => initModules()"
>
<MsButton type="icon" size="mini" class="ms-tree-node-extra__btn !mr-0" @click="setFocusNodeKey(nodeData)">
<MsIcon type="icon-icon_add_outlined" size="14" class="text-[var(--color-text-4)]" />
</MsButton>
</popConfirm>
<popConfirm
v-if="nodeData.id !== 'root'"
mode="rename"
:parent-id="nodeData.id"
:node-id="nodeData.id"
:field-config="{ field: renameFolderTitle }"
:all-names="(nodeData.children || []).map((e: ModuleTreeNode) => e.name || '')"
@close="resetFocusNodeKey"
@rename-finish="(val) => (nodeData.name = val)"
>
<span :id="`renameSpan${nodeData.id}`" class="relative"></span>
</popConfirm>
</template>
</MsTree>
</a-spin>
</template>
<script setup lang="ts">
@ -48,16 +78,27 @@
import type { MsTreeNodeData } from '@/components/business/ms-tree/types';
import popConfirm from './popConfirm.vue';
import {
deleteModule,
getModules,
getModulesCount,
moveModule,
} from '@/api/modules/project-management/fileManagement';
import { useI18n } from '@/hooks/useI18n';
import useModal from '@/hooks/useModal';
import useAppStore from '@/store/modules/app';
import { mapTree } from '@/utils';
import { FileListQueryParams, ModuleTreeNode } from '@/models/projectManagement/file';
const props = defineProps<{
isExpandAll: boolean;
selectedKeys?: Array<string | number>; // key
isModal?: boolean; //
}>();
const emit = defineEmits(['update:selectedKeys', 'folderNodeSelect']);
const emit = defineEmits(['update:selectedKeys', 'init', 'folderNodeSelect']);
const appStore = useAppStore();
const { t } = useI18n();
const { openModal } = useModal();
@ -68,111 +109,16 @@
};
}
return {
height: 'calc(100vh - 320px)',
height: 'calc(100vh - 325px)',
};
});
const moduleKeyword = ref('');
const folderTree = 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 folderTree = ref<ModuleTreeNode[]>([]);
const focusNodeKey = ref<string | number>('');
const loading = ref(false);
function setFocusNodeKe(node: MsTreeNodeData) {
focusNodeKey.value = node.key || '';
function setFocusNodeKey(node: MsTreeNodeData) {
focusNodeKey.value = node.id || '';
}
const folderMoreActions: ActionsItem[] = [
@ -188,6 +134,50 @@
];
const renamePopVisible = ref(false);
const selectedKeys = ref(props.selectedKeys || []);
watch(
() => props.selectedKeys,
(val) => {
selectedKeys.value = val || [];
}
);
watch(
() => selectedKeys.value,
(val) => {
emit('update:selectedKeys', val);
}
);
/**
* 初始化模块树
* @param isSetDefaultKey 是否设置第一个节点为选中节点
*/
async function initModules(isSetDefaultKey = false) {
try {
loading.value = true;
const res = await getModules(appStore.currentProjectId);
folderTree.value = res.map((e) => ({
...e,
hideMoreAction: e.id === 'root',
draggable: e.id !== 'root',
}));
if (isSetDefaultKey) {
selectedKeys.value = [folderTree.value[0].id];
}
emit(
'init',
folderTree.value.map((e) => e.name)
);
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
} finally {
loading.value = false;
}
}
/**
* 删除文件夹
* @param node 节点信息
@ -195,7 +185,7 @@
function deleteFolder(node: MsTreeNodeData) {
openModal({
type: 'error',
title: t('project.fileManagement.deleteFolderTipTitle', { name: node.title }),
title: t('project.fileManagement.deleteFolderTipTitle', { name: node.name }),
content: t('project.fileManagement.deleteFolderTipContent'),
okText: t('project.fileManagement.deleteConfirm'),
okButtonProps: {
@ -204,8 +194,11 @@
maskClosable: false,
onBeforeOk: async () => {
try {
await deleteModule(node.id);
Message.success(t('project.fileManagement.deleteSuccess'));
initModules(selectedKeys.value[0] === node.id);
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
},
@ -224,8 +217,8 @@
/**
* 处理文件夹树节点选中事件
*/
function folderNodeSelect(selectedKeys: (string | number)[]) {
emit('folderNodeSelect', selectedKeys);
function folderNodeSelect(_selectedKeys: (string | number)[]) {
emit('folderNodeSelect', _selectedKeys);
}
/**
@ -239,15 +232,45 @@
resetFocusNodeKey();
break;
case 'rename':
renameFolderTitle.value = node.title || '';
renameFolderTitle.value = node.name || '';
renamePopVisible.value = true;
document.querySelector(`#renameSpan${node.key}`)?.dispatchEvent(new Event('click'));
document.querySelector(`#renameSpan${node.id}`)?.dispatchEvent(new Event('click'));
break;
default:
break;
}
}
/**
* 处理文件夹树节点拖拽事件
* @param tree 树数据
* @param dragNode 拖拽节点
* @param dropNode 释放节点
* @param dropPosition 释放位置
*/
async function handleDrop(
tree: MsTreeNodeData[],
dragNode: MsTreeNodeData,
dropNode: MsTreeNodeData,
dropPosition: number
) {
try {
loading.value = true;
await moveModule({
dragNodeId: dragNode.id as string,
dropNodeId: dropNode.id || '',
dropPosition,
});
Message.success(t('project.fileManagement.moduleMoveSuccess'));
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
initModules();
} finally {
loading.value = false;
}
}
function moreActionsClose() {
if (!renamePopVisible.value) {
// key
@ -255,21 +278,32 @@
}
}
const selectedKeys = ref(props.selectedKeys || []);
onBeforeMount(() => {
initModules();
});
watch(
() => props.selectedKeys,
(val) => {
selectedKeys.value = val || [];
/**
* 初始化模块文件数量
*/
async function initModulesCount(params: FileListQueryParams) {
try {
const res = await getModulesCount(params);
folderTree.value = mapTree<ModuleTreeNode>(folderTree.value, (node) => {
return {
...node,
count: res[node.id] || 0,
};
});
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
);
}
watch(
() => selectedKeys.value,
(val) => {
emit('update:selectedKeys', val);
}
);
defineExpose({
initModules,
initModulesCount,
});
</script>
<style lang="less" scoped></style>

View File

@ -51,7 +51,9 @@
import { ref, watch } from 'vue';
import { Message } from '@arco-design/web-vue';
import { addModule, updateFile, updateModule } from '@/api/modules/project-management/fileManagement';
import { useI18n } from '@/hooks/useI18n';
import useAppStore from '@/store/modules/app';
import type { FieldRule, FormInstance } from '@arco-design/web-vue';
@ -64,16 +66,19 @@
}
const props = defineProps<{
mode: 'add' | 'rename';
mode: 'add' | 'rename' | 'fileRename' | 'fileUpdateDesc';
visible?: boolean;
title?: string;
allNames: string[];
popupContainer?: string;
fieldConfig?: FieldConfig;
parentId?: string; // id
nodeId?: string; // id
}>();
const emit = defineEmits(['update:visible', 'close']);
const emit = defineEmits(['update:visible', 'close', 'addFinish', 'renameFinish', 'updateDescFinish']);
const appStore = useAppStore();
const { t } = useI18n();
const innerVisible = ref(props.visible || false);
@ -113,9 +118,38 @@
try {
loading.value = true;
if (props.mode === 'add') {
//
await addModule({
projectId: appStore.currentProjectId,
parentId: props.parentId || '',
name: form.value.field,
});
Message.success(t('project.fileManagement.addSubModuleSuccess'));
} else {
emit('addFinish', form.value.field);
} else if (props.mode === 'rename') {
//
await updateModule({
id: props.nodeId || '',
name: form.value.field,
});
Message.success(t('project.fileManagement.renameSuccess'));
emit('renameFinish', form.value.field);
} else if (props.mode === 'fileRename') {
//
await updateFile({
id: props.nodeId || '',
name: form.value.field,
});
Message.success(t('project.fileManagement.renameSuccess'));
emit('renameFinish', form.value.field);
} else if (props.mode === 'fileUpdateDesc') {
//
await updateFile({
id: props.nodeId || '',
description: form.value.field,
});
Message.success(t('project.fileManagement.updateDescSuccess'));
emit('updateDescFinish', form.value.field);
}
if (done) {
done(true);
@ -123,7 +157,11 @@
innerVisible.value = false;
}
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
if (done) {
done(false);
}
} finally {
loading.value = false;
}

View File

@ -25,64 +25,74 @@
<a-radio value="module" class="show-type-icon">{{ t('project.fileManagement.module') }}</a-radio>
<a-radio value="storage" class="show-type-icon">{{ t('project.fileManagement.storage') }}</a-radio>
</a-radio-group>
<a-radio-group v-model:model-value="showType" type="button" class="file-show-type" @change="changeShowType">
<a-radio-group v-model:model-value="showType" type="button" class="file-show-type">
<a-radio value="list" class="show-type-icon p-[2px]"><MsIcon type="icon-icon_view-list_outlined" /></a-radio>
<a-radio value="card" class="show-type-icon p-[2px]"><MsIcon type="icon-icon_card_outlined" /></a-radio>
</a-radio-group>
</div>
</div>
<ms-base-table
v-if="showType === 'list'"
v-bind="propsRes"
:action-config="fileType === 'module' ? moduleFileBatchActions : storageFileBatchActions"
no-disable
v-on="propsEvent"
@selected-change="handleTableSelect"
@batch-action="handleTableBatch"
>
<template #name="{ record, rowIndex }">
<a-button type="text" class="px-0" @click="openFileDetail(record.id, rowIndex)">{{ record.name }}</a-button>
</template>
<template #tag="{ record }">
<MsTagGroup theme="outline" :tag-list="record.tag" is-string-tag />
</template>
<template #action="{ record }">
<MsButton type="text" class="mr-[8px]" @click="downloadFile(record.url, record.name)">
{{ t('project.fileManagement.download') }}
</MsButton>
<MsTableMoreAction
:list="record.type === 'JAR' ? jarFileActions : normalFileActions"
@select="handleMoreActionSelect($event, record)"
/>
</template>
<template v-if="keyword.trim() === ''" #empty>
<div class="flex items-center justify-center p-[8px] text-[var(--color-text-4)]">
{{ t('project.fileManagement.tableNoFile') }}
<MsButton class="ml-[8px]" @click="handleAddClick">
{{ t('project.fileManagement.addFile') }}
<a-spin class="w-full" :loading="loading">
<ms-base-table
v-if="showType === 'list'"
v-bind="propsRes"
:action-config="fileType === 'module' ? moduleFileBatchActions : storageFileBatchActions"
no-disable
v-on="propsEvent"
@selected-change="handleTableSelect"
@batch-action="handleTableBatch"
>
<template #name="{ record, rowIndex }">
<a-tooltip :content="record.name">
<a-button type="text" class="px-0" @click="openFileDetail(record.id, rowIndex)">
<div class="one-line-text max-w-[168px]">{{ record.name }}</div>
</a-button>
</a-tooltip>
</template>
<template #action="{ record }">
<MsButton type="text" class="mr-[8px]" @click="handleDownload(record)">
{{ t('project.fileManagement.download') }}
</MsButton>
</div>
</template>
</ms-base-table>
<MsCardList
v-else-if="showType === 'card'"
mode="remote"
:remote-func="getFileList"
:shadow-limit="50"
:card-min-width="102"
class="flex-1"
>
<template #item="{ item, index }">
<MsThumbnailCard
:type="item.type"
:url="item.url"
:footer-text="item.name"
:more-actions="item.type === 'JAR' ? jarFileActions : normalFileActions"
@click="openFileDetail(item.id, index)"
@action-select="handleMoreActionSelect($event, item)"
/>
</template>
</MsCardList>
<MsTableMoreAction
:list="record.fileType === 'jar' ? jarFileActions : normalFileActions"
@select="handleMoreActionSelect($event, record)"
/>
</template>
<template v-if="keyword.trim() === ''" #empty>
<div class="flex items-center justify-center p-[8px] text-[var(--color-text-4)]">
{{ t('project.fileManagement.tableNoFile') }}
<MsButton class="ml-[8px]" @click="handleAddClick">
{{ t('project.fileManagement.addFile') }}
</MsButton>
</div>
</template>
</ms-base-table>
<MsCardList
v-else-if="showType === 'card'"
ref="cardListRef"
mode="remote"
:remote-func="getFileList"
:remote-params="{
projectId: appStore.currentProjectId,
moduleId: props.activeFolder,
fileType: tableFileType,
keyword,
}"
:shadow-limit="50"
:card-min-width="102"
class="flex-1"
>
<template #item="{ item, index }">
<MsThumbnailCard
:type="item.fileType"
:url="`http://172.16.200.18:8081${item.previewSrc}.${item.fileType}`"
:footer-text="item.name"
:more-actions="item.fileType === 'JAR' ? jarFileActions : normalFileActions"
@click="openFileDetail(item.id, index)"
@action-select="handleMoreActionSelect($event, item)"
/>
</template>
</MsCardList>
</a-spin>
</div>
<MsDrawer v-model:visible="uploadDrawerVisible" :title="t('project.fileManagement.addFile')" :width="680">
<div class="mb-[8px] flex items-center justify-between text-[var(--color-text-1)]">
@ -126,6 +136,11 @@
<MsFileList
ref="fileListRef"
v-model:file-list="fileList"
:upload-func="uploadFile"
:request-params="{
projectId: appStore.currentProjectId,
moduleId: ['my', 'all'].includes(props.activeFolder) ? 'root' : props.activeFolder, // id, my/all
}"
:route="RouteEnum.PROJECT_MANAGEMENT_FILE_MANAGEMENT"
:route-query="{ position: 'uploadDrawer' }"
@start="handleUploadStart"
@ -256,11 +271,10 @@
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, MsTableColumn } from '@/components/pure/ms-table/type';
import type { BatchActionParams, BatchActionQueryParams, MsTableColumn } from '@/components/pure/ms-table/type';
import useTable from '@/components/pure/ms-table/useTable';
import MsTableMoreAction from '@/components/pure/ms-table-more-action/index.vue';
import type { ActionsItem } from '@/components/pure/ms-table-more-action/types';
import MsTagGroup from '@/components/pure/ms-tag/ms-tag-group.vue';
import MsFileList from '@/components/pure/ms-upload/fileList.vue';
import MsUpload from '@/components/pure/ms-upload/index.vue';
import type { MsFileItem, UploadType } from '@/components/pure/ms-upload/types';
@ -270,13 +284,23 @@
import fileDetailDrawerVue from './fileDetailDrawer.vue';
import folderTree from './folderTree.vue';
import { getFileList } from '@/api/modules/project-management/fileManagement';
import {
batchDownloadFile,
deleteFile,
downloadFile,
getFileList,
updateFile,
uploadFile,
} from '@/api/modules/project-management/fileManagement';
import { useI18n } from '@/hooks/useI18n';
import useModal from '@/hooks/useModal';
import useAppStore from '@/store/modules/app';
import useAsyncTaskStore from '@/store/modules/app/asyncTask';
import useTableStore from '@/store/modules/ms-table';
import { characterLimit, downloadUrlFile } from '@/utils';
import useUserStore from '@/store/modules/user';
import { characterLimit, downloadByteFile } from '@/utils';
import type { FileItem, FileListQueryParams } from '@/models/projectManagement/file';
import { RouteEnum } from '@/enums/routeEnum';
import { TableKeyEnum } from '@/enums/tableEnum';
import { UploadStatus } from '@/enums/uploadEnum';
@ -284,18 +308,27 @@
import type { FormInstance } from '@arco-design/web-vue';
const props = defineProps<{
activeFolder: string | number;
activeFolder: string;
activeFolderType: 'folder' | 'module' | 'storage';
}>();
const emit = defineEmits<{
(e: 'init', params: FileListQueryParams): void;
}>();
const route = useRoute();
const { t } = useI18n();
const appStore = useAppStore();
const userStore = useUserStore();
const asyncTaskStore = useAsyncTaskStore();
const { openModal } = useModal();
const fileType = ref('module'); // /
const acceptType = ref<UploadType>('none'); // -
const isUploading = ref(false);
const keyword = ref('');
const tableFileType = ref('');
const tableFileTypeOptions = ref(['JPG', 'PNG']);
const loading = ref(false);
watch(
() => props.activeFolderType,
@ -312,8 +345,6 @@
const showType = ref<'list' | 'card'>('list'); //
function changeShowType() {}
function getCardClass(type: 'none' | 'jar') {
if (acceptType.value !== type && isUploading.value) {
return 'file-type-card file-type-card--disabled';
@ -363,16 +394,16 @@
title: 'project.fileManagement.name',
slotName: 'name',
dataIndex: 'name',
showTooltip: true,
width: 200,
},
{
title: 'project.fileManagement.type',
dataIndex: 'type',
dataIndex: 'fileType',
width: 90,
},
{
title: 'project.fileManagement.tag',
dataIndex: 'tag',
dataIndex: 'tags',
slotName: 'tag',
isTag: true,
},
@ -383,7 +414,7 @@
},
{
title: 'project.fileManagement.updater',
dataIndex: 'updater',
dataIndex: 'updateUser',
showTooltip: true,
},
{
@ -452,17 +483,61 @@
tableSelected.value = arr;
}
function batchDownload() {}
/**
* 批量下载文件
* @param params 批量操作参数
*/
async function batchDownload(params: BatchActionQueryParams) {
try {
loading.value = true;
const res = await batchDownloadFile({
selectIds: params?.selectedIds || [],
selectAll: !!params?.selectAll,
excludeIds: params?.excludeIds || [],
condition: { keyword: keyword.value },
projectId: appStore.currentProjectId,
fileType: tableFileType.value,
moduleIds: [props.activeFolder],
});
downloadByteFile(res, 'files.zip');
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
} finally {
loading.value = false;
}
}
function emitTableParams() {
emit('init', {
keyword: keyword.value,
fileType: tableFileType.value,
moduleIds: ['all', 'my'].includes(props.activeFolder) ? [] : [props.activeFolder],
projectId: appStore.currentProjectId,
current: propsRes.value.msPagination?.current,
pageSize: propsRes.value.msPagination?.pageSize,
comebine:
props.activeFolder === 'my'
? {
createUser: userStore.id,
}
: {},
});
}
const cardListRef = ref<InstanceType<typeof MsCardList>>();
/**
* 删除文件
*/
function delFile(record: any, isBatch?: boolean) {
function delFile(record: FileItem | null, isBatch: boolean, params?: BatchActionQueryParams) {
let title = t('project.fileManagement.deleteFileTipTitle', { name: characterLimit(record?.name) });
let selectIds = [record?.id];
let selectIds = [record?.id || ''];
if (isBatch) {
title = t('project.fileManagement.batchDeleteFileTipTitle', { count: tableSelected.value.length });
selectIds = tableSelected.value as string[];
title = t('project.fileManagement.batchDeleteFileTipTitle', {
count: params?.currentSelectCount || params?.selectedIds?.length,
});
selectIds = params?.selectedIds || [];
}
openModal({
type: 'error',
@ -476,11 +551,24 @@
maskClosable: false,
onBeforeOk: async () => {
try {
console.log(selectIds);
await deleteFile({
selectIds,
selectAll: !!params?.selectAll,
excludeIds: params?.excludeIds || [],
condition: { keyword: keyword.value },
projectId: appStore.currentProjectId,
fileType: tableFileType.value,
moduleIds: [props.activeFolder],
});
Message.success(t('common.deleteSuccess'));
loadList();
if (showType.value === 'card') {
cardListRef.value?.reload();
} else {
loadList();
}
emitTableParams();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
},
@ -491,7 +579,7 @@
const moveModalVisible = ref(false); //
const selectedModuleKeys = ref<(string | number)[]>([]); //
const isBatchMove = ref(false); //
const activeFile = ref<any>(null); //
const activeFile = ref<FileItem | null>(null); //
/**
* 处理文件夹树节点选中事件
@ -504,17 +592,18 @@
* 处理表格选中后批量操作
* @param event 批量操作事件对象
*/
function handleTableBatch(event: BatchActionParams) {
function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) {
tableSelected.value = params?.selectedIds || [];
switch (event.eventTag) {
case 'download':
batchDownload();
batchDownload(params);
break;
case 'move':
moveModalVisible.value = true;
isBatchMove.value = true;
break;
case 'delete':
delFile(null, true);
delFile(null, true, params);
break;
default:
break;
@ -538,7 +627,12 @@
} else {
activeFile.value = null;
}
loadList();
if (showType.value === 'card') {
cardListRef.value?.reload();
} else {
loadList();
}
emitTableParams();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
@ -552,16 +646,25 @@
selectedModuleKeys.value = [];
}
const keyword = ref('');
const tableFileType = ref('');
const tableFileTypeOptions = ref(['JPG', 'PNG']);
const searchList = debounce(() => {
setLoadListParams({
fileType: tableFileType.value,
keyword: keyword.value,
fileType: tableFileType.value,
moduleIds: ['all', 'my'].includes(props.activeFolder) ? [] : [props.activeFolder],
projectId: appStore.currentProjectId,
comebine:
props.activeFolder === 'my'
? {
createUser: userStore.id,
}
: {},
});
loadList();
if (showType.value === 'card') {
cardListRef.value?.reload();
} else {
loadList();
}
emitTableParams();
}, 300);
watch(
@ -580,14 +683,27 @@
}
);
function downloadFile(url: string, name: string) {
downloadUrlFile(url, name);
/**
* 下载单个文件
* @param record 表格数据项
*/
async function handleDownload(record: FileItem) {
try {
loading.value = true;
const res = await downloadFile(record.id);
downloadByteFile(res, `${record.name}.${record.fileType}`);
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
} finally {
loading.value = false;
}
}
/**
* 禁用 jar 文件
*/
function disabledFile(record: any) {
function disabledFile(record: FileItem) {
openModal({
type: 'warning',
title: t('project.fileManagement.disabledFileTipTitle', { name: characterLimit(record.name) }),
@ -598,8 +714,13 @@
onBeforeOk: async () => {
try {
Message.success(t('common.disableSuccess'));
loadList();
if (showType.value === 'card') {
cardListRef.value?.reload();
} else {
loadList();
}
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
},
@ -611,7 +732,7 @@
* 处理表格更多按钮事件
* @param item
*/
function handleMoreActionSelect(item: ActionsItem, record: any) {
function handleMoreActionSelect(item: ActionsItem, record: FileItem) {
switch (item.eventTag) {
case 'move':
isBatchMove.value = false;
@ -619,7 +740,7 @@
moveModalVisible.value = true;
break;
case 'delete':
delFile(record);
delFile(record, false);
break;
case 'disabled':
disabledFile(record);
@ -630,10 +751,10 @@
}
const showDetailDrawer = ref(false);
const activeFileId = ref<string | number>('');
const activeFileId = ref<string>('');
const activeFileIndex = ref(0);
async function openFileDetail(id: string | number, index: number) {
async function openFileDetail(id: string, index: number) {
showDetailDrawer.value = true;
activeFileId.value = id;
activeFileIndex.value = index;
@ -721,6 +842,7 @@
fileList.value = [];
isUploading.value = false;
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
},
@ -758,6 +880,21 @@
}
);
watch(
() => asyncTaskStore.uploadFileTask.finishedTime,
() => {
if (asyncTaskStore.uploadFileTask.finishedTime) {
//
if (showType.value === 'card') {
cardListRef.value?.reload();
} else {
loadList();
}
emitTableParams();
}
}
);
const storageDialogVisible = ref(false); // -
const storageForm = ref({
branch: '',
@ -796,7 +933,11 @@
if (!isContinue) {
storageDialogVisible.value = false;
}
loadList();
if (showType.value === 'card') {
cardListRef.value?.reload();
} else {
loadList();
}
}
/**

View File

@ -31,6 +31,7 @@
<template #itemAction="{ item }">
<popConfirm
mode="rename"
:parent-id="item.key"
:field-config="{ field: renameStorageTitle }"
:all-names="[]"
@close="resetFocusItemKey"
@ -619,7 +620,7 @@
}
}
async function saveStorage(isContinue: boolean) {}
// async function saveStorage(isContinue: boolean) {}
/**
* 处理抽屉确认
@ -628,7 +629,7 @@
function handleDrawerConfirm(isContinue: boolean) {
storageFormRef.value?.validate(async (errors: Record<string, ValidatedError> | undefined) => {
if (!errors) {
saveStorage(isContinue);
// saveStorage(isContinue);
}
});
}

View File

@ -37,7 +37,12 @@
<a-doption value="storage">{{ t('project.fileManagement.addStorage') }}</a-doption>
</template>
</a-dropdown>
<popConfirm mode="add" :all-names="[]">
<popConfirm
mode="add"
:all-names="rootModulesName"
parent-id="none"
@add-finish="handleAddRootModuleFinish"
>
<span id="allPlus" class="invisible"></span>
</popConfirm>
</div>
@ -49,8 +54,10 @@
</a-radio-group>
<div v-show="showType === 'Module'">
<FolderTree
ref="folderTreeRef"
v-model:selected-keys="selectedKeys"
:is-expand-all="isExpandAll"
@init="setRootModules"
@folder-node-select="folderNodeSelect"
/>
</div>
@ -64,7 +71,7 @@
</div>
</template>
<template #right>
<rightBox :active-folder="activeFolder" :active-folder-type="activeFolderType" />
<rightBox :active-folder="activeFolder" :active-folder-type="activeFolderType" @init="handleModuleTableInit" />
</template>
</MsSplitBox>
</div>
@ -87,6 +94,8 @@
import { useI18n } from '@/hooks/useI18n';
import { FileListQueryParams } from '@/models/projectManagement/file';
const { t } = useI18n();
const myFileCount = ref(0);
@ -94,6 +103,7 @@
const isExpandAll = ref(false);
const activeFolderType = ref<'folder' | 'module' | 'storage'>('folder');
const storageDrawerVisible = ref(false);
const rootModulesName = ref<string[]>([]); //
function changeExpand() {
isExpandAll.value = !isExpandAll.value;
@ -111,7 +121,7 @@
}
}
const activeFolder = ref<string | number>('all');
const activeFolder = ref<string>('all');
const selectedKeys = computed({
get: () => [activeFolder.value],
set: (val) => val,
@ -140,7 +150,7 @@
/**
* 处理文件夹树节点选中事件
*/
function folderNodeSelect(keys: (string | number)[]) {
function folderNodeSelect(keys: string[]) {
[activeFolder.value] = keys;
activeFolderType.value = 'module';
}
@ -148,10 +158,37 @@
/**
* 处理存储库列表项选中事件
*/
function storageItemSelect(key: string | number) {
function storageItemSelect(key: string) {
activeFolder.value = key;
activeFolderType.value = 'storage';
}
/**
* 设置根模块名称列表
* @param names 根模块名称列表
*/
function setRootModules(names: string[]) {
rootModulesName.value = names;
}
const folderTreeRef = ref<InstanceType<typeof FolderTree>>();
/**
* 添加根模块后若当前展示的是模块则刷新模块树
*/
function handleAddRootModuleFinish() {
if (showType.value === 'Module') {
folderTreeRef.value?.initModules();
}
}
/**
* 右侧表格数据刷新后若当前展示的是模块则刷新模块树的统计数量
*/
function handleModuleTableInit(params: FileListQueryParams) {
if (showType.value === 'Module') {
folderTreeRef.value?.initModulesCount(params);
}
}
</script>
<style lang="less" scoped>

View File

@ -10,6 +10,7 @@ export default {
'project.fileManagement.nameNotNull': 'name cannot be empty',
'project.fileManagement.namePlaceholder': 'Please enter the group name and press Enter to save',
'project.fileManagement.renameSuccess': 'Rename successful',
'project.fileManagement.updateDescSuccess': 'File description updated successfully',
'project.fileManagement.addSubModuleSuccess': 'Added successfully',
'project.fileManagement.nameExist': 'This module name already exists at this level',
'project.fileManagement.module': 'Module',
@ -123,4 +124,5 @@ export default {
'project.fileManagement.batchMoveSearchPlaceholder': 'Please enter the module name to search',
'project.fileManagement.batchMoveConfirm': 'Move to selected module',
'project.fileManagement.batchMoveSuccess': 'File moved successfully',
'project.fileManagement.moduleMoveSuccess': 'Module moved successfully',
};

View File

@ -10,6 +10,7 @@ export default {
'project.fileManagement.nameNotNull': '名字不能为空',
'project.fileManagement.namePlaceholder': '请输入分组名称,按回车键保存',
'project.fileManagement.renameSuccess': '重命名成功',
'project.fileManagement.updateDescSuccess': '文件描述更新成功',
'project.fileManagement.addSubModuleSuccess': '添加成功',
'project.fileManagement.nameExist': '该层级已有此模块名称',
'project.fileManagement.module': '模块',
@ -115,4 +116,5 @@ export default {
'project.fileManagement.batchMoveSearchPlaceholder': '请输入模块名称进行搜索',
'project.fileManagement.batchMoveConfirm': '移动至所选模块',
'project.fileManagement.batchMoveSuccess': '文件移动成功',
'project.fileManagement.moduleMoveSuccess': '模块移动成功',
};

View File

@ -211,7 +211,12 @@
// 使 {{name}}
function replacePreviewName(str: string) {
return str.replace(/{{(.*?)}}/g, `<span style='color: rgb(var(--primary-6))'><$1></span>`).replace(/\n/g, '<br>');
return str
.replace(/<|>/g, (match) => {
return match === '<' ? '&lt;' : '&gt;';
})
.replace(/{{(.*?)}}/g, `<span style='color: rgb(var(--primary-6))'>&lt;$1&gt;</span>`)
.replace(/\n/g, '<br>');
}
const subject = computed(() => {

View File

@ -492,11 +492,17 @@
}
function handleNameClick(record: LogItem) {
const routeQuery = {
const routeQuery: Record<string, any> = {
organizationId: record.organizationId,
projectId: record.projectId,
id: record.sourceId,
};
if (record.organizationId === 'SYSTEM') {
delete routeQuery.organizationId;
}
if (record.projectId === 'SYSTEM' || record.projectId === 'ORGANIZATION') {
delete routeQuery.projectId;
}
jumpRouteByMapKey(record.module, routeQuery, true);
}

View File

@ -29,7 +29,8 @@
</MsCard>
<MsDrawer
v-model:visible="showDetailDrawer"
:width="480"
width="40vw"
min-width="480px"
:title="activePool?.name"
:title-tag="activePool?.enable ? t('system.resourcePool.tableEnable') : t('system.resourcePool.tableDisable')"
:title-tag-color="activePool?.enable ? 'green' : 'gray'"

View File

@ -25,7 +25,6 @@
title: 'name',
children: 'children',
disabled: 'disabled',
isLeaf: 'leafNode',
}"
show-search
/>