feat: 功能优化
This commit is contained in:
@@ -5,7 +5,7 @@ import { theme } from 'ant-design-vue'
|
|||||||
import SvgSprite from '@/components/icons/SvgSprite.vue'
|
import SvgSprite from '@/components/icons/SvgSprite.vue'
|
||||||
import { useUserStore } from '@/stores/user'
|
import { useUserStore } from '@/stores/user'
|
||||||
import tokenManager from '@gold/utils/token-manager'
|
import tokenManager from '@gold/utils/token-manager'
|
||||||
|
import zhCN from 'ant-design-vue/es/locale/zh_CN';
|
||||||
const themeToken = ref({
|
const themeToken = ref({
|
||||||
token: {
|
token: {
|
||||||
colorPrimary: '#3B82F6',
|
colorPrimary: '#3B82F6',
|
||||||
@@ -70,7 +70,7 @@ onMounted(async () => {})
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<a-config-provider :theme="themeToken">
|
<a-config-provider :theme="themeToken" :locale="zhCN">
|
||||||
<SvgSprite />
|
<SvgSprite />
|
||||||
<keep-alive>
|
<keep-alive>
|
||||||
<RouterView />
|
<RouterView />
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import Antd from 'ant-design-vue'
|
|||||||
import 'normalize.css'
|
import 'normalize.css'
|
||||||
import 'ant-design-vue/dist/reset.css'
|
import 'ant-design-vue/dist/reset.css'
|
||||||
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
|
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
|
||||||
|
import 'dayjs/locale/zh-cn';
|
||||||
|
|
||||||
|
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import router from './router'
|
import router from './router'
|
||||||
|
|||||||
@@ -35,9 +35,34 @@
|
|||||||
>
|
>
|
||||||
<div class="sidebar-group-item__content">
|
<div class="sidebar-group-item__content">
|
||||||
<FolderOutlined class="sidebar-group-item__icon" />
|
<FolderOutlined class="sidebar-group-item__icon" />
|
||||||
<span class="sidebar-group-item__name">{{ group.name }}</span>
|
<template v-if="editingGroupId !== group.id">
|
||||||
|
<span class="sidebar-group-item__name">{{ group.name }}</span>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<a-input
|
||||||
|
v-model:value="editingGroupName"
|
||||||
|
size="small"
|
||||||
|
class="sidebar-group-item__edit-input"
|
||||||
|
@blur="handleSaveGroupName(group)"
|
||||||
|
@press-enter="handleSaveGroupName(group)"
|
||||||
|
@click.stop
|
||||||
|
autofocus
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<div class="sidebar-group-item__actions">
|
||||||
|
<template v-if="editingGroupId !== group.id">
|
||||||
|
<span class="sidebar-group-item__count">{{ group.fileCount }}</span>
|
||||||
|
<EditOutlined
|
||||||
|
class="sidebar-group-item__action-btn"
|
||||||
|
@click.stop="handleEditGroup(group)"
|
||||||
|
/>
|
||||||
|
<DeleteOutlined
|
||||||
|
class="sidebar-group-item__action-btn sidebar-group-item__action-btn--danger"
|
||||||
|
@click.stop="handleDeleteGroup(group)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<span class="sidebar-group-item__count">{{ group.fileCount }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -238,187 +263,283 @@ import {
|
|||||||
SearchOutlined,
|
SearchOutlined,
|
||||||
FileOutlined,
|
FileOutlined,
|
||||||
FolderOutlined,
|
FolderOutlined,
|
||||||
PlusOutlined
|
PlusOutlined,
|
||||||
|
EditOutlined,
|
||||||
|
DeleteOutlined
|
||||||
} from '@ant-design/icons-vue';
|
} from '@ant-design/icons-vue';
|
||||||
import { message, Modal } from 'ant-design-vue';
|
import { message, Modal } from 'ant-design-vue';
|
||||||
import MaterialUploadModal from '@/components/material/MaterialUploadModal.vue';
|
import MaterialUploadModal from '@/components/material/MaterialUploadModal.vue';
|
||||||
import MaterialService, { MaterialGroupService } from '@/api/material';
|
import MaterialService, { MaterialGroupService } from '@/api/material';
|
||||||
import { useUpload } from '@/composables/useUpload';
|
import { useUpload } from '@/composables/useUpload';
|
||||||
|
|
||||||
// 响应式数据
|
// 状态管理
|
||||||
const loading = ref(false);
|
const loading = ref(false)
|
||||||
const activeCategory = ref('MIX'); // MIX 或 DIGITAL_HUMAN
|
const activeCategory = ref('MIX')
|
||||||
const selectedGroupId = ref(null);
|
const selectedGroupId = ref(null)
|
||||||
const groupList = ref([]);
|
const groupList = ref([])
|
||||||
const fileList = ref([]);
|
const fileList = ref([])
|
||||||
const totalFileCount = ref(0);
|
const totalFileCount = ref(0)
|
||||||
const searchKeyword = ref('');
|
const searchKeyword = ref('')
|
||||||
|
|
||||||
const uploadModalVisible = ref(false);
|
// 模态框状态
|
||||||
const uploadLoading = ref(false);
|
const uploadModalVisible = ref(false)
|
||||||
const createGroupModalVisible = ref(false);
|
const uploadLoading = ref(false)
|
||||||
|
const createGroupModalVisible = ref(false)
|
||||||
// Upload Hook
|
|
||||||
const { upload } = useUpload()
|
|
||||||
|
|
||||||
|
// 表单数据
|
||||||
const createGroupForm = reactive({
|
const createGroupForm = reactive({
|
||||||
name: '',
|
name: '',
|
||||||
description: '',
|
description: '',
|
||||||
category: 'MIX'
|
category: 'MIX'
|
||||||
});
|
})
|
||||||
|
|
||||||
// 选中的文件ID列表
|
// 文件选择
|
||||||
const selectedFileIds = ref([]);
|
const selectedFileIds = ref([])
|
||||||
|
|
||||||
// 编辑状态
|
// 编辑状态
|
||||||
const editingFileId = ref(null);
|
const editingFileId = ref(null)
|
||||||
const editingDisplayName = ref('');
|
const editingDisplayName = ref('')
|
||||||
const nameInputRef = ref(null);
|
const nameInputRef = ref(null)
|
||||||
|
const editingGroupId = ref(null)
|
||||||
|
const editingGroupName = ref('')
|
||||||
|
|
||||||
// 分页信息
|
// 分页
|
||||||
const pagination = reactive({
|
const pagination = reactive({
|
||||||
current: 1,
|
current: 1,
|
||||||
pageSize: 20,
|
pageSize: 20,
|
||||||
total: 0
|
total: 0
|
||||||
});
|
})
|
||||||
|
|
||||||
|
// Hooks
|
||||||
|
const { upload } = useUpload()
|
||||||
|
|
||||||
// 方法
|
// 方法
|
||||||
const handleCategoryChange = async (category) => {
|
const handleCategoryChange = async (category) => {
|
||||||
activeCategory.value = category;
|
activeCategory.value = category
|
||||||
selectedGroupId.value = null;
|
selectedGroupId.value = null
|
||||||
createGroupForm.category = category;
|
createGroupForm.category = category
|
||||||
await loadGroupList();
|
await loadGroupList()
|
||||||
await loadFileList();
|
await loadFileList()
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
const handleSelectGroup = (group) => {
|
const handleSelectGroup = (group) => {
|
||||||
// 如果点击的是当前已选中的分组,则不执行任何操作
|
// 编辑中则先保存
|
||||||
if (selectedGroupId.value === group.id) {
|
if (editingGroupId.value) {
|
||||||
return;
|
const currentGroup = groupList.value.find(g => g.id === editingGroupId.value)
|
||||||
|
if (currentGroup) {
|
||||||
|
handleSaveGroupName(currentGroup)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
selectedGroupId.value = group.id;
|
|
||||||
loadFileList();
|
// 已是选中状态则不处理
|
||||||
};
|
if (selectedGroupId.value === group.id) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
selectedGroupId.value = group.id
|
||||||
|
loadFileList()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleEditGroup = async (group, event) => {
|
||||||
|
event?.stopPropagation?.()
|
||||||
|
editingGroupId.value = group.id
|
||||||
|
editingGroupName.value = group.name
|
||||||
|
await nextTick()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSaveGroupName = async (group) => {
|
||||||
|
const newName = editingGroupName.value.trim()
|
||||||
|
|
||||||
|
if (!newName) {
|
||||||
|
message.warning('分组名称不能为空')
|
||||||
|
editingGroupId.value = null
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newName === group.name) {
|
||||||
|
editingGroupId.value = null
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await MaterialGroupService.updateGroup({
|
||||||
|
id: group.id,
|
||||||
|
name: newName,
|
||||||
|
description: group.description || '',
|
||||||
|
sort: group.sort || 0,
|
||||||
|
icon: group.icon || 'folder',
|
||||||
|
parentId: group.parentId || 0
|
||||||
|
})
|
||||||
|
|
||||||
|
group.name = newName
|
||||||
|
message.success('分组重命名成功')
|
||||||
|
} catch (error) {
|
||||||
|
console.error('分组重命名失败:', error)
|
||||||
|
message.error('分组重命名失败,请重试')
|
||||||
|
} finally {
|
||||||
|
editingGroupId.value = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDeleteGroup = async (group, event) => {
|
||||||
|
event?.stopPropagation?.()
|
||||||
|
|
||||||
|
const confirmed = await new Promise((resolve) => {
|
||||||
|
Modal.confirm({
|
||||||
|
title: '删除分组',
|
||||||
|
content: `确定要删除分组「${group.name}」吗?删除后该分组下的所有文件将被移动到默认分组。此操作不可恢复。`,
|
||||||
|
okText: '确认删除',
|
||||||
|
cancelText: '取消',
|
||||||
|
okType: 'danger',
|
||||||
|
centered: true,
|
||||||
|
class: 'delete-group-modal',
|
||||||
|
onOk() {
|
||||||
|
resolve(true)
|
||||||
|
},
|
||||||
|
onCancel() {
|
||||||
|
resolve(false)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!confirmed) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
loading.value = true
|
||||||
|
await MaterialGroupService.deleteGroup(group.id)
|
||||||
|
|
||||||
|
// 移除已删除的分组
|
||||||
|
const index = groupList.value.findIndex(g => g.id === group.id)
|
||||||
|
if (index > -1) {
|
||||||
|
groupList.value.splice(index, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重新选择分组
|
||||||
|
if (selectedGroupId.value === group.id) {
|
||||||
|
selectedGroupId.value = groupList.value.length > 0 ? groupList.value[0].id : null
|
||||||
|
await loadFileList()
|
||||||
|
}
|
||||||
|
|
||||||
|
message.success('分组删除成功')
|
||||||
|
} catch (error) {
|
||||||
|
console.error('分组删除失败:', error)
|
||||||
|
message.error('分组删除失败,请重试')
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const handleOpenCreateGroupModal = () => {
|
const handleOpenCreateGroupModal = () => {
|
||||||
createGroupForm.name = '';
|
createGroupForm.name = ''
|
||||||
createGroupForm.description = '';
|
createGroupForm.description = ''
|
||||||
createGroupForm.category = activeCategory.value;
|
createGroupForm.category = activeCategory.value
|
||||||
createGroupModalVisible.value = true;
|
createGroupModalVisible.value = true
|
||||||
};
|
}
|
||||||
|
|
||||||
const handleCreateGroup = async () => {
|
const handleCreateGroup = async () => {
|
||||||
try {
|
try {
|
||||||
await MaterialGroupService.createGroup(createGroupForm);
|
await MaterialGroupService.createGroup(createGroupForm)
|
||||||
message.success('分组创建成功');
|
message.success('分组创建成功')
|
||||||
createGroupModalVisible.value = false;
|
createGroupModalVisible.value = false
|
||||||
await loadGroupList();
|
await loadGroupList()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
message.error('分组创建失败');
|
message.error('分组创建失败')
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
const loadGroupList = async () => {
|
const loadGroupList = async () => {
|
||||||
try {
|
try {
|
||||||
const result = await MaterialGroupService.getGroupListByCategory(activeCategory.value);
|
const result = await MaterialGroupService.getGroupListByCategory(activeCategory.value)
|
||||||
groupList.value = result.data || result || [];
|
groupList.value = result.data || result || []
|
||||||
|
|
||||||
// 默认选中第一个分组
|
|
||||||
if (groupList.value.length > 0 && selectedGroupId.value === null) {
|
|
||||||
selectedGroupId.value = groupList.value[0].id;
|
|
||||||
}
|
|
||||||
|
|
||||||
await loadFileList();
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载分组列表失败:', error);
|
console.error('加载分组列表失败:', error)
|
||||||
// 如果按分类查询失败,尝试加载所有分组
|
|
||||||
try {
|
try {
|
||||||
const allGroups = await MaterialGroupService.getGroupList();
|
const allGroups = await MaterialGroupService.getGroupList()
|
||||||
groupList.value = allGroups.data || allGroups || [];
|
groupList.value = allGroups.data || allGroups || []
|
||||||
|
|
||||||
// 默认选中第一个分组
|
|
||||||
if (groupList.value.length > 0 && selectedGroupId.value === null) {
|
|
||||||
selectedGroupId.value = groupList.value[0].id;
|
|
||||||
}
|
|
||||||
|
|
||||||
await loadFileList();
|
|
||||||
} catch (fallbackError) {
|
} catch (fallbackError) {
|
||||||
console.error('加载所有分组也失败:', fallbackError);
|
console.error('加载所有分组也失败:', fallbackError)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
// 默认选中第一个分组
|
||||||
|
if (groupList.value.length > 0 && selectedGroupId.value === null) {
|
||||||
|
selectedGroupId.value = groupList.value[0].id
|
||||||
|
}
|
||||||
|
|
||||||
|
await loadFileList()
|
||||||
|
}
|
||||||
|
|
||||||
const loadFileList = async () => {
|
const loadFileList = async () => {
|
||||||
loading.value = true;
|
loading.value = true
|
||||||
try {
|
try {
|
||||||
const params = {
|
const params = {
|
||||||
pageNo: pagination.current,
|
pageNo: pagination.current,
|
||||||
pageSize: pagination.pageSize,
|
pageSize: pagination.pageSize,
|
||||||
fileCategory: 'video', // 只查询视频文件
|
fileCategory: 'video',
|
||||||
fileName: searchKeyword.value || undefined,
|
fileName: searchKeyword.value || undefined,
|
||||||
groupId: selectedGroupId.value || undefined
|
groupId: selectedGroupId.value || undefined
|
||||||
};
|
}
|
||||||
|
|
||||||
const result = await MaterialService.getFilePage(params);
|
const result = await MaterialService.getFilePage(params)
|
||||||
fileList.value = result.data?.list || result.list || [];
|
fileList.value = result.data?.list || result.list || []
|
||||||
pagination.total = result.data?.total || result.total || 0;
|
const total = result.data?.total || result.total || 0
|
||||||
totalFileCount.value = result.data?.total || result.total || 0;
|
pagination.total = total
|
||||||
|
totalFileCount.value = total
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载文件列表失败:', error);
|
console.error('加载文件列表失败:', error)
|
||||||
message.error('加载文件列表失败');
|
message.error('加载文件列表失败')
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
const handleSearch = () => {
|
const handleSearch = () => {
|
||||||
pagination.current = 1;
|
pagination.current = 1
|
||||||
loadFileList();
|
loadFileList()
|
||||||
};
|
}
|
||||||
|
|
||||||
const handlePageChange = (page, pageSize) => {
|
const handlePageChange = (page, pageSize) => {
|
||||||
pagination.current = page;
|
pagination.current = page
|
||||||
pagination.pageSize = pageSize;
|
pagination.pageSize = pageSize
|
||||||
loadFileList();
|
loadFileList()
|
||||||
};
|
}
|
||||||
|
|
||||||
const handlePageSizeChange = (current, size) => {
|
const handlePageSizeChange = (current, size) => {
|
||||||
pagination.current = 1;
|
pagination.current = 1
|
||||||
pagination.pageSize = size;
|
pagination.pageSize = size
|
||||||
loadFileList();
|
loadFileList()
|
||||||
};
|
}
|
||||||
|
|
||||||
const handleFileClick = (file) => {
|
const handleFileClick = (file) => {
|
||||||
const index = selectedFileIds.value.indexOf(file.id);
|
const index = selectedFileIds.value.indexOf(file.id)
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
selectedFileIds.value.splice(index, 1);
|
selectedFileIds.value.splice(index, 1)
|
||||||
} else {
|
} else {
|
||||||
selectedFileIds.value.push(file.id);
|
selectedFileIds.value.push(file.id)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
const handleFileSelectChange = (fileId, checked) => {
|
const handleFileSelectChange = (fileId, checked) => {
|
||||||
const index = selectedFileIds.value.indexOf(fileId);
|
const index = selectedFileIds.value.indexOf(fileId)
|
||||||
if (checked && index === -1) {
|
if (checked && index === -1) {
|
||||||
selectedFileIds.value.push(fileId);
|
selectedFileIds.value.push(fileId)
|
||||||
} else if (!checked && index > -1) {
|
} else if (!checked && index > -1) {
|
||||||
selectedFileIds.value.splice(index, 1);
|
selectedFileIds.value.splice(index, 1)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
const handleOpenUploadModal = () => {
|
const handleOpenUploadModal = () => {
|
||||||
uploadModalVisible.value = true;
|
uploadModalVisible.value = true
|
||||||
};
|
}
|
||||||
|
|
||||||
const handleFileUpload = async (filesWithCover, category, groupId) => {
|
const handleFileUpload = async (filesWithCover, category, groupId) => {
|
||||||
try {
|
try {
|
||||||
uploadLoading.value = true;
|
uploadLoading.value = true
|
||||||
// 上传每个文件
|
|
||||||
for (const fileWithCover of filesWithCover) {
|
for (const fileWithCover of filesWithCover) {
|
||||||
await upload(fileWithCover.file, {
|
await upload(fileWithCover.file, {
|
||||||
fileCategory: category,
|
fileCategory: category,
|
||||||
groupId, // 素材库模块使用groupId
|
groupId,
|
||||||
coverBase64: fileWithCover.coverBase64,
|
coverBase64: fileWithCover.coverBase64,
|
||||||
onStart: () => {},
|
onStart: () => {},
|
||||||
onProgress: () => {},
|
onProgress: () => {},
|
||||||
@@ -431,39 +552,36 @@ const handleFileUpload = async (filesWithCover, category, groupId) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
message.success(`成功上传 ${filesWithCover.length} 个文件`);
|
message.success(`成功上传 ${filesWithCover.length} 个文件`)
|
||||||
uploadModalVisible.value = false;
|
uploadModalVisible.value = false
|
||||||
await loadFileList();
|
await loadFileList()
|
||||||
await loadGroupList();
|
await loadGroupList()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("文件上传失败:", error);
|
console.error("文件上传失败:", error)
|
||||||
message.error("文件上传失败: " + (error.message || "未知错误"));
|
message.error("文件上传失败: " + (error.message || "未知错误"))
|
||||||
} finally {
|
} finally {
|
||||||
uploadLoading.value = false;
|
uploadLoading.value = false
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
const handleSelectAll = (event) => {
|
const handleSelectAll = (event) => {
|
||||||
const checked = event.target.checked;
|
const checked = event.target.checked
|
||||||
if (checked) {
|
if (checked) {
|
||||||
// 全选:选中当前页所有文件
|
selectedFileIds.value = fileList.value.map(file => file.id)
|
||||||
selectedFileIds.value = fileList.value.map(file => file.id);
|
|
||||||
} else {
|
} else {
|
||||||
// 取消全选:清空选中状态
|
selectedFileIds.value = []
|
||||||
selectedFileIds.value = [];
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
const handleBatchDelete = async () => {
|
const handleBatchDelete = async () => {
|
||||||
if (selectedFileIds.value.length === 0) {
|
if (selectedFileIds.value.length === 0) {
|
||||||
message.warning('请先选择要删除的文件');
|
message.warning('请先选择要删除的文件')
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 确认对话框
|
const count = selectedFileIds.value.length
|
||||||
const count = selectedFileIds.value.length;
|
const fileIdsToDelete = [...selectedFileIds.value]
|
||||||
const fileIdsToDelete = [...selectedFileIds.value]; // 保存要删除的文件ID
|
|
||||||
const confirmed = await new Promise((resolve) => {
|
const confirmed = await new Promise((resolve) => {
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: '确认删除',
|
title: '确认删除',
|
||||||
@@ -474,128 +592,124 @@ const handleBatchDelete = async () => {
|
|||||||
centered: true,
|
centered: true,
|
||||||
class: 'batch-delete-modal',
|
class: 'batch-delete-modal',
|
||||||
onOk() {
|
onOk() {
|
||||||
resolve(true);
|
resolve(true)
|
||||||
},
|
},
|
||||||
onCancel() {
|
onCancel() {
|
||||||
resolve(false);
|
resolve(false)
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
|
|
||||||
if (!confirmed) {
|
if (!confirmed) return
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
loading.value = true;
|
loading.value = true
|
||||||
await MaterialService.deleteFiles(fileIdsToDelete);
|
await MaterialService.deleteFiles(fileIdsToDelete)
|
||||||
|
|
||||||
// 从列表中移除已删除的文件
|
// 移除已删除的文件
|
||||||
fileList.value = fileList.value.filter(file => !fileIdsToDelete.includes(file.id));
|
fileList.value = fileList.value.filter(file => !fileIdsToDelete.includes(file.id))
|
||||||
|
|
||||||
// 更新总数
|
// 更新状态
|
||||||
totalFileCount.value = Math.max(0, totalFileCount.value - count);
|
totalFileCount.value = Math.max(0, totalFileCount.value - count)
|
||||||
|
selectedFileIds.value = []
|
||||||
|
|
||||||
// 清空选中状态
|
// 如果删除后当前页没有数据了,则加载上一页
|
||||||
selectedFileIds.value = [];
|
|
||||||
|
|
||||||
// 如果删除后当前页没有数据了,且不是第一页,则加载上一页
|
|
||||||
if (fileList.value.length === 0 && pagination.current > 1) {
|
if (fileList.value.length === 0 && pagination.current > 1) {
|
||||||
pagination.current = pagination.current - 1;
|
pagination.current = pagination.current - 1
|
||||||
await loadFileList();
|
await loadFileList()
|
||||||
}
|
}
|
||||||
|
|
||||||
message.success(`成功删除 ${count} 个文件`);
|
message.success(`成功删除 ${count} 个文件`)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('批量删除失败:', error);
|
console.error('批量删除失败:', error)
|
||||||
message.error('删除失败,请重试');
|
message.error('删除失败,请重试')
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
const formatFileSize = (size) => {
|
const formatFileSize = (size) => {
|
||||||
if (size < 1024) return size + ' B';
|
if (size < 1024) return size + ' B'
|
||||||
if (size < 1024 * 1024) return (size / 1024).toFixed(2) + ' KB';
|
if (size < 1024 * 1024) return (size / 1024).toFixed(2) + ' KB'
|
||||||
if (size < 1024 * 1024 * 1024) return (size / (1024 * 1024)).toFixed(2) + ' MB';
|
if (size < 1024 * 1024 * 1024) return (size / (1024 * 1024)).toFixed(2) + ' MB'
|
||||||
return (size / (1024 * 1024 * 1024)).toFixed(2) + ' GB';
|
return (size / (1024 * 1024 * 1024)).toFixed(2) + ' GB'
|
||||||
};
|
}
|
||||||
|
|
||||||
const formatDate = (date) => {
|
const formatDate = (date) => {
|
||||||
return new Date(date).toLocaleDateString();
|
return new Date(date).toLocaleDateString()
|
||||||
};
|
}
|
||||||
|
|
||||||
const getFileTypeText = (fileName) => {
|
const getFileTypeText = (fileName) => {
|
||||||
if (!fileName) return '';
|
if (!fileName) return ''
|
||||||
// 提取文件后缀,如 .mp3、.mp4、.avi 等
|
const ext = fileName.split('.').pop()
|
||||||
const ext = fileName.split('.').pop();
|
return ext ? `${ext.toLowerCase()}` : ''
|
||||||
return ext ? `${ext.toLowerCase()}` : '';
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const handleEditName = async (file) => {
|
const handleEditName = async (file) => {
|
||||||
editingFileId.value = file.id;
|
editingFileId.value = file.id
|
||||||
editingDisplayName.value = file.displayName || file.fileName;
|
editingDisplayName.value = file.displayName || file.fileName
|
||||||
// 使用 nextTick 确保 DOM 更新后再聚焦
|
await nextTick()
|
||||||
await nextTick();
|
|
||||||
|
|
||||||
// 查找当前编辑文件的输入框
|
// 查找当前编辑文件的输入框
|
||||||
const nameElement = document.querySelector(`[data-file-id="${file.id}"] .material-item__name`);
|
const nameElement = document.querySelector(`[data-file-id="${file.id}"] .material-item__name`)
|
||||||
if (nameElement) {
|
if (nameElement) {
|
||||||
const input = nameElement.querySelector('input');
|
const input = nameElement.querySelector('input')
|
||||||
if (input) {
|
if (input) {
|
||||||
input.focus();
|
input.focus()
|
||||||
input.select();
|
input.select()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
const handleSaveName = async (file) => {
|
const handleSaveName = async (file) => {
|
||||||
if (!editingDisplayName.value.trim()) {
|
const newName = editingDisplayName.value.trim()
|
||||||
message.warning('名称不能为空');
|
|
||||||
editingFileId.value = null;
|
if (!newName) {
|
||||||
return;
|
message.warning('名称不能为空')
|
||||||
|
editingFileId.value = null
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (editingDisplayName.value === file.displayName) {
|
if (newName === file.displayName) {
|
||||||
editingFileId.value = null;
|
editingFileId.value = null
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await MaterialService.updateDisplayName(file.id, editingDisplayName.value.trim());
|
await MaterialService.updateDisplayName(file.id, newName)
|
||||||
file.displayName = editingDisplayName.value.trim();
|
file.displayName = newName
|
||||||
message.success('重命名成功');
|
message.success('重命名成功')
|
||||||
|
|
||||||
// 添加成功动画效果
|
// 成功动画效果
|
||||||
const nameElement = document.querySelector(`[data-file-id="${file.id}"] .material-item__name`);
|
const nameElement = document.querySelector(`[data-file-id="${file.id}"] .material-item__name`)
|
||||||
if (nameElement) {
|
if (nameElement) {
|
||||||
nameElement.style.transition = 'all 0.3s ease';
|
nameElement.style.transition = 'all 0.3s ease'
|
||||||
nameElement.style.transform = 'scale(1.05)';
|
nameElement.style.transform = 'scale(1.05)'
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
nameElement.style.transform = 'scale(1)';
|
nameElement.style.transform = 'scale(1)'
|
||||||
}, 300);
|
}, 300)
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('重命名失败:', error);
|
console.error('重命名失败:', error)
|
||||||
message.error('重命名失败,请重试');
|
message.error('重命名失败,请重试')
|
||||||
} finally {
|
} finally {
|
||||||
editingFileId.value = null;
|
editingFileId.value = null
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
const handleImageError = (e) => {
|
const handleImageError = (e) => {
|
||||||
e.target.style.display = 'none';
|
e.target.style.display = 'none'
|
||||||
};
|
}
|
||||||
|
|
||||||
// 监听分类变化
|
// 监听分类变化
|
||||||
watch(activeCategory, () => {
|
watch(activeCategory, () => {
|
||||||
selectedFileIds.value = [];
|
selectedFileIds.value = []
|
||||||
});
|
})
|
||||||
|
|
||||||
// 初始化
|
// 初始化
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
loadGroupList();
|
loadGroupList()
|
||||||
});
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
@@ -714,6 +828,11 @@ onMounted(() => {
|
|||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: #f5f5f5;
|
background: #f5f5f5;
|
||||||
|
|
||||||
|
.sidebar-group-item__action-btn {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&--active {
|
&--active {
|
||||||
@@ -741,10 +860,46 @@ onMounted(() => {
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
&__count {
|
&__count {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #999;
|
color: #999;
|
||||||
margin-left: 8px;
|
}
|
||||||
|
|
||||||
|
&__action-btn {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(4px);
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
padding: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
color: #94a3b8;
|
||||||
|
font-size: 12px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #1890ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--danger:hover {
|
||||||
|
color: #ff4d4f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__edit-input {
|
||||||
|
.ant-input {
|
||||||
|
height: 24px;
|
||||||
|
font-size: 13px;
|
||||||
|
border-color: #1890ff;
|
||||||
|
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.1);
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1056,4 +1211,25 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 删除分组确认弹窗样式
|
||||||
|
:deep(.delete-group-modal) {
|
||||||
|
.ant-modal-body {
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-modal-footer {
|
||||||
|
text-align: right;
|
||||||
|
padding: 16px 24px;
|
||||||
|
border-top: 1px solid #e8e8e8;
|
||||||
|
|
||||||
|
.ant-btn {
|
||||||
|
margin-left: 8px;
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user