This commit is contained in:
2026-01-20 21:29:33 +08:00
parent 0f2a9a4cc3
commit 8e55f7de9d
7 changed files with 3 additions and 672 deletions

View File

@@ -1,335 +0,0 @@
# 上传组件使用说明
本项目提供了两个基于 Ant Design Vue 的二次封装上传组件:
1. **ImageUpload** - 图片上传组件
2. **FileUpload** - 文件上传组件
## ImageUpload 图片上传组件
### 功能特性
- 支持单图和多图上传
- 图片预览功能(支持大图预览)
- 支持拖拽上传(带拖拽视觉反馈)
- 文件大小限制(从配置文件读取)
- 图片尺寸限制(支持最小/最大宽高限制)
- 上传进度显示和上传状态反馈
- 错误文件自动过滤
- 上传成功/失败事件回调
- 自定义上传按钮文字和提示信息
- 禁用状态下隐藏删除图标
- 自动上传到服务器
- 支持 v-model 双向绑定
### Props 参数
| 参数 | 说明 | 类型 | 默认值 |
|------|------|------|--------|
| v-model / modelValue | 图片列表(单图传字符串,多图传数组) | String / Array | [] |
| maxCount | 最大上传数量 | Number | 1 |
| accept | 接受的文件类型 | String | 'image/*' |
| disabled | 是否禁用 | Boolean | false |
| returnUrl | 是否返回URLtrue或完整文件列表false | Boolean | true |
| uploadText | 上传按钮文字 | String | '上传图片' |
| tip | 提示文字(显示在上传按钮下方) | String | '' |
| minWidth | 图片最小宽度像素0表示不限制 | Number | 0 |
| maxWidth | 图片最大宽度像素0表示不限制 | Number | 0 |
| minHeight | 图片最小高度像素0表示不限制 | Number | 0 |
| maxHeight | 图片最大高度像素0表示不限制 | Number | 0 |
| confirmBeforeRemove | 删除前是否确认 | Boolean | false |
| customUploadBtn | 自定义上传按钮内容函数返回VNode | Function | null |
### Events 事件
| 事件名 | 说明 | 回调参数 |
|--------|------|----------|
| update:modelValue | 值变化时触发 | value: 图片URL或URL数组 |
| change | 文件列表变化时触发 | value: 图片URL或URL数组, fileList: 完整文件列表 |
| preview | 预览图片时触发 | file: 当前预览的文件对象 |
| uploadSuccess | 上传成功时触发 | data: 响应数据, file: 上传的文件 |
| uploadError | 上传失败时触发 | errorMsg: 错误信息, file: 上传的文件 |
### 使用示例
#### 单图上传
```vue
<template>
<div>
<ImageUpload v-model="imageUrl" />
<p>图片URL: {{ imageUrl }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue'
import ImageUpload from '@/components/ImageUpload/index.vue'
const imageUrl = ref('')
</script>
```
#### 多图上传
```vue
<template>
<div>
<ImageUpload
v-model="imageList"
:max-count="5"
@change="handleChange"
/>
</div>
</template>
<script setup>
import { ref } from 'vue'
import ImageUpload from '@/components/ImageUpload/index.vue'
const imageList = ref([])
const handleChange = (value, fileList) => {
console.log('图片URL数组:', value)
console.log('完整文件列表:', fileList)
}
</script>
```
#### 限制文件类型
```vue
<template>
<ImageUpload
v-model="imageUrl"
accept="image/jpeg,image/png"
/>
</template>
```
#### 限制图片尺寸
```vue
<template>
<ImageUpload
v-model="imageUrl"
:min-width="800"
:max-width="1920"
:min-height="600"
:max-height="1080"
tip="尺寸要求800x600 ~ 1920x1080"
/>
</template>
```
#### 自定义上传文字和提示
```vue
<template>
<ImageUpload
v-model="imageUrl"
upload-text="点击上传"
tip="支持 JPG、PNG 格式,不超过 10MB"
/>
</template>
```
#### 监听上传事件
```vue
<template>
<ImageUpload
v-model="imageUrl"
@upload-success="handleUploadSuccess"
@upload-error="handleUploadError"
@preview="handlePreview"
/>
</template>
<script setup>
import ImageUpload from '@/components/ImageUpload/index.vue'
const handleUploadSuccess = (data, file) => {
console.log('上传成功:', data)
console.log('文件信息:', file)
}
const handleUploadError = (errorMsg, file) => {
console.log('上传失败:', errorMsg)
console.log('文件信息:', file)
}
const handlePreview = (file) => {
console.log('预览文件:', file)
}
</script>
```
---
## FileUpload 文件上传组件
### 功能特性
- 支持单文件和多文件上传
- 文件列表展示
- 支持多选上传
- 文件大小限制(从配置文件读取)
- 自动上传到服务器
- 支持 v-model 双向绑定
### Props 参数
| 参数 | 说明 | 类型 | 默认值 |
|------|------|------|--------|
| v-model / modelValue | 文件列表(单文件传字符串,多文件传数组) | String / Array | [] |
| maxCount | 最大上传数量 | Number | 1 |
| accept | 接受的文件类型(例如 '.pdf,.doc,.docx' 或 '*' | String | '*' |
| disabled | 是否禁用 | Boolean | false |
| multiple | 是否支持多选 | Boolean | false |
| returnUrl | 是否返回URLtrue或完整文件列表false | Boolean | true |
### Events 事件
| 事件名 | 说明 | 回调参数 |
|--------|------|----------|
| update:modelValue | 值变化时触发 | value: 文件URL或URL数组 |
| change | 文件列表变化时触发 | value: 文件URL或URL数组, fileList: 完整文件列表 |
| remove | 移除文件时触发 | file: 被移除的文件对象 |
### 使用示例
#### 单文件上传
```vue
<template>
<div>
<FileUpload v-model="fileUrl" />
<p>文件URL: {{ fileUrl }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue'
import FileUpload from '@/components/FileUpload/index.vue'
const fileUrl = ref('')
</script>
```
#### 多文件上传
```vue
<template>
<div>
<FileUpload
v-model="fileList"
:max-count="10"
:multiple="true"
@change="handleChange"
/>
</div>
</template>
<script setup>
import { ref } from 'vue'
import FileUpload from '@/components/FileUpload/index.vue'
const fileList = ref([])
const handleChange = (value, fileList) => {
console.log('文件URL数组:', value)
console.log('完整文件列表:', fileList)
}
</script>
```
#### 限制文件类型
```vue
<template>
<FileUpload
v-model="fileUrl"
accept=".pdf,.doc,.docx,.xls,.xlsx"
/>
</template>
```
#### 监听文件移除
```vue
<template>
<FileUpload
v-model="fileList"
@remove="handleRemove"
/>
</template>
<script setup>
import FileUpload from '@/components/FileUpload/index.vue'
const handleRemove = (file) => {
console.log('移除的文件:', file)
}
</script>
```
---
## 配置说明
上传组件的配置位于 `src/config/upload.js` 文件中:
```javascript
export default {
apiObj: systemAPI.upload, // 图片上传请求API对象
filename: "file", // form请求时文件的key
successCode: 1, // 请求完成代码
maxSize: 10, // 最大图片大小 默认10MB
parseData: function (res) {
return {
code: res.code, // 分析状态字段结构
fileName: res.data.name, // 分析文件名称
src: res.data.url, // 分析图片远程地址结构
msg: res.message // 分析描述字段结构
}
},
apiObjFile: systemAPI.upload, // 文件上传请求API对象
maxSizeFile: 10 // 最大文件大小 默认10MB
}
```
### 配置项说明
| 配置项 | 说明 |
|--------|------|
| apiObj | 图片上传API方法 |
| filename | FormData 中文件的字段名 |
| successCode | 上传成功的响应码 |
| maxSize | 图片最大大小限制MB |
| parseData | 响应数据解析函数,将后端响应转换为标准格式 |
| apiObjFile | 文件上传API方法如未配置则使用 apiObj |
| maxSizeFile | 文件最大大小限制MB |
## 注意事项
1. **v-model 数据格式**
- 单图/单文件上传:使用字符串类型 `imageUrl = 'http://example.com/image.jpg'`
- 多图/多文件上传:使用数组类型 `imageList = ['http://example.com/1.jpg', 'http://example.com/2.jpg']`
2. **返回值控制**
- `returnUrl: true`(默认):返回 URL 字符串或数组
- `returnUrl: false`:返回完整的文件列表对象(包含 uid, name, status, url 等字段)
3. **API 响应格式**
- 确保后端 API 返回的数据格式与 `parseData` 函数的解析逻辑一致
4. **文件大小限制**
- 图片上传使用 `maxSize` 配置
- 文件上传使用 `maxSizeFile` 配置
5. **图片尺寸限制**
- 设置 `minWidth``maxWidth``minHeight``maxHeight` 可以限制图片尺寸
- 尺寸校验会在上传前进行,不符合要求的文件将被拒绝
- 推荐配合 `tip` 属性显示尺寸要求提示
6. **上传状态反馈**
- 上传过程中显示加载动画
- 上传成功/失败会显示相应的提示消息
- 可通过 `@upload-success``@upload-error` 事件监听上传结果
7. **拖拽上传**
- 组件支持拖拽上传,拖拽时会有视觉反馈
- 拖拽区域会显示蓝色边框和背景色变化
8. **错误处理**
- 上传失败的文件会自动从列表中过滤
- 只有上传成功的文件会被包含在最终结果中

View File

@@ -53,23 +53,3 @@ watch(
{ immediate: true } { immediate: true }
) )
</script> </script>
<style scoped lang="scss">
.breadcrumb {
font-size: 14px;
.no-redirect {
color: #97a8be;
cursor: text;
}
a {
color: #1890ff;
cursor: pointer;
&:hover {
color: #40a9ff;
}
}
}
</style>

View File

@@ -206,7 +206,7 @@ const handleLanguageChange = ({ key }) => {
const handleMenuClick = ({ key }) => { const handleMenuClick = ({ key }) => {
switch (key) { switch (key) {
case 'profile': case 'profile':
router.push('/profile') router.push('/ucenter')
break break
case 'settings': case 'settings':
// 系统设置功能暂未实现 // 系统设置功能暂未实现

View File

@@ -183,8 +183,8 @@
<script setup> <script setup>
import { ref } from 'vue' import { ref } from 'vue'
import ImageUpload from '@/components/ImageUpload/index.vue' import ImageUpload from '@/components/scUpload/index.vue'
import FileUpload from '@/components/FileUpload/index.vue' import FileUpload from '@/components/scUpload/file.vue'
// 单图上传 // 单图上传
const singleImage = ref('') const singleImage = ref('')

View File

@@ -1,314 +0,0 @@
<template>
<div class="upload-demo">
<a-card title="图片上传组件示例" class="demo-card">
<a-row :gutter="24">
<a-col :span="12">
<a-card type="inner" title="单图上传">
<ImageUpload v-model="singleImage" />
<div class="result">
<strong>结果</strong>
<p>{{ singleImage || '暂无图片' }}</p>
</div>
</a-card>
</a-col>
<a-col :span="12">
<a-card type="inner" title="多图上传最多5张">
<ImageUpload
v-model="multipleImages"
:max-count="5"
@change="handleImageChange"
/>
<div class="result">
<strong>结果</strong>
<p v-if="multipleImages.length > 0">
{{ multipleImages.join(', ') }}
</p>
<p v-else>暂无图片</p>
</div>
</a-card>
</a-col>
</a-row>
</a-card>
<a-card title="图片尺寸限制示例" class="demo-card">
<a-row :gutter="24">
<a-col :span="12">
<a-card type="inner" title="限制图片尺寸 800x600">
<ImageUpload
v-model="sizeImage"
:min-width="800"
:max-width="1920"
:min-height="600"
:max-height="1080"
tip="尺寸要求800x600 ~ 1920x1080"
/>
<div class="result">
<strong>结果</strong>
<p>{{ sizeImage || '暂无图片' }}</p>
</div>
</a-card>
</a-col>
<a-col :span="12">
<a-card type="inner" title="自定义上传文字">
<ImageUpload
v-model="customImage"
upload-text="点击选择图片"
tip="支持 JPG、PNG 格式,最大 10MB"
/>
<div class="result">
<strong>结果</strong>
<p>{{ customImage || '暂无图片' }}</p>
</div>
</a-card>
</a-col>
</a-row>
</a-card>
<a-card title="上传事件监听示例" class="demo-card">
<a-row :gutter="24">
<a-col :span="12">
<a-card type="inner" title="监听上传事件">
<ImageUpload
v-model="eventImage"
@upload-success="handleUploadSuccess"
@upload-error="handleUploadError"
@preview="handlePreview"
/>
<div class="result">
<strong>结果</strong>
<p>{{ eventImage || '暂无图片' }}</p>
<p v-if="eventLog" class="event-log">
<strong>事件日志</strong>
<pre>{{ eventLog }}</pre>
</p>
</div>
</a-card>
</a-col>
</a-row>
</a-card>
<a-card title="文件上传组件示例" class="demo-card">
<a-row :gutter="24">
<a-col :span="12">
<a-card type="inner" title="单文件上传">
<FileUpload v-model="singleFile" />
<div class="result">
<strong>结果</strong>
<p>{{ singleFile || '暂无文件' }}</p>
</div>
</a-card>
</a-col>
<a-col :span="12">
<a-card type="inner" title="多文件上传">
<FileUpload
v-model="multipleFiles"
:max-count="10"
:multiple="true"
@change="handleFileChange"
@remove="handleFileRemove"
/>
<div class="result">
<strong>结果</strong>
<p v-if="multipleFiles.length > 0">
{{ multipleFiles.join(', ') }}
</p>
<p v-else>暂无文件</p>
</div>
</a-card>
</a-col>
</a-row>
</a-card>
<a-card title="限制文件类型示例" class="demo-card">
<a-row :gutter="24">
<a-col :span="12">
<a-card type="inner" title="仅支持 JPG/PNG 图片">
<ImageUpload
v-model="jpgImage"
accept="image/jpeg,image/png"
/>
</a-card>
</a-col>
<a-col :span="12">
<a-card type="inner" title="仅支持 PDF/Word 文档">
<FileUpload
v-model="documentFile"
accept=".pdf,.doc,.docx"
/>
</a-card>
</a-col>
</a-row>
</a-card>
<a-card title="禁用状态示例" class="demo-card">
<a-row :gutter="24">
<a-col :span="12">
<a-card type="inner" title="禁用图片上传">
<ImageUpload
v-model="disabledImage"
:disabled="true"
/>
</a-card>
</a-col>
<a-col :span="12">
<a-card type="inner" title="禁用文件上传">
<FileUpload
v-model="disabledFile"
:disabled="true"
/>
</a-card>
</a-col>
</a-row>
</a-card>
<a-card title="返回完整文件列表示例" class="demo-card">
<a-row :gutter="24">
<a-col :span="12">
<a-card type="inner" title="返回完整文件对象">
<ImageUpload
v-model="fullFileList"
:return-url="false"
@change="handleFullListChange"
/>
<div class="result">
<strong>完整文件列表</strong>
<pre>{{ JSON.stringify(fullFileList, null, 2) }}</pre>
</div>
</a-card>
</a-col>
</a-row>
</a-card>
</div>
</template>
<script setup>
import { ref } from 'vue'
import ImageUpload from '@/components/ImageUpload/index.vue'
import FileUpload from '@/components/FileUpload/index.vue'
// 单图上传
const singleImage = ref('')
// 多图上传
const multipleImages = ref([])
// 单文件上传
const singleFile = ref('')
// 多文件上传
const multipleFiles = ref([])
// 限制类型
const jpgImage = ref('')
const documentFile = ref('')
// 禁用状态
const disabledImage = ref('')
const disabledFile = ref('')
// 完整文件列表
const fullFileList = ref([])
// 新增示例
const sizeImage = ref('')
const customImage = ref('')
const eventImage = ref('')
const eventLog = ref('')
// 图片变化事件
const handleImageChange = (value, fileList) => {
console.log('图片URL数组:', value)
console.log('完整文件列表:', fileList)
}
// 文件变化事件
const handleFileChange = (value, fileList) => {
console.log('文件URL数组:', value)
console.log('完整文件列表:', fileList)
}
// 文件移除事件
const handleFileRemove = (file) => {
console.log('移除的文件:', file)
}
// 完整文件列表变化事件
const handleFullListChange = (value, fileList) => {
console.log('完整文件列表:', fileList)
}
// 上传成功事件
const handleUploadSuccess = (data, file) => {
eventLog.value = `上传成功\n文件名: ${file.name}\n响应数据: ${JSON.stringify(data, null, 2)}`
console.log('上传成功:', data, file)
}
// 上传失败事件
const handleUploadError = (errorMsg, file) => {
eventLog.value = `上传失败\n文件名: ${file.name}\n错误信息: ${errorMsg}`
console.log('上传失败:', errorMsg, file)
}
// 预览事件
const handlePreview = (file) => {
eventLog.value = `预览图片\n文件名: ${file.name}\n状态: ${file.status}`
console.log('预览文件:', file)
}
</script>
<style scoped>
.upload-demo {
padding: 24px;
}
.demo-card {
margin-bottom: 24px;
}
.demo-card :deep(.ant-card-body) {
padding: 24px;
}
.demo-card :deep(.ant-card-head-title) {
font-size: 16px;
font-weight: 600;
}
.result {
margin-top: 16px;
padding: 12px;
background-color: #f5f5f5;
border-radius: 4px;
}
.result p {
margin: 8px 0 0 0;
word-break: break-all;
}
.result pre {
margin: 8px 0 0 0;
max-height: 200px;
overflow-y: auto;
background: #fff;
padding: 8px;
border-radius: 4px;
}
.event-log {
margin-top: 12px !important;
padding: 8px !important;
background-color: #f0f2f5 !important;
border-radius: 4px;
}
.event-log pre {
margin: 8px 0 0 0;
max-height: 150px;
overflow-y: auto;
background: #fff;
padding: 8px;
border-radius: 4px;
font-size: 11px;
}
</style>