feat(文件管理): 文件管理部分接口&部分组件调整

This commit is contained in:
baiqi 2023-11-01 15:23:15 +08:00 committed by Craftsman
parent 289464050c
commit 7680537fc6
13 changed files with 135 additions and 97 deletions

View File

@ -95,6 +95,7 @@ module.exports = {
'^jsencrypt$', '^jsencrypt$',
'^echarts$', '^echarts$',
'^color$', '^color$',
'^localforage$',
], // node依赖 ], // node依赖
['.*/assets/.*', '^@/assets$'], // 项目静态资源 ['.*/assets/.*', '^@/assets$'], // 项目静态资源
['^@/components/pure/.*', '^@/components/business/.*', '.*\\.vue$'], // 组件 ['^@/components/pure/.*', '^@/components/business/.*', '.*\\.vue$'], // 组件

View File

@ -2,6 +2,7 @@ import MSR from '@/api/http/index';
import { import {
AddModuleUrl, AddModuleUrl,
BatchDownloadFileUrl, BatchDownloadFileUrl,
BatchMoveFileUrl,
DeleteFileUrl, DeleteFileUrl,
DeleteModuleUrl, DeleteModuleUrl,
DownloadFileUrl, DownloadFileUrl,
@ -113,3 +114,8 @@ export function getFileDetail(id: string) {
export function toggleJarFileStatus(id: string, status: boolean) { export function toggleJarFileStatus(id: string, status: boolean) {
return MSR.get({ url: `${ToggleJarFileUrl}/${id}/${status}` }); return MSR.get({ url: `${ToggleJarFileUrl}/${id}/${status}` });
} }
// 批量移动文件
export function batchMoveFile(data: BatchFileApiParams) {
return MSR.post({ url: BatchMoveFileUrl, data });
}

View File

@ -16,3 +16,4 @@ export const CompressImgUrl = '/file/preview/compressed'; // 预览图片文件
export const GetFileTypesUrl = '/project/file/type'; // 获取文件类型集合 export const GetFileTypesUrl = '/project/file/type'; // 获取文件类型集合
export const GetFileDetailUrl = '/project/file/get'; // 查看文件详情 export const GetFileDetailUrl = '/project/file/get'; // 查看文件详情
export const ToggleJarFileUrl = '/project/file/jar-file-status'; // jar 文件启用禁用 export const ToggleJarFileUrl = '/project/file/jar-file-status'; // jar 文件启用禁用
export const BatchMoveFileUrl = '/project/file/batch-move'; // jar 文件启用禁用

View File

@ -532,52 +532,6 @@
} }
} }
/** 穿梭框 **/
.arco-transfer {
@apply grid;
grid-template-columns: 4fr 1fr 4fr;
.arco-transfer-view {
@apply w-auto;
height: 370px;
.arco-transfer-view-header {
@apply bg-white;
}
}
.arco-transfer-operations {
.arco-btn-secondary {
border-color: rgb(var(--primary-5));
border-radius: var(--border-radius-small);
background-color: rgb(var(--primary-1)) !important;
.arco-btn-icon {
color: rgb(var(--primary-5));
}
&:disabled {
border-color: var(--color-text-input-border) !important;
background-color: var(--color-text-n8) !important;
.arco-btn-icon {
color: var(--color-text-4);
}
}
&:not(:disabled):hover {
border-color: rgb(var(--primary-4)) !important;
background-color: rgb(var(--primary-1)) !important;
.arco-btn-icon {
color: rgb(var(--primary-7));
}
}
&:not(:disabled):active {
border-color: rgb(var(--primary-7)) !important;
background-color: rgb(var(--primary-9)) !important;
.arco-btn-icon {
color: rgb(var(--primary-7));
}
}
}
}
}
/** 滚动条 **/ /** 滚动条 **/
.arco-scrollbar-track-direction-horizontal { .arco-scrollbar-track-direction-horizontal {
height: 6px; height: 6px;
@ -768,22 +722,6 @@
} }
} }
/** 穿梭框节点溢出省略 **/
.arco-transfer {
.arco-tree-node-title-text {
overflow: hidden;
width: 206px;
text-overflow: ellipsis;
white-space: nowrap;
}
.arco-checkbox-label {
overflow: hidden;
width: 207px;
text-overflow: ellipsis;
white-space: nowrap;
}
}
/** Alter **/ /** Alter **/
.arco-alert-title { .arco-alert-title {
font-size: 14px; font-size: 14px;

View File

@ -20,7 +20,13 @@
block-node block-node
default-expand-all default-expand-all
@check="onSelect" @check="onSelect"
/> >
<template #title="nodeData">
<div class="one-line-text">
{{ nodeData.title }}
</div>
</template>
</MsTree>
</template> </template>
</a-transfer> </a-transfer>
</template> </template>
@ -45,6 +51,7 @@
data: MsTreeNodeData[]; // data: MsTreeNodeData[]; //
treeFiled?: MsTreeFieldNames; // treeFiled?: MsTreeFieldNames; //
showSearch?: boolean; // showSearch?: boolean; //
height?: string; // 穿
sourceInputSearchProps?: Record<string, any>; sourceInputSearchProps?: Record<string, any>;
targetInputSearchProps?: Record<string, any>; targetInputSearchProps?: Record<string, any>;
}>(), }>(),
@ -139,4 +146,46 @@
); );
</script> </script>
<style lang="less" scoped></style> <style lang="less">
/** 穿梭框 **/
.arco-transfer {
.arco-transfer-view {
width: calc(50% - 34px);
height: v-bind(height);
.arco-transfer-view-header {
@apply bg-white;
}
}
.arco-transfer-operations {
.arco-btn-secondary {
border-color: rgb(var(--primary-5));
border-radius: var(--border-radius-small);
background-color: rgb(var(--primary-1)) !important;
.arco-btn-icon {
color: rgb(var(--primary-5));
}
&:disabled {
border-color: var(--color-text-input-border) !important;
background-color: var(--color-text-n8) !important;
.arco-btn-icon {
color: var(--color-text-4);
}
}
&:not(:disabled):hover {
border-color: rgb(var(--primary-4)) !important;
background-color: rgb(var(--primary-1)) !important;
.arco-btn-icon {
color: rgb(var(--primary-7));
}
}
&:not(:disabled):active {
border-color: rgb(var(--primary-7)) !important;
background-color: rgb(var(--primary-9)) !important;
.arco-btn-icon {
color: rgb(var(--primary-7));
}
}
}
}
}
</style>

View File

@ -13,7 +13,13 @@
@check="checked" @check="checked"
> >
<template v-if="$slots['title']" #title="_props"> <template v-if="$slots['title']" #title="_props">
<slot name="title" v-bind="_props"></slot> <a-tooltip
:content="_props[props.fieldNames.title]"
:mouse-enter-delay="500"
:position="props.titleTooltipPosition"
>
<slot name="title" v-bind="_props"></slot>
</a-tooltip>
</template> </template>
<template v-if="$slots['extra']" #extra="_props"> <template v-if="$slots['extra']" #extra="_props">
<div <div
@ -92,11 +98,26 @@
checkedStrategy?: 'all' | 'parent' | 'child'; // checkedStrategy?: 'all' | 'parent' | 'child'; //
checkedKeys?: Array<string | number>; // key checkedKeys?: Array<string | number>; // key
virtualListProps?: Record<string, unknown>; // virtualListProps?: Record<string, unknown>; //
titleTooltipPosition?:
| 'top'
| 'tl'
| 'tr'
| 'bottom'
| 'bl'
| 'br'
| 'left'
| 'lt'
| 'lb'
| 'right'
| 'rt'
| 'rb'; // tooltip
}>(), }>(),
{ {
searchDebounce: 300, searchDebounce: 300,
defaultExpandAll: false, defaultExpandAll: false,
selectable: true, selectable: true,
draggable: false,
titleTooltipPosition: 'right',
fieldNames: () => ({ fieldNames: () => ({
key: 'key', key: 'key',
title: 'title', title: 'title',
@ -401,6 +422,9 @@
} }
} }
} }
.arco-tree-node-title-block {
width: 80%;
}
.ms-tree-node-extra { .ms-tree-node-extra {
@apply relative hidden; @apply relative hidden;
&:hover { &:hover {

View File

@ -1,4 +1,5 @@
import { filter, orderBy, sortBy } from 'lodash-es'; import { filter, orderBy, sortBy } from 'lodash-es';
import localforage from 'localforage';
import { MsTableColumn, MsTableColumnData } from '@/components/pure/ms-table/type'; import { MsTableColumn, MsTableColumnData } from '@/components/pure/ms-table/type';
@ -8,8 +9,6 @@ import { isArraysEqualWithOrder } from '@/utils/equal';
import { SpecialColumnEnum } from '@/enums/tableEnum'; import { SpecialColumnEnum } from '@/enums/tableEnum';
import localforage from 'localforage';
export default function useTableStore() { export default function useTableStore() {
const state = reactive({ const state = reactive({
baseSortIndex: 10, baseSortIndex: 10,

View File

@ -59,6 +59,7 @@ export interface BatchFileApiParams extends BatchApiParams {
projectId: string; projectId: string;
fileType: string; fileType: string;
moduleIds: string[]; moduleIds: string[];
moveModuleId?: string | number; // 移动的模块ID
} }
// 更新模块参数 // 更新模块参数
export interface UpdateModuleParams { export interface UpdateModuleParams {

View File

@ -23,6 +23,7 @@
count: 'count', count: 'count',
}" }"
block-node block-node
title-tooltip-position="left"
@select="folderNodeSelect" @select="folderNodeSelect"
@more-action-select="handleFolderMoreSelect" @more-action-select="handleFolderMoreSelect"
@more-actions-close="moreActionsClose" @more-actions-close="moreActionsClose"
@ -30,9 +31,7 @@
> >
<template #title="nodeData"> <template #title="nodeData">
<div class="inline-flex w-full"> <div class="inline-flex w-full">
<a-tooltip :content="nodeData.name" :mouse-enter-delay="300" position="left"> <div class="one-line-text w-[calc(100%-32px)] text-[var(--color-text-1)]">{{ nodeData.name }}</div>
<div class="one-line-text w-[calc(100%-32px)] text-[var(--color-text-1)]">{{ nodeData.name }}</div>
</a-tooltip>
<div v-if="!props.isModal" class="ml-[4px] text-[var(--color-text-4)]">({{ nodeData.count || 0 }})</div> <div v-if="!props.isModal" class="ml-[4px] text-[var(--color-text-4)]">({{ nodeData.count || 0 }})</div>
</div> </div>
</template> </template>
@ -162,7 +161,7 @@
folderTree.value = res.map((e) => ({ folderTree.value = res.map((e) => ({
...e, ...e,
hideMoreAction: e.id === 'root', hideMoreAction: e.id === 'root',
draggable: e.id !== 'root', draggable: e.id !== 'root' && !props.isModal,
})); }));
if (isSetDefaultKey) { if (isSetDefaultKey) {
selectedKeys.value = [folderTree.value[0].id]; selectedKeys.value = [folderTree.value[0].id];

View File

@ -234,7 +234,7 @@
:ok-text="t('project.fileManagement.batchMoveConfirm')" :ok-text="t('project.fileManagement.batchMoveConfirm')"
:ok-button-props="{ disabled: selectedModuleKeys.length === 0 }" :ok-button-props="{ disabled: selectedModuleKeys.length === 0 }"
:cancel-button-props="{ disabled: batchMoveFileLoading }" :cancel-button-props="{ disabled: batchMoveFileLoading }"
:on-before-ok="batchMoveFile" :on-before-ok="handleFileMove"
@close="handleMoveFileModalCancel" @close="handleMoveFileModalCancel"
> >
<template #title> <template #title>
@ -292,6 +292,7 @@
import { import {
batchDownloadFile, batchDownloadFile,
batchMoveFile,
deleteFile, deleteFile,
downloadFile, downloadFile,
getFileList, getFileList,
@ -341,6 +342,9 @@
const tableFileTypeOptions = ref<string[]>([]); const tableFileTypeOptions = ref<string[]>([]);
const fileTypeLoading = ref(false); const fileTypeLoading = ref(false);
/**
* 初始化文件类型筛选选项
*/
async function initFileTypes() { async function initFileTypes() {
try { try {
fileTypeLoading.value = true; fileTypeLoading.value = true;
@ -464,7 +468,6 @@
tableStore.initColumn(TableKeyEnum.FILE_MANAGEMENT_FILE, columns, 'drawer'); tableStore.initColumn(TableKeyEnum.FILE_MANAGEMENT_FILE, columns, 'drawer');
const { propsRes, propsEvent, loadList, setLoadListParams } = useTable(getFileList, { const { propsRes, propsEvent, loadList, setLoadListParams } = useTable(getFileList, {
tableKey: TableKeyEnum.FILE_MANAGEMENT_FILE, tableKey: TableKeyEnum.FILE_MANAGEMENT_FILE,
columns,
showSetting: true, showSetting: true,
selectable: true, selectable: true,
showSelectAll: true, showSelectAll: true,
@ -500,6 +503,13 @@
], ],
}; };
const tableSelected = ref<(string | number)[]>([]); const tableSelected = ref<(string | number)[]>([]);
const batchParams = ref<BatchActionQueryParams>({
selectedIds: [],
selectAll: false,
excludeIds: [],
currentSelectCount: 0,
});
const combine = ref<Record<string, any>>({});
/** /**
* 处理表格选中 * 处理表格选中
@ -510,16 +520,15 @@
/** /**
* 批量下载文件 * 批量下载文件
* @param params 批量操作参数
*/ */
async function batchDownload(params: BatchActionQueryParams) { async function batchDownload() {
try { try {
loading.value = true; loading.value = true;
const res = await batchDownloadFile({ const res = await batchDownloadFile({
selectIds: params?.selectedIds || [], selectIds: batchParams.value?.selectedIds || [],
selectAll: !!params?.selectAll, selectAll: !!batchParams.value?.selectAll,
excludeIds: params?.excludeIds || [], excludeIds: batchParams.value?.excludeIds || [],
condition: { keyword: keyword.value }, condition: { keyword: keyword.value, comebine: combine.value },
projectId: appStore.currentProjectId, projectId: appStore.currentProjectId,
fileType: tableFileType.value, fileType: tableFileType.value,
moduleIds: [props.activeFolder], moduleIds: [props.activeFolder],
@ -555,14 +564,14 @@
/** /**
* 删除文件 * 删除文件
*/ */
function delFile(record: FileItem | null, isBatch: boolean, params?: BatchActionQueryParams) { function delFile(record: FileItem | null, isBatch: boolean) {
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', { title = t('project.fileManagement.batchDeleteFileTipTitle', {
count: params?.currentSelectCount || params?.selectedIds?.length, count: batchParams.value?.currentSelectCount || batchParams.value?.selectedIds?.length,
}); });
selectIds = params?.selectedIds || []; selectIds = batchParams.value?.selectedIds || [];
} }
openModal({ openModal({
type: 'error', type: 'error',
@ -578,9 +587,9 @@
try { try {
await deleteFile({ await deleteFile({
selectIds, selectIds,
selectAll: !!params?.selectAll, selectAll: !!batchParams.value?.selectAll,
excludeIds: params?.excludeIds || [], excludeIds: batchParams.value?.excludeIds || [],
condition: { keyword: keyword.value }, condition: { keyword: keyword.value, comebine: combine.value },
projectId: appStore.currentProjectId, projectId: appStore.currentProjectId,
fileType: tableFileType.value, fileType: tableFileType.value,
moduleIds: [props.activeFolder], moduleIds: [props.activeFolder],
@ -619,16 +628,17 @@
*/ */
function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) { function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) {
tableSelected.value = params?.selectedIds || []; tableSelected.value = params?.selectedIds || [];
batchParams.value = params;
switch (event.eventTag) { switch (event.eventTag) {
case 'download': case 'download':
batchDownload(params); batchDownload();
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, params); delFile(null, true);
break; break;
default: default:
break; break;
@ -639,11 +649,18 @@
/** /**
* 单个/批量移动文件 * 单个/批量移动文件
*/ */
async function batchMoveFile() { async function handleFileMove() {
try { try {
batchMoveFileLoading.value = true; batchMoveFileLoading.value = true;
await new Promise((resolve) => { await batchMoveFile({
setTimeout(() => resolve(true), 2000); selectIds: batchParams.value?.selectedIds || [activeFile.value?.id || ''],
selectAll: !!batchParams.value?.selectAll,
excludeIds: batchParams.value?.excludeIds || [],
condition: { keyword: keyword.value, comebine: combine.value },
projectId: appStore.currentProjectId,
fileType: tableFileType.value,
moduleIds: [props.activeFolder],
moveModuleId: selectedModuleKeys.value[0],
}); });
Message.success(t('project.fileManagement.batchMoveSuccess')); Message.success(t('project.fileManagement.batchMoveSuccess'));
if (isBatchMove.value) { if (isBatchMove.value) {
@ -672,19 +689,18 @@
} }
function setTableParams() { function setTableParams() {
const combine: Record<string, any> = {};
if (props.activeFolder === 'my') { if (props.activeFolder === 'my') {
combine.createUser = userStore.id; combine.value.createUser = userStore.id;
} }
if (fileType.value === 'storage') { if (fileType.value === 'storage') {
combine.storage = 'git'; combine.value.storage = 'git';
} }
setLoadListParams({ setLoadListParams({
keyword: keyword.value, keyword: keyword.value,
fileType: tableFileType.value, fileType: tableFileType.value,
moduleIds: ['all', 'my'].includes(props.activeFolder) ? [] : [props.activeFolder], moduleIds: ['all', 'my'].includes(props.activeFolder) ? [] : [props.activeFolder],
projectId: appStore.currentProjectId, projectId: appStore.currentProjectId,
comebine: combine, comebine: combine.value,
}); });
} }
@ -885,6 +901,9 @@
isUploading.value = false; isUploading.value = false;
} }
/**
* 取消上传二次确认
*/
function cancelUpload() { function cancelUpload() {
if (asyncTaskStore.uploadFileTask.eachTaskQueue.length > 0 && asyncTaskStore.eachUploadTaskProgress !== 100) { if (asyncTaskStore.uploadFileTask.eachTaskQueue.length > 0 && asyncTaskStore.eachUploadTaskProgress !== 100) {
openModal({ openModal({

View File

@ -4,7 +4,7 @@ export default {
'project.fileManagement.defaultFile': 'Default files', 'project.fileManagement.defaultFile': 'Default files',
'project.fileManagement.expandAll': 'Expand all submodules', 'project.fileManagement.expandAll': 'Expand all submodules',
'project.fileManagement.collapseAll': 'Collapse all submodules', 'project.fileManagement.collapseAll': 'Collapse all submodules',
'project.fileManagement.addSubModule': 'Add module', 'project.fileManagement.addSubModule': 'Add submodule',
'project.fileManagement.addStorage': 'Add repository', 'project.fileManagement.addStorage': 'Add repository',
'project.fileManagement.rename': 'Rename', 'project.fileManagement.rename': 'Rename',
'project.fileManagement.nameNotNull': 'name cannot be empty', 'project.fileManagement.nameNotNull': 'name cannot be empty',

View File

@ -4,7 +4,7 @@ export default {
'project.fileManagement.defaultFile': '默认文件', 'project.fileManagement.defaultFile': '默认文件',
'project.fileManagement.expandAll': '展开全部子模块', 'project.fileManagement.expandAll': '展开全部子模块',
'project.fileManagement.collapseAll': '收起全部子模块', 'project.fileManagement.collapseAll': '收起全部子模块',
'project.fileManagement.addSubModule': '添加模块', 'project.fileManagement.addSubModule': '添加模块',
'project.fileManagement.addStorage': '添加存储库', 'project.fileManagement.addStorage': '添加存储库',
'project.fileManagement.rename': '重命名', 'project.fileManagement.rename': '重命名',
'project.fileManagement.nameNotNull': '名字不能为空', 'project.fileManagement.nameNotNull': '名字不能为空',

View File

@ -10,7 +10,7 @@
}} }}
</div> </div>
</template> </template>
<a-spin :loading="loading"> <a-spin class="w-full" :loading="loading">
<a-alert v-if="batchModalMode === 'project'" class="mb-[16px]"> <a-alert v-if="batchModalMode === 'project'" class="mb-[16px]">
{{ t('system.user.batchModalTip') }} {{ t('system.user.batchModalTip') }}
</a-alert> </a-alert>
@ -26,6 +26,7 @@
children: 'children', children: 'children',
disabled: 'disabled', disabled: 'disabled',
}" }"
height="370px"
show-search show-search
/> />
</a-spin> </a-spin>