mirror of
https://github.com/DrizzleTime/Foxel.git
synced 2026-06-08 17:09:59 +08:00
feat(upload): add image format conversion and quality settings for uploads #6
This commit is contained in:
@@ -119,6 +119,8 @@ export async function uploadPicture(
|
||||
data: {
|
||||
permission?: number;
|
||||
albumId?: number;
|
||||
convertToFormat?: string;
|
||||
quality?: number;
|
||||
onProgress?: (percent: number) => void
|
||||
} = {}
|
||||
): Promise<BaseResult<PictureResponse>> {
|
||||
@@ -133,6 +135,14 @@ export async function uploadPicture(
|
||||
formData.append('albumId', data.albumId.toString());
|
||||
}
|
||||
|
||||
if (data.convertToFormat !== undefined) {
|
||||
formData.append('convertToFormat', data.convertToFormat.toString());
|
||||
}
|
||||
|
||||
if (data.quality !== undefined) {
|
||||
formData.append('quality', data.quality.toString());
|
||||
}
|
||||
|
||||
try {
|
||||
const token = localStorage.getItem('token');
|
||||
const headers: Record<string, string> = {};
|
||||
|
||||
@@ -103,10 +103,24 @@ export interface UploadFile {
|
||||
response?: PictureResponse; // 上传成功后的响应
|
||||
}
|
||||
|
||||
// 上传图片请求参数
|
||||
// 图片格式类型
|
||||
export type ImageFormat = 0 | 1 | 2 | 3;
|
||||
|
||||
// 添加常量对象提供运行时值
|
||||
export const ImageFormat = {
|
||||
Original: 0 as ImageFormat,
|
||||
Jpeg: 1 as ImageFormat,
|
||||
Png: 2 as ImageFormat,
|
||||
WebP: 3 as ImageFormat
|
||||
};
|
||||
|
||||
// 上传图片参数
|
||||
export interface UploadPictureParams {
|
||||
permission?: number; // 权限设置,默认为0(公开)
|
||||
albumId?: number; // 相册ID,可选
|
||||
permission?: number;
|
||||
albumId?: number;
|
||||
convertToFormat?: ImageFormat;
|
||||
quality?: number;
|
||||
onProgress?: (percent: number) => void;
|
||||
}
|
||||
|
||||
// 相册响应数据
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Modal, Upload, Button, Progress, message, Form, Select, Radio, Slider } from 'antd';
|
||||
import { Modal, Upload, Button, Progress, message, Form, Select, Radio, Slider, Divider, Alert } from 'antd';
|
||||
import { InboxOutlined } from '@ant-design/icons';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import type { UploadFile, UploadPictureParams, AlbumResponse } from '../../api';
|
||||
import { uploadPicture, getAlbums } from '../../api';
|
||||
import type { UploadFile, AlbumResponse } from '../../api';
|
||||
import { uploadPicture, getAlbums, ImageFormat } from '../../api';
|
||||
|
||||
const { Dragger } = Upload;
|
||||
const { Option } = Select;
|
||||
@@ -20,6 +20,8 @@ const ImageUploadDialog: React.FC<UploadDialogProps> = ({ visible, onClose, onUp
|
||||
const [form] = Form.useForm();
|
||||
const [albums, setAlbums] = useState<AlbumResponse[]>([]);
|
||||
const [concurrentUploads, setConcurrentUploads] = useState<number>(3);
|
||||
const [convertFormat, setConvertFormat] = useState<ImageFormat>(ImageFormat.Original);
|
||||
const [quality, setQuality] = useState<number>(95);
|
||||
|
||||
useEffect(() => {
|
||||
if (visible) {
|
||||
@@ -75,13 +77,23 @@ const ImageUploadDialog: React.FC<UploadDialogProps> = ({ visible, onClose, onUp
|
||||
setUploading(true);
|
||||
const values = await form.validateFields();
|
||||
|
||||
const params: UploadPictureParams = {};
|
||||
const params: { // 修改此处的类型定义
|
||||
permission?: number;
|
||||
albumId?: number;
|
||||
convertToFormat?: string; // 允许 string 类型
|
||||
quality?: number;
|
||||
} = {};
|
||||
|
||||
if (values.permission !== undefined) {
|
||||
params.permission = values.permission;
|
||||
}
|
||||
if (values.albumId) {
|
||||
params.albumId = values.albumId;
|
||||
}
|
||||
if (convertFormat !== ImageFormat.Original) {
|
||||
params.convertToFormat = convertFormat.toString(); // 现在类型匹配
|
||||
params.quality = quality;
|
||||
}
|
||||
|
||||
let successCount = 0;
|
||||
let failCount = 0;
|
||||
@@ -98,7 +110,7 @@ const ImageUploadDialog: React.FC<UploadDialogProps> = ({ visible, onClose, onUp
|
||||
|
||||
try {
|
||||
// 上传文件
|
||||
const result = await uploadPicture(item.file, {
|
||||
const result = await uploadPicture(item.file, { // 此处 params 类型现在匹配
|
||||
...params,
|
||||
onProgress: (percent) => {
|
||||
setUploadQueue((prev) =>
|
||||
@@ -205,6 +217,17 @@ const ImageUploadDialog: React.FC<UploadDialogProps> = ({ visible, onClose, onUp
|
||||
}
|
||||
};
|
||||
|
||||
// 获取格式名称
|
||||
const getFormatName = (format: ImageFormat) => {
|
||||
switch (format) {
|
||||
case ImageFormat.Original: return '保持原格式';
|
||||
case ImageFormat.Jpeg: return 'JPEG';
|
||||
case ImageFormat.Png: return 'PNG';
|
||||
case ImageFormat.WebP: return 'WebP';
|
||||
default: return '未知格式';
|
||||
}
|
||||
};
|
||||
|
||||
// 自定义上传列表项
|
||||
const renderUploadItem = (item: UploadFile) => {
|
||||
let statusIcon;
|
||||
@@ -305,9 +328,9 @@ const ImageUploadDialog: React.FC<UploadDialogProps> = ({ visible, onClose, onUp
|
||||
onClick={uploadFiles}
|
||||
>
|
||||
{uploading ? '正在上传...' : '开始上传'}
|
||||
</Button>,
|
||||
</Button>
|
||||
]}
|
||||
width={600}
|
||||
width={700}
|
||||
>
|
||||
<Form
|
||||
form={form}
|
||||
@@ -336,9 +359,53 @@ const ImageUploadDialog: React.FC<UploadDialogProps> = ({ visible, onClose, onUp
|
||||
<Radio value={0}>公开</Radio>
|
||||
<Radio value={1}>好友可见</Radio>
|
||||
<Radio value={2}>仅自己</Radio>
|
||||
|
||||
</Radio.Group>
|
||||
</Form.Item>
|
||||
|
||||
<Divider orientation="left">格式转换设置</Divider>
|
||||
|
||||
<Form.Item label="输出格式">
|
||||
<Radio.Group
|
||||
value={convertFormat}
|
||||
onChange={(e) => setConvertFormat(e.target.value)}
|
||||
optionType="button"
|
||||
buttonStyle="solid"
|
||||
style={{ display: 'flex', flexWrap: 'wrap', gap: '8px' }}
|
||||
>
|
||||
<Radio.Button value={ImageFormat.Original}>保持原格式</Radio.Button>
|
||||
<Radio.Button value={ImageFormat.Jpeg}>JPEG (.jpg)</Radio.Button>
|
||||
<Radio.Button value={ImageFormat.Png}>PNG (.png)</Radio.Button>
|
||||
<Radio.Button value={ImageFormat.WebP}>WebP (.webp)</Radio.Button>
|
||||
</Radio.Group>
|
||||
</Form.Item>
|
||||
|
||||
{convertFormat !== ImageFormat.Original && (
|
||||
<>
|
||||
{convertFormat === ImageFormat.Png ? (
|
||||
<Alert
|
||||
message="提示"
|
||||
description={`${getFormatName(convertFormat)} 格式为无损压缩,不支持质量调节。`}
|
||||
type="info"
|
||||
showIcon
|
||||
style={{ marginBottom: '16px' }}
|
||||
/>
|
||||
) : (
|
||||
<Form.Item label={`图片质量 (${quality}%)`}>
|
||||
<Slider
|
||||
min={50}
|
||||
max={100}
|
||||
value={quality}
|
||||
onChange={setQuality}
|
||||
marks={{ 50: '50%', 75: '75%', 90: '90%', 95: '95%', 100: '100%' }}
|
||||
tooltip={{ formatter: (value) => `${value}%` }}
|
||||
/>
|
||||
<div style={{ fontSize: '12px', color: '#666', marginTop: '4px' }}>
|
||||
质量越高文件越大,建议使用 85-95% 的质量设置
|
||||
</div>
|
||||
</Form.Item>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
<Form.Item
|
||||
name="concurrentUploads"
|
||||
@@ -367,6 +434,14 @@ const ImageUploadDialog: React.FC<UploadDialogProps> = ({ visible, onClose, onUp
|
||||
<p className="ant-upload-text">点击或拖拽图片到此区域上传</p>
|
||||
<p className="ant-upload-hint">
|
||||
支持单个或批量上传,图片大小不超过10MB
|
||||
{convertFormat !== ImageFormat.Original && (
|
||||
<>
|
||||
<br />
|
||||
<span style={{ color: '#1890ff' }}>
|
||||
将转换为 {getFormatName(convertFormat)} 格式
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
</p>
|
||||
</Dragger>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user