feat: extend SMS signature and setting file support
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="visible"
|
||||
title="选择图片"
|
||||
:title="props.acceptAll ? '选择文件' : '选择图片'"
|
||||
width="900px"
|
||||
append-to-body
|
||||
@close="handleClose"
|
||||
@@ -12,13 +12,13 @@
|
||||
<el-tab-pane label="文件库" name="fileLibrary">
|
||||
<div class="file-list-container">
|
||||
<div class="file-list-header">
|
||||
<h4>图片文件库</h4>
|
||||
<h4>{{ props.acceptAll ? '文件库' : '图片文件库' }}</h4>
|
||||
<div class="header-actions">
|
||||
<span v-if="props.multiple && selectedIds.size > 0" class="selected-count">
|
||||
已选 {{ selectedIds.size }} 个文件
|
||||
</span>
|
||||
<el-button type="primary" @click="switchToUpload" :icon="Upload">
|
||||
上传新图片
|
||||
{{ props.acceptAll ? '上传新文件' : '上传新图片' }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -52,10 +52,15 @@
|
||||
</div>
|
||||
<div class="file-preview">
|
||||
<img
|
||||
v-if="isImageFile(file.realName, file.url)"
|
||||
:src="processImageUrl(file.url)"
|
||||
:alt="file.realName"
|
||||
@error="handleImageError"
|
||||
/>
|
||||
<div v-else class="file-type-icon">
|
||||
<el-icon :size="32"><Document /></el-icon>
|
||||
<span class="file-ext">{{ getFileExt(file.realName) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="file-info">
|
||||
<p class="file-name" :title="file.realName">{{ file.realName }}</p>
|
||||
@@ -63,7 +68,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-empty v-if="filteredFileList.length === 0 && !loading" description="暂无图片文件" />
|
||||
<el-empty v-if="filteredFileList.length === 0 && !loading" :description="props.acceptAll ? '暂无文件' : '暂无图片文件'" />
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination-container" v-if="total > 0">
|
||||
@@ -81,14 +86,14 @@
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 上传图片 -->
|
||||
<el-tab-pane label="上传图片" name="upload">
|
||||
<!-- 上传文件 -->
|
||||
<el-tab-pane :label="props.acceptAll ? '上传文件' : '上传图片'" name="upload">
|
||||
<div class="upload-section">
|
||||
<el-upload
|
||||
:auto-upload="false"
|
||||
:show-file-list="false"
|
||||
:on-change="handleFileChange"
|
||||
accept="image/*"
|
||||
:accept="props.acceptAll ? undefined : 'image/*'"
|
||||
multiple
|
||||
drag
|
||||
>
|
||||
@@ -98,7 +103,7 @@
|
||||
</div>
|
||||
<template #tip>
|
||||
<div class="el-upload__tip">
|
||||
支持jpg、png、gif、webp等图片格式,单个文件不超过5MB
|
||||
{{ props.acceptAll ? '支持所有文件类型,单个文件不超过50MB' : '支持jpg、png、gif、webp等图片格式,单个文件不超过5MB' }}
|
||||
</div>
|
||||
</template>
|
||||
</el-upload>
|
||||
@@ -111,7 +116,10 @@
|
||||
</div>
|
||||
<div class="pending-list">
|
||||
<div v-for="(file, index) in pendingFiles" :key="index" class="pending-item">
|
||||
<img :src="file.previewUrl" class="pending-preview" />
|
||||
<img v-if="file.isImage" :src="file.previewUrl" class="pending-preview" />
|
||||
<div v-else class="pending-preview pending-file-icon">
|
||||
<el-icon :size="20"><Document /></el-icon>
|
||||
</div>
|
||||
<span class="pending-name" :title="file.name">{{ file.name }}</span>
|
||||
<span class="pending-size">{{ formatFileSize(file.size) }}</span>
|
||||
<el-button type="danger" link size="small" @click="removePendingFile(index)">移除</el-button>
|
||||
@@ -149,7 +157,7 @@
|
||||
<script setup>
|
||||
import { ref, watch, computed } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { Upload, UploadFilled, Search, Select, Delete } from '@element-plus/icons-vue'
|
||||
import { Upload, UploadFilled, Search, Select, Delete, Document } from '@element-plus/icons-vue'
|
||||
import { getFileList, getFileDetail, uploadFile } from '@/api/admin/file'
|
||||
|
||||
// Props
|
||||
@@ -165,6 +173,10 @@ const props = defineProps({
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
acceptAll: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
|
||||
@@ -349,22 +361,37 @@ const selectFile = (file) => {
|
||||
}
|
||||
}
|
||||
|
||||
// 判断是否为图片文件
|
||||
const isImageFile = (name, url) => {
|
||||
const imgExts = /\.(jpe?g|png|gif|webp|bmp|svg|ico|avif)$/i
|
||||
if (name && imgExts.test(name)) return true
|
||||
if (url && imgExts.test(url.split('?')[0])) return true
|
||||
return false
|
||||
}
|
||||
|
||||
const getFileExt = (name) => {
|
||||
if (!name) return ''
|
||||
const dotIndex = name.lastIndexOf('.')
|
||||
if (dotIndex === -1) return ''
|
||||
return name.slice(dotIndex + 1).toUpperCase()
|
||||
}
|
||||
|
||||
// 文件选择变化(收集待上传文件)
|
||||
const handleFileChange = (file) => {
|
||||
const rawFile = file.raw
|
||||
if (!rawFile) return
|
||||
|
||||
// 验证文件类型
|
||||
const isImage = rawFile.type.startsWith('image/')
|
||||
if (!isImage) {
|
||||
ElMessage.error(`${rawFile.name} 不是图片文件,已跳过`)
|
||||
return
|
||||
if (!props.acceptAll) {
|
||||
const isImage = rawFile.type.startsWith('image/')
|
||||
if (!isImage) {
|
||||
ElMessage.error(`${rawFile.name} 不是图片文件,已跳过`)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 验证文件大小
|
||||
const isLt5M = rawFile.size / 1024 / 1024 < 5
|
||||
if (!isLt5M) {
|
||||
ElMessage.error(`${rawFile.name} 超过 5MB,已跳过`)
|
||||
const sizeLimit = props.acceptAll ? 50 : 5
|
||||
if (rawFile.size / 1024 / 1024 > sizeLimit) {
|
||||
ElMessage.error(`${rawFile.name} 超过 ${sizeLimit}MB,已跳过`)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -372,12 +399,13 @@ const handleFileChange = (file) => {
|
||||
const exists = pendingFiles.value.some(f => f.name === rawFile.name && f.size === rawFile.size)
|
||||
if (exists) return
|
||||
|
||||
// 添加到待上传列表,生成本地预览URL
|
||||
const fileIsImage = rawFile.type.startsWith('image/')
|
||||
pendingFiles.value.push({
|
||||
raw: rawFile,
|
||||
name: rawFile.name,
|
||||
size: rawFile.size,
|
||||
previewUrl: URL.createObjectURL(rawFile)
|
||||
isImage: fileIsImage,
|
||||
previewUrl: fileIsImage ? URL.createObjectURL(rawFile) : ''
|
||||
})
|
||||
}
|
||||
|
||||
@@ -593,6 +621,25 @@ const handleConfirm = () => {
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.file-type-icon {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 4px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.file-ext {
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
color: #606266;
|
||||
max-width: 60px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.file-info {
|
||||
text-align: center;
|
||||
}
|
||||
@@ -670,6 +717,14 @@ const handleConfirm = () => {
|
||||
border: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
.pending-file-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #f5f7fa;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.pending-name {
|
||||
flex: 1;
|
||||
font-size: 13px;
|
||||
|
||||
Reference in New Issue
Block a user