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": { "dependencies": {
"@7polo/kity": "2.0.8", "@7polo/kity": "2.0.8",
"@7polo/kityminder-core": "1.4.53", "@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", "@arco-themes/vue-ms-theme-default": "^0.0.30",
"@form-create/arco-design": "^3.1.23", "@form-create/arco-design": "^3.1.23",
"@halo-dev/richtext-editor": "0.0.0-alpha.32", "@halo-dev/richtext-editor": "0.0.0-alpha.32",

View File

@ -1,831 +1,96 @@
import MSR from '@/api/http/index'; 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>> { export function getFileList(data: FileListQueryParams) {
// return MSR.post<CommonList<any>>({ url: FileListUrl, data }); return MSR.post<CommonList<FileItem>>({ url: FilePageUrl, data });
return Promise.resolve({
total: 100,
list: fileList,
pageSize: 10,
current: 1,
});
} }
// 获取文件详情 // 获取文件列表
export function getFileDetail(id: string | number) { export function getModulesCount(data: FileListQueryParams) {
// return MSR.post<CommonList<any>>({ url: FileDetailUrl, data }); return MSR.post<ModuleCount>({ url: GetModuleCountUrl, data });
return Promise.resolve(fileList.find((item) => item.id === id));
} }
// 获取文件关联用例列表 // 上传文件
export function getFileCases(data: TableQueryParams) { export function uploadFile(data: UploadFileParams) {
// return MSR.post<CommonList<any>>({ url: FileDetailUrl, data }); return MSR.uploadFile({ url: UploadFileUrl }, { request: data.request, fileList: [data.file] });
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 getFileVersions(data: TableQueryParams) { export function updateFile(data: UpdateFileParams) {
// return MSR.post<CommonList<any>>({ url: FileDetailUrl, data }); return MSR.post({ url: UpdateFileUrl, data });
return Promise.resolve({ }
total: 1,
list: [ // 重新上传文件
{ export function reuploadFile(data: ReuploadFileParams) {
id: 1, return MSR.uploadFile({ url: ReuploadFileUrl }, { request: data.request, fileList: [data.file] });
version: 'd08hf034f3', }
record: 'fuih03h4f0ihoiw',
creator: '创建人', // 删除文件
createTime: 18975439859, export function deleteFile(data: BatchFileApiParams) {
}, return MSR.post({ url: DeleteFileUrl, data });
{ }
id: 1,
version: 'd08hf034f3', // 下载文件
record: 'fuih03h4f0ihoiw', export function downloadFile(id: string) {
creator: '创建人', return MSR.get({ url: DownloadFileUrl, params: id }, { isTransformResponse: false });
createTime: 18975439859, }
},
], // 批量下载文件
pageSize: 10, export function batchDownloadFile(data: BatchFileApiParams) {
current: 1, 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 UploadFileUrl = '/project/file/upload'; // 上传文件
export const FileDetailUrl = '/project/member/get-member/option'; 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> </template>
<script setup lang="ts"> <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 { useResizeObserver } from '@vueuse/core';
import { debounce } from 'lodash-es'; import { debounce } from 'lodash-es';
@ -95,13 +95,12 @@
const listPage = ref(0); const listPage = ref(0);
const listTotal = ref(0); const listTotal = ref(0);
const remoteList = ref<any[]>([]); const remoteList = ref<any[]>([]);
const noMore = computed(() => { const noMore = ref(false);
return listSize.value * (listPage.value - 1) + remoteList.value.length >= listTotal.value;
});
const isInit = ref(false); const isInit = ref(false);
const topLoading = ref(false); const topLoading = ref(false);
const bottomLoading = 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 { try {
if (props.mode === 'remote' && typeof props.remoteFunc === 'function') { if (props.mode === 'remote' && typeof props.remoteFunc === 'function') {
bottomLoading.value = true; bottomLoading.value = true;
listPage.value += 1; listPage.value += 1;
if (isReload) {
listPage.value = 1;
}
const res = await props.remoteFunc({ const res = await props.remoteFunc({
current: listPage.value, current: listPage.value,
pageSize: listSize.value, pageSize: listSize.value,
...(props.remoteParams || {}),
}); });
remoteList.value = res.list; remoteList.value = isReload ? res.list : remoteList.value.concat(res.list);
listTotal.value = res.total; listTotal.value = res.total;
bottomLoading.value = false; bottomLoading.value = false;
noMore.value = listSize.value * (listPage.value - 1) + remoteList.value.length >= listTotal.value;
} }
} catch (error) { } catch (error) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log(error); console.log(error);
isLoadError.value = true;
} finally { } finally {
bottomLoading.value = false; bottomLoading.value = false;
} }
@ -188,7 +194,7 @@
debounce((entries) => { debounce((entries) => {
const entry = entries[0]; const entry = entries[0];
const { width, height } = entry.contentRect; const { width, height } = entry.contentRect;
if (isInit.value) { if (isInit.value && !isLoadError.value && !noMore.value) {
computedListSize(width, height); computedListSize(width, height);
} }
}, 300) }, 300)
@ -207,12 +213,26 @@
if (isArrivedTop.value && !isArrivedBottom.value && listPage.value > 1 && !topLoading.value) { if (isArrivedTop.value && !isArrivedBottom.value && listPage.value > 1 && !topLoading.value) {
// 1 // 1
loadPrevList(); loadPrevList();
} else if (isArrivedBottom.value && !isArrivedTop.value && !noMore.value && !bottomLoading.value) { } else if (
isArrivedBottom.value &&
!isArrivedTop.value &&
!noMore.value &&
!bottomLoading.value &&
!isLoadError.value
) {
// 1 // 1
loadNextList(); loadNextList();
} }
} }
}); });
function reload() {
loadNextList(true);
}
defineExpose({
reload,
});
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

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

View File

@ -4,11 +4,17 @@
<div class="ms-thumbnail-card-more"> <div class="ms-thumbnail-card-more">
<MsTableMoreAction v-if="props.moreActions" :list="props.moreActions" @select="handleMoreActionSelect" /> <MsTableMoreAction v-if="props.moreActions" :list="props.moreActions" @select="handleMoreActionSelect" />
</div> </div>
<img v-if="fileType === 'image'" :src="props.url" class="absolute top-0" /> <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]" /> <MsIcon
<div class="ms-thumbnail-card-footer"> v-else
{{ props.footerText }} :type="FileIconMap[fileType][UploadStatus.done]"
</div> 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>
</div> </div>
</template> </template>
@ -58,14 +64,14 @@
<style lang="less" scoped> <style lang="less" scoped>
.ms-thumbnail-card { .ms-thumbnail-card {
@apply relative w-full; @apply relative w-full overflow-hidden;
border-radius: var(--border-radius-small);
aspect-ratio: 1/1; aspect-ratio: 1/1;
.ms-thumbnail-card-content { .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; min-width: 102px;
border-radius: var(--border-radius-small);
background-color: var(--color-text-n9); background-color: var(--color-text-n9);
transition: all 0.2s; transition: all 0.2s;
&::before { &::before {
@ -96,7 +102,7 @@
@apply absolute w-full text-center; @apply absolute w-full text-center;
bottom: 0; bottom: 0;
padding: 2px 0; padding: 2px 4px;
font-size: 12px; font-size: 12px;
font-weight: 500; font-weight: 500;
color: #ffffff; color: #ffffff;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,8 @@
<template> <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 <a-table
v-bind="$attrs" v-bind="$attrs"
:row-class="getRowClass" :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) { :deep(.ms-table-select-all) {
.dropdown-icon { .dropdown-icon {
background: none !important; background: none !important;

View File

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

View File

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

View File

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

View File

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

View File

@ -2,8 +2,7 @@
<router-view v-slot="{ Component, route }"> <router-view v-slot="{ Component, route }">
<transition name="fade" mode="out-in" appear> <transition name="fade" mode="out-in" appear>
<!-- transition内必须有且只有一个根元素不然会导致二级路由的组件无法渲染 --> <!-- transition内必须有且只有一个根元素不然会导致二级路由的组件无法渲染 -->
<!-- eslint-disable-next-line vue/require-toggle-inside-transition --> <div v-show="true" class="page-content">
<div class="page-content">
<component :is="Component" v-if="!route.meta.isCache" :key="route.fullPath" /> <component :is="Component" v-if="!route.meta.isCache" :key="route.fullPath" />
<keep-alive v-else> <keep-alive v-else>
<component :is="Component" :key="route.fullPath" /> <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, // 是否后台上传,后台上传会展示全局提示类型的进度提示 isBackstageUpload: false, // 是否后台上传,后台上传会展示全局提示类型的进度提示
isHideMessage: false, // 后台上传时展示的消息提示在点击关闭后无需再弹 isHideMessage: false, // 后台上传时展示的消息提示在点击关闭后无需再弹
fileList: [], // 文件总队列,包含已经上传的历史记录(不做持久化存储,刷新丢失) fileList: [], // 文件总队列,包含已经上传的历史记录(不做持久化存储,刷新丢失)
uploadFunc: undefined, // 上传文件时,自定义上传方法
requestParams: undefined, // 上传文件时,额外的请求参数
uploadQueue: [], // 每次添加的上传队列,用于展示每次任务的进度使用 uploadQueue: [], // 每次添加的上传队列,用于展示每次任务的进度使用
eachTaskQueue: [], // 上传队列,每个文件上传完成后会从队列中移除,初始值为上传队列的副本 eachTaskQueue: [], // 上传队列,每个文件上传完成后会从队列中移除,初始值为上传队列的副本
singleProgress: 0, // 单个上传文件的上传进度,非总进度,是每个文件在上传时的模拟进度 singleProgress: 0, // 单个上传文件的上传进度,非总进度,是每个文件在上传时的模拟进度
@ -67,6 +69,14 @@ const useAsyncTaskStore = defineStore('asyncTask', {
}, },
}, },
actions: { 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>) { beforeEachUpload(fileItem?: MsFileItem, route?: string, routeQuery?: Record<string, any>) {
const { t } = useI18n(); const { t } = useI18n();
const { uploadFileTask } = this; const { uploadFileTask } = this;
@ -161,6 +171,8 @@ const useAsyncTaskStore = defineStore('asyncTask', {
uploadFileTask: { uploadFileTask: {
isBackstageUpload: false, isBackstageUpload: false,
isHideMessage: 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>) { async uploadFileFromQueue(fileItem?: MsFileItem, route?: string, routeQuery?: Record<string, any>) {
this.beforeEachUpload(fileItem, route, routeQuery); this.beforeEachUpload(fileItem, route, routeQuery);
try { try {
// TODO: 模拟上传,待接口联调后替换为真实上传逻辑 if (this.uploadFileTask.uploadFunc) {
await new Promise((resolve) => { await this.uploadFileTask.uploadFunc({
setTimeout(() => { request: { ...this.uploadFileTask.requestParams },
resolve(null); file: unref(fileItem)?.file,
}, 3000); });
}); } else {
throw new Error('uploadFunc is not defined');
}
if (fileItem) { if (fileItem) {
fileItem.status = UploadStatus.done; fileItem.status = UploadStatus.done;
fileItem.uploadedTime = Date.now(); fileItem.uploadedTime = Date.now();
@ -219,6 +233,8 @@ const useAsyncTaskStore = defineStore('asyncTask', {
fileList: [], fileList: [],
uploadQueue: [], uploadQueue: [],
singleProgress: 0, singleProgress: 0,
uploadFunc: undefined,
requestParams: undefined,
}, },
}); });
}, },

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -37,7 +37,12 @@
<a-doption value="storage">{{ t('project.fileManagement.addStorage') }}</a-doption> <a-doption value="storage">{{ t('project.fileManagement.addStorage') }}</a-doption>
</template> </template>
</a-dropdown> </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> <span id="allPlus" class="invisible"></span>
</popConfirm> </popConfirm>
</div> </div>
@ -49,8 +54,10 @@
</a-radio-group> </a-radio-group>
<div v-show="showType === 'Module'"> <div v-show="showType === 'Module'">
<FolderTree <FolderTree
ref="folderTreeRef"
v-model:selected-keys="selectedKeys" v-model:selected-keys="selectedKeys"
:is-expand-all="isExpandAll" :is-expand-all="isExpandAll"
@init="setRootModules"
@folder-node-select="folderNodeSelect" @folder-node-select="folderNodeSelect"
/> />
</div> </div>
@ -64,7 +71,7 @@
</div> </div>
</template> </template>
<template #right> <template #right>
<rightBox :active-folder="activeFolder" :active-folder-type="activeFolderType" /> <rightBox :active-folder="activeFolder" :active-folder-type="activeFolderType" @init="handleModuleTableInit" />
</template> </template>
</MsSplitBox> </MsSplitBox>
</div> </div>
@ -87,6 +94,8 @@
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import { FileListQueryParams } from '@/models/projectManagement/file';
const { t } = useI18n(); const { t } = useI18n();
const myFileCount = ref(0); const myFileCount = ref(0);
@ -94,6 +103,7 @@
const isExpandAll = ref(false); const isExpandAll = ref(false);
const activeFolderType = ref<'folder' | 'module' | 'storage'>('folder'); const activeFolderType = ref<'folder' | 'module' | 'storage'>('folder');
const storageDrawerVisible = ref(false); const storageDrawerVisible = ref(false);
const rootModulesName = ref<string[]>([]); //
function changeExpand() { function changeExpand() {
isExpandAll.value = !isExpandAll.value; isExpandAll.value = !isExpandAll.value;
@ -111,7 +121,7 @@
} }
} }
const activeFolder = ref<string | number>('all'); const activeFolder = ref<string>('all');
const selectedKeys = computed({ const selectedKeys = computed({
get: () => [activeFolder.value], get: () => [activeFolder.value],
set: (val) => val, set: (val) => val,
@ -140,7 +150,7 @@
/** /**
* 处理文件夹树节点选中事件 * 处理文件夹树节点选中事件
*/ */
function folderNodeSelect(keys: (string | number)[]) { function folderNodeSelect(keys: string[]) {
[activeFolder.value] = keys; [activeFolder.value] = keys;
activeFolderType.value = 'module'; activeFolderType.value = 'module';
} }
@ -148,10 +158,37 @@
/** /**
* 处理存储库列表项选中事件 * 处理存储库列表项选中事件
*/ */
function storageItemSelect(key: string | number) { function storageItemSelect(key: string) {
activeFolder.value = key; activeFolder.value = key;
activeFolderType.value = 'storage'; 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> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -10,6 +10,7 @@ export default {
'project.fileManagement.nameNotNull': 'name cannot be empty', 'project.fileManagement.nameNotNull': 'name cannot be empty',
'project.fileManagement.namePlaceholder': 'Please enter the group name and press Enter to save', 'project.fileManagement.namePlaceholder': 'Please enter the group name and press Enter to save',
'project.fileManagement.renameSuccess': 'Rename successful', 'project.fileManagement.renameSuccess': 'Rename successful',
'project.fileManagement.updateDescSuccess': 'File description updated successfully',
'project.fileManagement.addSubModuleSuccess': 'Added successfully', 'project.fileManagement.addSubModuleSuccess': 'Added successfully',
'project.fileManagement.nameExist': 'This module name already exists at this level', 'project.fileManagement.nameExist': 'This module name already exists at this level',
'project.fileManagement.module': 'Module', 'project.fileManagement.module': 'Module',
@ -123,4 +124,5 @@ export default {
'project.fileManagement.batchMoveSearchPlaceholder': 'Please enter the module name to search', 'project.fileManagement.batchMoveSearchPlaceholder': 'Please enter the module name to search',
'project.fileManagement.batchMoveConfirm': 'Move to selected module', 'project.fileManagement.batchMoveConfirm': 'Move to selected module',
'project.fileManagement.batchMoveSuccess': 'File moved successfully', '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.nameNotNull': '名字不能为空',
'project.fileManagement.namePlaceholder': '请输入分组名称,按回车键保存', 'project.fileManagement.namePlaceholder': '请输入分组名称,按回车键保存',
'project.fileManagement.renameSuccess': '重命名成功', 'project.fileManagement.renameSuccess': '重命名成功',
'project.fileManagement.updateDescSuccess': '文件描述更新成功',
'project.fileManagement.addSubModuleSuccess': '添加成功', 'project.fileManagement.addSubModuleSuccess': '添加成功',
'project.fileManagement.nameExist': '该层级已有此模块名称', 'project.fileManagement.nameExist': '该层级已有此模块名称',
'project.fileManagement.module': '模块', 'project.fileManagement.module': '模块',
@ -115,4 +116,5 @@ export default {
'project.fileManagement.batchMoveSearchPlaceholder': '请输入模块名称进行搜索', 'project.fileManagement.batchMoveSearchPlaceholder': '请输入模块名称进行搜索',
'project.fileManagement.batchMoveConfirm': '移动至所选模块', 'project.fileManagement.batchMoveConfirm': '移动至所选模块',
'project.fileManagement.batchMoveSuccess': '文件移动成功', 'project.fileManagement.batchMoveSuccess': '文件移动成功',
'project.fileManagement.moduleMoveSuccess': '模块移动成功',
}; };

View File

@ -211,7 +211,12 @@
// 使 {{name}} // 使 {{name}}
function replacePreviewName(str: string) { 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(() => { const subject = computed(() => {

View File

@ -492,11 +492,17 @@
} }
function handleNameClick(record: LogItem) { function handleNameClick(record: LogItem) {
const routeQuery = { const routeQuery: Record<string, any> = {
organizationId: record.organizationId, organizationId: record.organizationId,
projectId: record.projectId, projectId: record.projectId,
id: record.sourceId, 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); jumpRouteByMapKey(record.module, routeQuery, true);
} }

View File

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

View File

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