feat: 优化
This commit is contained in:
@@ -62,9 +62,26 @@
|
||||
<div class="material-item__content">
|
||||
<!-- 预览图 -->
|
||||
<div class="material-item__preview">
|
||||
<!-- 视频文件:统一使用 coverBase64,如果没有则使用 coverUrl,最后使用视频标签显示第一帧 -->
|
||||
<img
|
||||
v-if="file.previewUrl"
|
||||
v-if="file.isVideo && (file.coverBase64 || file.coverUrl)"
|
||||
:src="file.coverBase64"
|
||||
:alt="file.fileName"
|
||||
@error="handleImageError"
|
||||
/>
|
||||
<!-- 视频文件:如果没有封面,使用视频标签显示第一帧 -->
|
||||
<video
|
||||
v-else-if="file.isVideo && file.previewUrl"
|
||||
:src="file.previewUrl"
|
||||
muted
|
||||
preload="metadata"
|
||||
class="preview-video"
|
||||
/>
|
||||
<!-- 图片或其他文件:使用图片标签 -->
|
||||
<!-- 优先级:coverUrl > coverBase64 > previewUrl -->
|
||||
<img
|
||||
v-else-if="file.coverUrl || file.coverBase64 || file.previewUrl"
|
||||
:src="file.coverUrl || file.coverBase64 || file.previewUrl"
|
||||
:alt="file.fileName"
|
||||
@error="handleImageError"
|
||||
/>
|
||||
@@ -130,7 +147,7 @@
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { message } from 'ant-design-vue'
|
||||
import { message, Modal } from 'ant-design-vue'
|
||||
import {
|
||||
UploadOutlined,
|
||||
SearchOutlined,
|
||||
@@ -138,6 +155,7 @@ import {
|
||||
} from '@ant-design/icons-vue'
|
||||
import { MaterialService } from '@/api/material'
|
||||
import MaterialUploadModal from '@/components/material/MaterialUploadModal.vue'
|
||||
import { formatFileSize, formatDate } from '@/utils/file'
|
||||
|
||||
// 数据
|
||||
const loading = ref(false)
|
||||
@@ -159,24 +177,28 @@ const pagination = reactive({
|
||||
total: 0
|
||||
})
|
||||
|
||||
// 构建查询参数
|
||||
const buildQueryParams = () => {
|
||||
const params = {
|
||||
pageNo: pagination.pageNo,
|
||||
pageSize: pagination.pageSize,
|
||||
...filters
|
||||
}
|
||||
// 处理日期范围
|
||||
if (filters.createTime && Array.isArray(filters.createTime) && filters.createTime.length === 2) {
|
||||
params.createTime = [
|
||||
`${filters.createTime[0]} 00:00:00`,
|
||||
`${filters.createTime[1]} 23:59:59`
|
||||
]
|
||||
}
|
||||
return params
|
||||
}
|
||||
|
||||
// 加载文件列表
|
||||
const loadFileList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const params = {
|
||||
pageNo: pagination.pageNo,
|
||||
pageSize: pagination.pageSize,
|
||||
...filters
|
||||
}
|
||||
// 处理日期范围(a-range-picker返回的是数组格式的字符串)
|
||||
// 日期区间:将开始日期设置为 00:00:00,结束日期设置为 23:59:59
|
||||
if (filters.createTime && Array.isArray(filters.createTime) && filters.createTime.length === 2) {
|
||||
params.createTime = [
|
||||
filters.createTime[0] + ' 00:00:00',
|
||||
filters.createTime[1] + ' 23:59:59'
|
||||
]
|
||||
}
|
||||
const res = await MaterialService.getFilePage(params)
|
||||
const res = await MaterialService.getFilePage(buildQueryParams())
|
||||
if (res.code === 0) {
|
||||
fileList.value = res.data.list || []
|
||||
pagination.total = res.data.total || 0
|
||||
@@ -197,8 +219,8 @@ const handleOpenUploadModal = () => {
|
||||
}
|
||||
|
||||
// 确认上传
|
||||
const handleConfirmUpload = async (files, fileCategory) => {
|
||||
if (!files || files.length === 0) {
|
||||
const handleConfirmUpload = async (filesWithCover, fileCategory) => {
|
||||
if (!filesWithCover?.length) {
|
||||
message.warning('请选择文件')
|
||||
return
|
||||
}
|
||||
@@ -208,10 +230,9 @@ const handleConfirmUpload = async (files, fileCategory) => {
|
||||
let failCount = 0
|
||||
|
||||
try {
|
||||
// 逐个上传文件,显示进度
|
||||
for (const file of files) {
|
||||
for (const { file, coverBase64 } of filesWithCover) {
|
||||
try {
|
||||
await MaterialService.uploadFile(file, fileCategory)
|
||||
await MaterialService.uploadFile(file, fileCategory, coverBase64)
|
||||
successCount++
|
||||
} catch (error) {
|
||||
console.error('文件上传失败:', file.name, error)
|
||||
@@ -240,33 +261,37 @@ const handleUploadCancel = () => {
|
||||
}
|
||||
|
||||
// 删除文件
|
||||
const handleBatchDelete = async () => {
|
||||
if (selectedFileIds.value.length === 0) {
|
||||
return
|
||||
}
|
||||
const handleBatchDelete = () => {
|
||||
if (selectedFileIds.value.length === 0) return
|
||||
|
||||
try {
|
||||
await MaterialService.deleteFiles(selectedFileIds.value)
|
||||
message.success('删除成功')
|
||||
selectedFileIds.value = []
|
||||
loadFileList()
|
||||
} catch (error) {
|
||||
console.error('删除失败:', error)
|
||||
message.error(error.message || '删除失败,请重试')
|
||||
}
|
||||
// 二次确认弹窗
|
||||
Modal.confirm({
|
||||
title: '确认删除',
|
||||
content: `确定要删除选中的 ${selectedFileIds.value.length} 个文件吗?删除后无法恢复。`,
|
||||
okText: '确定删除',
|
||||
cancelText: '取消',
|
||||
okType: 'danger',
|
||||
onOk: async () => {
|
||||
try {
|
||||
await MaterialService.deleteFiles(selectedFileIds.value)
|
||||
message.success('删除成功')
|
||||
selectedFileIds.value = []
|
||||
loadFileList()
|
||||
} catch (error) {
|
||||
console.error('删除失败:', error)
|
||||
message.error(error.message || '删除失败,请重试')
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 选择文件
|
||||
// 选择文件(简化逻辑)
|
||||
const handleSelectFile = (fileId, checked) => {
|
||||
if (checked) {
|
||||
if (!selectedFileIds.value.includes(fileId)) {
|
||||
selectedFileIds.value.push(fileId)
|
||||
}
|
||||
} else {
|
||||
const index = selectedFileIds.value.indexOf(fileId)
|
||||
if (index > -1) {
|
||||
selectedFileIds.value.splice(index, 1)
|
||||
}
|
||||
const index = selectedFileIds.value.indexOf(fileId)
|
||||
if (checked && index === -1) {
|
||||
selectedFileIds.value.push(fileId)
|
||||
} else if (!checked && index > -1) {
|
||||
selectedFileIds.value.splice(index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,27 +324,50 @@ const handlePageChange = (page, pageSize) => {
|
||||
loadFileList()
|
||||
}
|
||||
|
||||
// 工具函数
|
||||
const formatFileSize = (bytes) => {
|
||||
if (!bytes) return '0 B'
|
||||
const k = 1024
|
||||
const sizes = ['B', 'KB', 'MB', 'GB']
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k))
|
||||
return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i]
|
||||
}
|
||||
|
||||
const formatDate = (dateStr) => {
|
||||
if (!dateStr) return ''
|
||||
const date = new Date(dateStr)
|
||||
return date.toLocaleDateString('zh-CN', {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit'
|
||||
})
|
||||
}
|
||||
|
||||
// 图片加载错误处理(支持回退到其他图片源)
|
||||
const handleImageError = (e) => {
|
||||
e.target.style.display = 'none'
|
||||
const img = e.target
|
||||
const currentSrc = img.src
|
||||
|
||||
// 找到对应的文件对象
|
||||
const file = fileList.value.find(f =>
|
||||
f.coverBase64 === currentSrc ||
|
||||
f.coverUrl === currentSrc ||
|
||||
f.previewUrl === currentSrc
|
||||
)
|
||||
|
||||
if (file) {
|
||||
// 视频文件:优先使用 coverBase64,如果失败则尝试 coverUrl,最后尝试 previewUrl
|
||||
if (file.isVideo) {
|
||||
if (currentSrc === file.coverBase64 && file.coverUrl && file.coverUrl !== currentSrc) {
|
||||
// coverBase64 失败,尝试 coverUrl
|
||||
img.src = file.coverUrl
|
||||
return
|
||||
}
|
||||
if ((currentSrc === file.coverBase64 || currentSrc === file.coverUrl) && file.previewUrl && file.previewUrl !== currentSrc) {
|
||||
// coverBase64 和 coverUrl 都失败,尝试 previewUrl(视频第一帧)
|
||||
img.src = file.previewUrl
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// 非视频文件:尝试其他图片源
|
||||
if (file.coverUrl && file.coverUrl !== currentSrc) {
|
||||
img.src = file.coverUrl
|
||||
return
|
||||
}
|
||||
if (file.coverBase64 && file.coverBase64 !== currentSrc && file.coverBase64.startsWith('data:image')) {
|
||||
img.src = file.coverBase64
|
||||
return
|
||||
}
|
||||
if (file.previewUrl && file.previewUrl !== currentSrc) {
|
||||
img.src = file.previewUrl
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果所有图片源都失败,隐藏图片
|
||||
img.style.display = 'none'
|
||||
}
|
||||
|
||||
// 初始化
|
||||
@@ -421,7 +469,8 @@ onMounted(() => {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.material-item__preview img {
|
||||
.material-item__preview img,
|
||||
.material-item__preview video {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
@@ -430,6 +479,10 @@ onMounted(() => {
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.material-item__preview video {
|
||||
pointer-events: none; /* 禁用视频交互,避免点击播放 */
|
||||
}
|
||||
|
||||
.material-item__placeholder {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
|
||||
Reference in New Issue
Block a user