Fix API compatibility and add user/role/permission and asset import/export
This commit is contained in:
424
backend/FILE_MANAGEMENT_QUICKSTART.md
Normal file
424
backend/FILE_MANAGEMENT_QUICKSTART.md
Normal file
@@ -0,0 +1,424 @@
|
||||
# 文件管理模块快速开始指南
|
||||
|
||||
## 🚀 快速开始
|
||||
|
||||
### 后端启动
|
||||
|
||||
#### 1. 数据库迁移
|
||||
```bash
|
||||
cd C:/Users/Administrator/asset_management_backend
|
||||
|
||||
# 激活虚拟环境
|
||||
python -m venv venv
|
||||
venv\Scripts\activate # Windows
|
||||
# source venv/bin/activate # Linux/Mac
|
||||
|
||||
# 安装依赖
|
||||
pip install -r requirements.txt
|
||||
pip install python-multipart pillow
|
||||
|
||||
# 运行迁移
|
||||
alembic upgrade head
|
||||
```
|
||||
|
||||
#### 2. 创建上传目录
|
||||
```bash
|
||||
mkdir -p uploads/images
|
||||
mkdir -p uploads/documents
|
||||
mkdir -p uploads/thumbnails
|
||||
mkdir -p uploads/temp
|
||||
```
|
||||
|
||||
#### 3. 启动服务
|
||||
```bash
|
||||
python run.py
|
||||
```
|
||||
|
||||
后端服务将运行在 `http://localhost:8000`
|
||||
|
||||
### 前端启动
|
||||
|
||||
#### 1. 安装依赖
|
||||
```bash
|
||||
cd C:/Users/Administrator/asset-management-frontend
|
||||
|
||||
npm install
|
||||
```
|
||||
|
||||
#### 2. 启动开发服务器
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
前端服务将运行在 `http://localhost:5173`
|
||||
|
||||
## 📝 API测试示例
|
||||
|
||||
### 1. 文件上传(使用curl)
|
||||
|
||||
```bash
|
||||
# 上传文件
|
||||
curl -X POST http://localhost:8000/api/v1/files/upload \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-F "file=@/path/to/your/file.jpg" \
|
||||
-F "remark=测试文件"
|
||||
```
|
||||
|
||||
### 2. 获取文件列表
|
||||
```bash
|
||||
curl -X GET "http://localhost:8000/api/v1/files?page=1&page_size=20" \
|
||||
-H "Authorization: Bearer YOUR_TOKEN"
|
||||
```
|
||||
|
||||
### 3. 下载文件
|
||||
```bash
|
||||
curl -X GET http://localhost:8000/api/v1/files/1/download \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-o downloaded_file.jpg
|
||||
```
|
||||
|
||||
### 4. 生成分享链接
|
||||
```bash
|
||||
curl -X POST http://localhost:8000/api/v1/files/1/share \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"expire_days": 7}'
|
||||
```
|
||||
|
||||
## 💻 前端使用示例
|
||||
|
||||
### 1. 在页面中使用文件上传组件
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div>
|
||||
<file-upload
|
||||
:auto-upload="false"
|
||||
:show-progress="true"
|
||||
:show-image-preview="true"
|
||||
@upload-success="handleUploadSuccess"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import FileUpload from '@/components/file/FileUpload.vue'
|
||||
|
||||
const handleUploadSuccess = (response, file) => {
|
||||
ElMessage.success(`文件 ${file.name} 上传成功`)
|
||||
console.log('上传响应:', response)
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
### 2. 在页面中使用文件列表组件
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div>
|
||||
<file-list />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import FileList from '@/components/file/FileList.vue'
|
||||
</script>
|
||||
```
|
||||
|
||||
### 3. 使用文件API
|
||||
|
||||
```typescript
|
||||
import { uploadFile, getFileList, downloadFile } from '@/api/file'
|
||||
|
||||
// 上传文件
|
||||
const handleUpload = async (file: File) => {
|
||||
try {
|
||||
const response = await uploadFile(file, { remark: '测试' })
|
||||
console.log('上传成功:', response)
|
||||
} catch (error) {
|
||||
console.error('上传失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取文件列表
|
||||
const fetchFiles = async () => {
|
||||
try {
|
||||
const files = await getFileList({
|
||||
page: 1,
|
||||
page_size: 20,
|
||||
keyword: 'test'
|
||||
})
|
||||
console.log('文件列表:', files)
|
||||
} catch (error) {
|
||||
console.error('获取失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 下载文件
|
||||
const handleDownload = async (fileId: number, fileName: string) => {
|
||||
try {
|
||||
await downloadFile(fileId)
|
||||
// 注意:实际下载需要在响应头处理
|
||||
window.open(`http://localhost:8000/api/v1/files/${fileId}/download`)
|
||||
} catch (error) {
|
||||
console.error('下载失败:', error)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🎯 常见功能实现
|
||||
|
||||
### 1. 批量上传
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<file-upload
|
||||
:multiple="true"
|
||||
:limit="10"
|
||||
:auto-upload="false"
|
||||
ref="uploadRef"
|
||||
>
|
||||
<template #tip>
|
||||
<div>最多可上传10个文件</div>
|
||||
</template>
|
||||
</file-upload>
|
||||
|
||||
<el-button @click="submitUpload">开始上传</el-button>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import FileUpload from '@/components/file/FileUpload.vue'
|
||||
|
||||
const uploadRef = ref()
|
||||
|
||||
const submitUpload = () => {
|
||||
uploadRef.value.submitUpload()
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
### 2. 图片预览
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div>
|
||||
<el-button @click="showPreview = true">预览图片</el-button>
|
||||
|
||||
<image-preview
|
||||
v-model:visible="showPreview"
|
||||
:images="images"
|
||||
:initial-index="0"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import ImagePreview from '@/components/file/ImagePreview.vue'
|
||||
|
||||
const showPreview = ref(false)
|
||||
const images = ref([
|
||||
{
|
||||
url: 'http://localhost:8000/api/v1/files/1/preview',
|
||||
name: '图片1.jpg'
|
||||
},
|
||||
{
|
||||
url: 'http://localhost:8000/api/v1/files/2/preview',
|
||||
name: '图片2.jpg'
|
||||
}
|
||||
])
|
||||
</script>
|
||||
```
|
||||
|
||||
### 3. 文件分享
|
||||
|
||||
```typescript
|
||||
import { createShareLink } from '@/api/file'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
const shareFile = async (fileId: number) => {
|
||||
try {
|
||||
const result = await createShareLink(fileId, 7) // 7天有效期
|
||||
ElMessage.success(`分享链接: ${result.share_url}`)
|
||||
|
||||
// 复制到剪贴板
|
||||
navigator.clipboard.writeText(result.share_url)
|
||||
} catch (error) {
|
||||
ElMessage.error('生成分享链接失败')
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 大文件分片上传
|
||||
|
||||
```typescript
|
||||
import { initChunkUpload, uploadChunk, completeChunkUpload } from '@/api/file'
|
||||
|
||||
const uploadLargeFile = async (file: File) => {
|
||||
const CHUNK_SIZE = 5 * 1024 * 1024 // 5MB每片
|
||||
const totalChunks = Math.ceil(file.size / CHUNK_SIZE)
|
||||
|
||||
// 1. 初始化
|
||||
const { upload_id } = await initChunkUpload({
|
||||
file_name: file.name,
|
||||
file_size: file.size,
|
||||
file_type: file.type,
|
||||
total_chunks: totalChunks
|
||||
})
|
||||
|
||||
// 2. 上传分片
|
||||
for (let i = 0; i < totalChunks; i++) {
|
||||
const start = i * CHUNK_SIZE
|
||||
const end = Math.min(start + CHUNK_SIZE, file.size)
|
||||
const chunk = file.slice(start, end)
|
||||
|
||||
await uploadChunk(upload_id, i, chunk)
|
||||
console.log(`分片 ${i + 1}/${totalChunks} 上传完成`)
|
||||
}
|
||||
|
||||
// 3. 完成上传
|
||||
const result = await completeChunkUpload({
|
||||
upload_id: upload_id,
|
||||
file_name: file.name
|
||||
})
|
||||
|
||||
console.log('上传完成:', result)
|
||||
}
|
||||
```
|
||||
|
||||
## 🔍 API响应示例
|
||||
|
||||
### 上传文件响应
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"file_name": "a1b2c3d4-e5f6-7890-abcd-ef1234567890.jpg",
|
||||
"original_name": "photo.jpg",
|
||||
"file_size": 1024000,
|
||||
"file_type": "image/jpeg",
|
||||
"file_path": "uploads/2026/01/24/a1b2c3d4-e5f6-7890-abcd-ef1234567890.jpg",
|
||||
"download_url": "http://localhost:8000/api/v1/files/1/download",
|
||||
"preview_url": "http://localhost:8000/api/v1/files/1/preview",
|
||||
"message": "上传成功"
|
||||
}
|
||||
```
|
||||
|
||||
### 文件列表响应
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"file_name": "uuid.jpg",
|
||||
"original_name": "photo.jpg",
|
||||
"file_size": 1024000,
|
||||
"file_type": "image/jpeg",
|
||||
"file_ext": "jpg",
|
||||
"uploader_id": 1,
|
||||
"uploader_name": "张三",
|
||||
"upload_time": "2026-01-24T10:30:00",
|
||||
"thumbnail_path": "uploads/thumbnails/2026/01/24/thumb_uuid.jpg",
|
||||
"download_count": 5,
|
||||
"remark": null
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### 分享链接响应
|
||||
```json
|
||||
{
|
||||
"share_code": "AbCdEf1234567890",
|
||||
"share_url": "http://localhost:8000/api/v1/files/share/AbCdEf1234567890",
|
||||
"expire_time": "2026-01-31T10:30:00"
|
||||
}
|
||||
```
|
||||
|
||||
### 文件统计响应
|
||||
```json
|
||||
{
|
||||
"total_files": 150,
|
||||
"total_size": 524288000,
|
||||
"total_size_human": "500.00 MB",
|
||||
"type_distribution": {
|
||||
"image/jpeg": 80,
|
||||
"image/png": 40,
|
||||
"application/pdf": 30
|
||||
},
|
||||
"upload_today": 10,
|
||||
"upload_this_week": 50,
|
||||
"upload_this_month": 120,
|
||||
"top_uploaders": [
|
||||
{ "uploader_id": 1, "count": 50 },
|
||||
{ "uploader_id": 2, "count": 30 }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 🛠️ 故障排除
|
||||
|
||||
### 问题1:上传文件失败
|
||||
**错误信息**:`413 Request Entity Too Large`
|
||||
|
||||
**解决方案**:
|
||||
检查Nginx配置(如果使用):
|
||||
```nginx
|
||||
client_max_body_size 100M;
|
||||
```
|
||||
|
||||
### 问题2:文件类型不支持
|
||||
**错误信息**:`不支持的文件类型`
|
||||
|
||||
**解决方案**:
|
||||
在 `app/services/file_service.py` 中添加文件类型到白名单:
|
||||
```python
|
||||
ALLOWED_MIME_TYPES = {
|
||||
'image/webp', # 添加新类型
|
||||
# ... 其他类型
|
||||
}
|
||||
```
|
||||
|
||||
### 问题3:缩略图生成失败
|
||||
**错误信息**:`生成缩略图失败`
|
||||
|
||||
**解决方案**:
|
||||
确保安装了Pillow库:
|
||||
```bash
|
||||
pip install pillow
|
||||
```
|
||||
|
||||
### 问题4:前端无法预览图片
|
||||
**错误信息**:CORS错误
|
||||
|
||||
**解决方案**:
|
||||
在后端添加CORS中间件:
|
||||
```python
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["http://localhost:5173"],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
```
|
||||
|
||||
## 📚 更多资源
|
||||
|
||||
- [完整文档](./FILE_MANAGEMENT_README.md)
|
||||
- [API文档](./API_QUICK_REFERENCE.md)
|
||||
- [项目主文档](./README.md)
|
||||
|
||||
## 💡 提示
|
||||
|
||||
1. **开发环境**:使用小文件测试,避免上传大文件
|
||||
2. **生产环境**:建议使用云存储服务(OSS、S3等)
|
||||
3. **安全性**:生产环境务必配置文件类型和大小限制
|
||||
4. **性能**:大文件使用分片上传,提高上传成功率
|
||||
5. **监控**:记录文件上传、下载日志,便于问题追踪
|
||||
|
||||
---
|
||||
|
||||
如有问题,请查看完整文档或联系开发团队。
|
||||
Reference in New Issue
Block a user