feat(文件管理): 表格组件排序、标签&文件管理部分接口

This commit is contained in:
baiqi 2023-10-30 18:23:41 +08:00 committed by Craftsman
parent f38f3243ba
commit 69d528bb7b
9 changed files with 119 additions and 67 deletions

View File

@ -6,6 +6,7 @@ import {
DeleteModuleUrl,
DownloadFileUrl,
FilePageUrl,
GetFileTypesUrl,
GetModuleCountUrl,
GetModuleUrl,
MoveModuleUrl,
@ -94,3 +95,8 @@ export function getModules(id: string) {
export function deleteModule(id: string) {
return MSR.get({ url: DeleteModuleUrl, params: id });
}
// 获取文件类型集合
export function getFileTypes(id: string) {
return MSR.get<string[]>({ url: GetFileTypesUrl, params: id });
}

View File

@ -11,4 +11,6 @@ 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'; // 模块统计文件数量
export const PreviewImgUrl = '/project/file/download/preview-img'; // 预览图片文件接口
export const OriginImgUrl = '/file/preview/original'; // 预览图片文件接口-原图
export const CompressImgUrl = '/file/preview/compressed'; // 预览图片文件接口-缩略图
export const GetFileTypesUrl = '/project/file/type'; // 获取文件类型集合

View File

@ -24,6 +24,11 @@
<a-spin :loading="bottomLoading"></a-spin>
</div>
</div>
<a-empty
v-if="!topLoading && !bottomLoading && (remoteList.length === 0 || props.list?.length === 0)"
:description="t('common.noData')"
class="h-[200px] justify-center"
/>
</div>
</template>
@ -33,6 +38,7 @@
import { debounce } from 'lodash-es';
import useContainerShadow from '@/hooks/useContainerShadow';
import { useI18n } from '@/hooks/useI18n';
import type { CommonList } from '@/models/common';
@ -55,6 +61,8 @@
}
);
const { t } = useI18n();
const msCardListRef: Ref<HTMLElement | null> = ref(null);
const msCardListContainerRef: Ref<HTMLElement | null> = ref(null);
@ -255,4 +263,7 @@
}
}
}
:deep(.arco-icon-empty) {
font-size: 48px;
}
</style>

View File

@ -86,11 +86,12 @@
</slot>
</template>
<template v-else-if="item.isTag">
<div class="one-line-text max-w-[456px]">
<slot :name="item.slotName" v-bind="{ record, rowIndex, column }">
{{ record[item.dataIndex as string] || (attrs.emptyDataShowLine ? '-' : '') }}
</slot>
</div>
<span
v-if="!record[item.dataIndex as string] || (Array.isArray(record[item.dataIndex as string]) && record[item.dataIndex as string].length === 0)"
>
<slot :name="item.slotName" v-bind="{ record, rowIndex, column }"> - </slot>
</span>
<MsTagGroup v-else :tag-list="record[item.dataIndex as string]" type="primary" theme="outline" />
</template>
<template v-else-if="item.slotName === SpecialColumnEnum.OPERATION">
<slot name="operation" v-bind="{ record, rowIndex }" />
@ -187,6 +188,7 @@
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
import MsPagination from '@/components/pure/ms-pagination/index';
import MsTagGroup from '@/components/pure/ms-tag/ms-tag-group.vue';
import MsCheckbox from '../ms-checkbox/MsCheckbox.vue';
import BatchAction from './batchAction.vue';
import ColumnSelector from './columnSelector.vue';
@ -371,9 +373,9 @@
const handleSortChange = (dataIndex: string, direction: string) => {
const regex = /^__arco_data_index_(\d+)$/;
const match = dataIndex.match(regex);
const lastDigit = match && (match[1] as unknown as number);
if (lastDigit) {
dataIndex = currentColumns.value[lastDigit - 1].dataIndex as string;
const lastDigit = match && Number(match[1]);
if (lastDigit && !Number.isNaN(lastDigit)) {
dataIndex = currentColumns.value[lastDigit].dataIndex as string;
}
let sortOrder = '';
if (direction === 'ascend') {

View File

@ -60,8 +60,8 @@
<a-spin :loading="replaceLoading">
<MsPreviewCard
mode="hover"
:type="detail?.type"
:url="detail?.url"
:type="detail?.fileType"
:url="`${CompressImgUrl}/${userStore.id}/${detail.id}`"
:footer-text="t('project.fileManagement.replaceFile')"
@click="handleFileIconClick"
/>
@ -170,7 +170,7 @@
</div>
</div>
</div>
<a-image-preview v-model:visible="previewVisible" :src="detail?.url" />
<a-image-preview v-model:visible="previewVisible" :src="`${OriginImgUrl}/${userStore.id}/${detail.id}`" />
</template>
</MsDetailDrawer>
</template>
@ -193,8 +193,10 @@
import popConfirm from './popConfirm.vue';
import { reuploadFile, updateFile } from '@/api/modules/project-management/fileManagement';
import { CompressImgUrl, OriginImgUrl } from '@/api/requrls/project-management/fileManagement';
import { useI18n } from '@/hooks/useI18n';
import useLocale from '@/locale/useLocale';
import useUserStore from '@/store/modules/user';
import { downloadUrlFile } from '@/utils';
import { TableKeyEnum } from '@/enums/tableEnum';
@ -213,6 +215,7 @@
const { file: newFile, open } = useFileSystemAccess();
const { t } = useI18n();
const { currentLocale } = useLocale();
const userStore = useUserStore();
const innerVisible = ref(false);
const fileDescriptions = ref<Description[]>([]);

View File

@ -95,6 +95,7 @@
isExpandAll: boolean;
selectedKeys?: Array<string | number>; // key
isModal?: boolean; //
modulesCount?: Record<string, number>; //
}>();
const emit = defineEmits(['update:selectedKeys', 'init', 'folderNodeSelect']);
@ -265,9 +266,9 @@
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
initModules();
} finally {
loading.value = false;
initModules();
}
}
@ -285,24 +286,20 @@
/**
* 初始化模块文件数量
*/
async function initModulesCount(params: FileListQueryParams) {
try {
const res = await getModulesCount(params);
watch(
() => props.modulesCount,
(obj) => {
folderTree.value = mapTree<ModuleTreeNode>(folderTree.value, (node) => {
return {
...node,
count: res[node.id] || 0,
count: obj?.[node.id] || 0,
};
});
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
}
);
defineExpose({
initModules,
initModulesCount,
});
</script>

View File

@ -3,7 +3,7 @@
<div class="header">
<a-button type="primary" @click="handleAddClick">{{ t('project.fileManagement.addFile') }}</a-button>
<div class="header-right">
<a-select v-model="tableFileType" class="w-[240px]" @change="searchList">
<a-select v-model="tableFileType" class="w-[240px]" :loading="fileTypeLoading" @change="searchList">
<a-option key="" value="">{{ t('common.all') }}</a-option>
<a-option v-for="item of tableFileTypeOptions" :key="item" :value="item">
{{ item }}
@ -14,6 +14,8 @@
:placeholder="t('project.fileManagement.folderSearchPlaceholder')"
allow-clear
class="w-[240px]"
@search="searchList"
@press-enter="searchList"
/>
<a-radio-group
v-if="props.activeFolderType === 'folder'"
@ -84,7 +86,7 @@
<template #item="{ item, index }">
<MsThumbnailCard
:type="item.fileType"
:url="item.url || `${PreviewImgUrl}/${item.id}`"
:url="`${CompressImgUrl}/${userStore.id}/${item.id}`"
:footer-text="item.name"
:more-actions="item.fileType === 'JAR' ? jarFileActions : normalFileActions"
@click="openFileDetail(item.id, index)"
@ -290,10 +292,11 @@
deleteFile,
downloadFile,
getFileList,
getFileTypes,
updateFile,
uploadFile,
} from '@/api/modules/project-management/fileManagement';
import { PreviewImgUrl } from '@/api/requrls/project-management/fileManagement';
import { CompressImgUrl } from '@/api/requrls/project-management/fileManagement';
import { useI18n } from '@/hooks/useI18n';
import useModal from '@/hooks/useModal';
import useAppStore from '@/store/modules/app';
@ -328,22 +331,23 @@
const acceptType = ref<UploadType>('none'); // -
const isUploading = ref(false);
const keyword = ref('');
const tableFileType = ref('');
const tableFileTypeOptions = ref(['JPG', 'PNG']);
const loading = ref(false);
watch(
() => props.activeFolderType,
(val) => {
if (val === 'folder') {
fileType.value = 'module';
} else {
fileType.value = val;
}
}
);
const tableFileType = ref('');
const tableFileTypeOptions = ref<string[]>([]);
const fileTypeLoading = ref(false);
function changeFileType() {}
async function initFileTypes() {
try {
fileTypeLoading.value = true;
const res = await getFileTypes(appStore.currentProjectId);
tableFileTypeOptions.value = res;
} catch (error) {
console.log(error);
} finally {
fileTypeLoading.value = false;
}
}
const showType = ref<'list' | 'card'>('list'); //
@ -406,7 +410,6 @@
{
title: 'project.fileManagement.tag',
dataIndex: 'tags',
slotName: 'tag',
isTag: true,
},
{
@ -648,19 +651,42 @@
selectedModuleKeys.value = [];
}
const searchList = debounce(() => {
function setTableParams() {
const combine: Record<string, any> = {};
if (props.activeFolder === 'my') {
combine.createUser = userStore.id;
}
if (fileType.value === 'storage') {
combine.storage = 'git';
}
setLoadListParams({
keyword: keyword.value,
fileType: tableFileType.value,
moduleIds: ['all', 'my'].includes(props.activeFolder) ? [] : [props.activeFolder],
projectId: appStore.currentProjectId,
comebine:
props.activeFolder === 'my'
? {
createUser: userStore.id,
}
: {},
comebine: combine,
});
}
function changeFileType() {
setTableParams();
loadList();
}
watch(
() => props.activeFolderType,
(val) => {
if (val === 'folder') {
fileType.value = 'module';
} else {
fileType.value = val;
}
setTableParams();
}
);
const searchList = debounce(() => {
setTableParams();
if (showType.value === 'card') {
cardListRef.value?.reload();
} else {
@ -678,13 +704,6 @@
{ immediate: true }
);
watch(
() => keyword.value,
() => {
searchList();
}
);
/**
* 下载单个文件
* @param record 表格数据项
@ -858,6 +877,7 @@
type RouteQueryPosition = 'uploadDrawer' | null;
onBeforeMount(() => {
initFileTypes();
if (route.query.position) {
switch (
route.query.position as RouteQueryPosition //

View File

@ -57,6 +57,7 @@
ref="folderTreeRef"
v-model:selected-keys="selectedKeys"
:is-expand-all="isExpandAll"
:modules-count="modulesCount"
@init="setRootModules"
@folder-node-select="folderNodeSelect"
/>
@ -92,14 +93,14 @@
import rightBox from './components/rightBox.vue';
import StorageList from './components/storageList.vue';
import { getModulesCount } from '@/api/modules/project-management/fileManagement';
import { useI18n } from '@/hooks/useI18n';
import { mapTree } from '@/utils';
import { FileListQueryParams } from '@/models/projectManagement/file';
import { FileListQueryParams, ModuleTreeNode } from '@/models/projectManagement/file';
const { t } = useI18n();
const myFileCount = ref(0);
const allFileCount = ref(0);
const isExpandAll = ref(false);
const activeFolderType = ref<'folder' | 'module' | 'storage'>('folder');
const storageDrawerVisible = ref(false);
@ -181,12 +182,30 @@
}
}
const modulesCount = ref<Record<string, number>>({});
const myFileCount = ref(0);
const allFileCount = ref(0);
/**
* 初始化模块文件数量
*/
async function initModulesCount(params: FileListQueryParams) {
try {
modulesCount.value = await getModulesCount(params);
myFileCount.value = modulesCount.value.my || 0;
allFileCount.value = modulesCount.value.all || 0;
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
}
/**
* 右侧表格数据刷新后若当前展示的是模块则刷新模块树的统计数量
*/
function handleModuleTableInit(params: FileListQueryParams) {
if (showType.value === 'Module') {
folderTreeRef.value?.initModulesCount(params);
initModulesCount(params);
}
}
</script>

View File

@ -25,12 +25,6 @@
v-on="propsEvent"
@batch-action="handleTableBatch"
>
<template #organization="{ record }">
<MsTagGroup theme="outline" :tag-list="record.organizationList"> </MsTagGroup>
</template>
<template #userRole="{ record }">
<MsTagGroup :tag-list="record.userRoleList" type="primary" theme="outline"> </MsTagGroup>
</template>
<template #action="{ record }">
<template v-if="!record.enable">
<MsButton @click="enableUser(record)">{{ t('system.user.enable') }}</MsButton>
@ -249,15 +243,13 @@
},
{
title: 'system.user.tableColumnOrg',
slotName: 'organization',
dataIndex: 'organization',
dataIndex: 'organizationList',
isTag: true,
},
{
title: 'system.user.tableColumnUserGroup',
slotName: 'userRole',
isTag: true,
dataIndex: 'userRole',
dataIndex: 'userRoleList',
},
{
title: 'system.user.tableColumnStatus',