feat(picture): 优化图片管理页面功能

- 新增MinIO存储服务选项支持
- 集成CoiImageViewer组件替换原生NImage组件
- 改进网格视图和表格视图的图片展示效果
- 移除冗余的图片错误处理函数,使用组件内置处理
- 统一存储服务类型的标签显示样式
- 提升图片预览和下载功能的用户体验
This commit is contained in:
Leo 2025-09-22 23:00:10 +08:00
parent a6dc2f90ae
commit 821b80d09a

View File

@ -191,13 +191,16 @@
<template #trigger> <template #trigger>
<div class="picture-card group relative bg-white rounded-lg shadow-sm border border-gray-200 overflow-hidden hover:shadow-md transition-shadow cursor-pointer"> <div class="picture-card group relative bg-white rounded-lg shadow-sm border border-gray-200 overflow-hidden hover:shadow-md transition-shadow cursor-pointer">
<!-- 图片预览 --> <!-- 图片预览 -->
<div class="aspect-square relative overflow-hidden bg-gray-100"> <div class="aspect-square relative overflow-hidden bg-gray-100 flex items-center justify-center">
<img <CoiImageViewer
:src="picture.picturePath" :src="picture.picturePath"
:alt="picture.pictureName" :alt="picture.pictureName"
class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-200" :width="200"
@error="handleImageError" :height="200"
> :previewable="true"
:title="`图片预览 - ${picture.pictureName}`"
class="w-full h-full"
/>
</div> </div>
<!-- 图片信息 --> <!-- 图片信息 -->
@ -344,6 +347,7 @@
:options="[ :options="[
{ label: 'LOCAL', value: 'LOCAL' }, { label: 'LOCAL', value: 'LOCAL' },
{ label: 'OSS', value: 'OSS' }, { label: 'OSS', value: 'OSS' },
{ label: 'MINIO', value: 'MINIO' },
]" ]"
/> />
</n-form-item> </n-form-item>
@ -402,11 +406,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { h, onMounted, ref } from 'vue' import { h, onMounted, ref } from 'vue'
import { NButton, NIcon, NImage, NP, NPopconfirm, NSpace, NSpin, NTag, NText, NTooltip, NUpload, NUploadDragger } from 'naive-ui' import { NButton, NIcon, NP, NPopconfirm, NSpace, NSpin, NTag, NText, NTooltip, NUpload, NUploadDragger } from 'naive-ui'
import type { DataTableColumns, DataTableInst, FormInst, UploadFileInfo, UploadInst } from 'naive-ui' import type { DataTableColumns, DataTableInst, FormInst, UploadFileInfo, UploadInst } from 'naive-ui'
import CoiEmpty from '@/components/common/CoiEmpty.vue' import CoiEmpty from '@/components/common/CoiEmpty.vue'
import CoiDialog from '@/components/common/CoiDialog.vue' import CoiDialog from '@/components/common/CoiDialog.vue'
import CoiPagination from '@/components/common/CoiPagination.vue' import CoiPagination from '@/components/common/CoiPagination.vue'
import CoiImageViewer from '@/components/common/CoiImageViewer.vue'
import { coiMsgBox, coiMsgError, coiMsgSuccess, coiMsgWarning } from '@/utils/coi' import { coiMsgBox, coiMsgError, coiMsgSuccess, coiMsgWarning } from '@/utils/coi'
import { usePermission } from '@/hooks/usePermission' import { usePermission } from '@/hooks/usePermission'
import { PERMISSIONS } from '@/constants/permissions' import { PERMISSIONS } from '@/constants/permissions'
@ -570,13 +575,13 @@ const columns: DataTableColumns<SysPictureVo> = [
}, },
render: (row) => { render: (row) => {
if (row.picturePath) { if (row.picturePath) {
return h(NImage, { return h(CoiImageViewer, {
src: row.picturePath, src: row.picturePath,
width: 45, alt: row.pictureName,
height: 30, width: 50,
objectFit: 'cover', height: 40,
previewDisabled: true, previewable: true,
class: 'rounded border', title: `图片预览 - ${row.pictureName}`,
}) })
} }
return '--' return '--'
@ -590,6 +595,7 @@ const columns: DataTableColumns<SysPictureVo> = [
render: (row) => { render: (row) => {
const serviceMap: Record<string, { type: 'success' | 'info' | 'warning', text: string }> = { const serviceMap: Record<string, { type: 'success' | 'info' | 'warning', text: string }> = {
1: { type: 'success', text: '本地存储' }, 1: { type: 'success', text: '本地存储' },
2: { type: 'info', text: 'MinIO存储' },
3: { type: 'warning', text: '阿里云OSS' }, 3: { type: 'warning', text: '阿里云OSS' },
} }
const config = serviceMap[row.pictureService] || { type: 'info', text: '未知' } const config = serviceMap[row.pictureService] || { type: 'info', text: '未知' }
@ -795,16 +801,11 @@ function handleDownload(row: SysPictureVo) {
} }
} }
//
function handleImageError(e: Event) {
const img = e.target as HTMLImageElement
img.src = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjQiIGhlaWdodD0iNjQiIHZpZXdCb3g9IjAgMCA2NCA2NCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9IjY0IiBoZWlnaHQ9IjY0IiBmaWxsPSIjRjVGNUY1Ii8+CjxwYXRoIGQ9Ik0yMCAyMEw0NCA0NEwyMCA0NFYyMFoiIGZpbGw9IiNEOUQ5RDkiLz4KPGNpcmNsZSBjeD0iMjgiIGN5PSIyOCIgcj0iNCIgZmlsbD0iI0Q5RDlEOSIvPgo8L3N2Zz4K'
}
// //
function getPictureServiceText(serviceType: string): string { function getPictureServiceText(serviceType: string): string {
const serviceMap: Record<string, string> = { const serviceMap: Record<string, string> = {
1: '本地存储', 1: '本地存储',
2: 'MinIO存储',
3: '阿里云OSS', 3: '阿里云OSS',
} }
return serviceMap[serviceType] || '未知' return serviceMap[serviceType] || '未知'