mirror of
https://github.com/DrizzleTime/Foxel.git
synced 2026-09-04 23:29:00 +08:00
feat(upload): add storage mode selection and retrieval for image uploads
This commit is contained in:
@@ -13,6 +13,31 @@ namespace Foxel.Api.Management;
|
|||||||
[Route("api/management/storage")]
|
[Route("api/management/storage")]
|
||||||
public class StorageManagementController(IStorageManagementService storageManagementService) : BaseApiController
|
public class StorageManagementController(IStorageManagementService storageManagementService) : BaseApiController
|
||||||
{
|
{
|
||||||
|
[AllowAnonymous]
|
||||||
|
[HttpGet("get_available_modes")]
|
||||||
|
public async Task<ActionResult<BaseResult<List<StorageModeResponse>>>> GetAvailableStorageModes()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await storageManagementService.GetStorageModesAsync();
|
||||||
|
var filteredModes = result.Data!
|
||||||
|
.Where(mode => mode.IsEnabled)
|
||||||
|
.Select(mode => new StorageModeResponse
|
||||||
|
{
|
||||||
|
Id = mode.Id,
|
||||||
|
Name = mode.Name,
|
||||||
|
StorageType = mode.StorageType,
|
||||||
|
IsEnabled = mode.IsEnabled
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
|
return Success(filteredModes, "Available storage modes retrieved successfully.");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Error<List<StorageModeResponse>>($"Failed to get available storage modes: {ex.Message}", 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[HttpGet("get_modes")]
|
[HttpGet("get_modes")]
|
||||||
public async Task<ActionResult<PaginatedResult<StorageModeResponse>>> GetStorageModes(
|
public async Task<ActionResult<PaginatedResult<StorageModeResponse>>> GetStorageModes(
|
||||||
[FromQuery] int page = 1,
|
[FromQuery] int page = 1,
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ public class PictureController(IPictureService pictureService, IStorageService s
|
|||||||
[HttpPost("upload_picture")]
|
[HttpPost("upload_picture")]
|
||||||
[Consumes("multipart/form-data")]
|
[Consumes("multipart/form-data")]
|
||||||
public async Task<ActionResult<BaseResult<PictureResponse>>> UploadPicture(
|
public async Task<ActionResult<BaseResult<PictureResponse>>> UploadPicture(
|
||||||
[FromForm] UploadPictureRequest request)
|
[FromForm] UploadPictureRequest request) // UploadPictureRequest 模型需要添加 StorageModeId 属性
|
||||||
{
|
{
|
||||||
if (request.File.Length == 0)
|
if (request.File.Length == 0)
|
||||||
return Error<PictureResponse>("没有上传文件");
|
return Error<PictureResponse>("没有上传文件");
|
||||||
@@ -87,9 +87,9 @@ public class PictureController(IPictureService pictureService, IStorageService s
|
|||||||
stream,
|
stream,
|
||||||
request.File.ContentType,
|
request.File.ContentType,
|
||||||
userId,
|
userId,
|
||||||
(PermissionType)request.Permission!,
|
(PermissionType)request.Permission!, // 确保 PermissionType 的转换是安全的
|
||||||
request.AlbumId,
|
request.AlbumId,
|
||||||
request.StorageModeId
|
request.StorageModeId // 传递 StorageModeId
|
||||||
);
|
);
|
||||||
|
|
||||||
var picture = result.Picture;
|
var picture = result.Picture;
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ export const ImageFormat = {
|
|||||||
export interface UploadPictureParams {
|
export interface UploadPictureParams {
|
||||||
permission?: number;
|
permission?: number;
|
||||||
albumId?: number;
|
albumId?: number;
|
||||||
|
storageModeId?: number; // 新增:存储模式ID
|
||||||
convertToFormat?: ImageFormat;
|
convertToFormat?: ImageFormat;
|
||||||
quality?: number;
|
quality?: number;
|
||||||
onProgress?: (percent: number) => void;
|
onProgress?: (percent: number) => void;
|
||||||
@@ -208,6 +209,7 @@ export async function uploadPicture(
|
|||||||
data: {
|
data: {
|
||||||
permission?: number;
|
permission?: number;
|
||||||
albumId?: number;
|
albumId?: number;
|
||||||
|
storageModeId?: number; // 新增
|
||||||
onProgress?: (percent: number) => void
|
onProgress?: (percent: number) => void
|
||||||
} = {}
|
} = {}
|
||||||
): Promise<BaseResult<PictureResponse>> {
|
): Promise<BaseResult<PictureResponse>> {
|
||||||
@@ -222,6 +224,10 @@ export async function uploadPicture(
|
|||||||
formData.append('albumId', data.albumId.toString());
|
formData.append('albumId', data.albumId.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data.storageModeId !== undefined) { // 新增:添加 storageModeId 到 FormData
|
||||||
|
formData.append('storageModeId', data.storageModeId.toString());
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const token = localStorage.getItem('token');
|
const token = localStorage.getItem('token');
|
||||||
const headers: Record<string, string> = {};
|
const headers: Record<string, string> = {};
|
||||||
|
|||||||
@@ -139,6 +139,14 @@ export const getStorageTypes = async (): Promise<BaseResult<StorageTypeResponse[
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 获取可用的存储模式 (通常是启用的模式,用于选择)
|
||||||
|
export const getAvailableStorageModes = async (): Promise<BaseResult<StorageModeResponse[]>> => {
|
||||||
|
return fetchApi<StorageModeResponse[]>(
|
||||||
|
'/management/storage/get_available_modes',
|
||||||
|
{ method: 'GET' }
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
// 获取默认存储模式ID
|
// 获取默认存储模式ID
|
||||||
export const getDefaultStorageModeId = async (): Promise<BaseResult<number | null>> => {
|
export const getDefaultStorageModeId = async (): Promise<BaseResult<number | null>> => {
|
||||||
return fetchApi<number | null>(
|
return fetchApi<number | null>(
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { InboxOutlined } from '@ant-design/icons';
|
|||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
import type { UploadFile, AlbumResponse } from '../../api';
|
import type { UploadFile, AlbumResponse } from '../../api';
|
||||||
import { uploadPicture, getAlbums } from '../../api';
|
import { uploadPicture, getAlbums } from '../../api';
|
||||||
|
import { getAvailableStorageModes, type StorageModeResponse } from '../../api/storageManagementApi'; // 新增导入
|
||||||
|
|
||||||
const { Dragger } = Upload;
|
const { Dragger } = Upload;
|
||||||
const { Option } = Select;
|
const { Option } = Select;
|
||||||
@@ -19,11 +20,13 @@ const ImageUploadDialog: React.FC<UploadDialogProps> = ({ visible, onClose, onUp
|
|||||||
const [uploading, setUploading] = useState(false);
|
const [uploading, setUploading] = useState(false);
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const [albums, setAlbums] = useState<AlbumResponse[]>([]);
|
const [albums, setAlbums] = useState<AlbumResponse[]>([]);
|
||||||
|
const [availableStorageModes, setAvailableStorageModes] = useState<StorageModeResponse[]>([]); // 新增状态
|
||||||
const [concurrentUploads, setConcurrentUploads] = useState<number>(3);
|
const [concurrentUploads, setConcurrentUploads] = useState<number>(3);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
fetchAlbums();
|
fetchAlbums();
|
||||||
|
fetchStorageModes(); // 新增调用
|
||||||
}
|
}
|
||||||
}, [visible]);
|
}, [visible]);
|
||||||
|
|
||||||
@@ -38,6 +41,26 @@ const ImageUploadDialog: React.FC<UploadDialogProps> = ({ visible, onClose, onUp
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 新增:获取可用存储模式
|
||||||
|
const fetchStorageModes = async () => {
|
||||||
|
try {
|
||||||
|
const result = await getAvailableStorageModes();
|
||||||
|
if (result.success && result.data) {
|
||||||
|
setAvailableStorageModes(result.data);
|
||||||
|
// 尝试设置默认存储模式ID(如果后端有此逻辑,或者选择第一个作为默认)
|
||||||
|
if (result.data.length > 0) {
|
||||||
|
// 这里可以根据业务逻辑设置一个默认选中的 storageModeId
|
||||||
|
// form.setFieldsValue({ storageModeId: result.data[0].id });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
message.error('获取存储模式列表失败: ' + result.message);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取存储模式列表失败:', error);
|
||||||
|
message.error('获取存储模式列表失败');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleBeforeUpload = (file: File) => {
|
const handleBeforeUpload = (file: File) => {
|
||||||
// 检查是否为图片文件
|
// 检查是否为图片文件
|
||||||
const isImage = file.type.startsWith('image/');
|
const isImage = file.type.startsWith('image/');
|
||||||
@@ -78,6 +101,7 @@ const ImageUploadDialog: React.FC<UploadDialogProps> = ({ visible, onClose, onUp
|
|||||||
const params: {
|
const params: {
|
||||||
permission?: number;
|
permission?: number;
|
||||||
albumId?: number;
|
albumId?: number;
|
||||||
|
storageModeId?: number; // 新增
|
||||||
} = {};
|
} = {};
|
||||||
|
|
||||||
if (values.permission !== undefined) {
|
if (values.permission !== undefined) {
|
||||||
@@ -86,6 +110,9 @@ const ImageUploadDialog: React.FC<UploadDialogProps> = ({ visible, onClose, onUp
|
|||||||
if (values.albumId) {
|
if (values.albumId) {
|
||||||
params.albumId = values.albumId;
|
params.albumId = values.albumId;
|
||||||
}
|
}
|
||||||
|
if (values.storageModeId) { // 新增
|
||||||
|
params.storageModeId = values.storageModeId;
|
||||||
|
}
|
||||||
|
|
||||||
let successCount = 0;
|
let successCount = 0;
|
||||||
let failCount = 0;
|
let failCount = 0;
|
||||||
@@ -103,7 +130,7 @@ const ImageUploadDialog: React.FC<UploadDialogProps> = ({ visible, onClose, onUp
|
|||||||
try {
|
try {
|
||||||
// 上传文件
|
// 上传文件
|
||||||
const result = await uploadPicture(item.file, {
|
const result = await uploadPicture(item.file, {
|
||||||
...params,
|
...params, // 传递包含 storageModeId 的 params
|
||||||
onProgress: (percent) => {
|
onProgress: (percent) => {
|
||||||
setUploadQueue((prev) =>
|
setUploadQueue((prev) =>
|
||||||
prev.map(file => file.id === item.id ? { ...file, percent } : file)
|
prev.map(file => file.id === item.id ? { ...file, percent } : file)
|
||||||
@@ -319,6 +346,7 @@ const ImageUploadDialog: React.FC<UploadDialogProps> = ({ visible, onClose, onUp
|
|||||||
initialValues={{
|
initialValues={{
|
||||||
permission: 2,
|
permission: 2,
|
||||||
concurrentUploads: 3
|
concurrentUploads: 3
|
||||||
|
// storageModeId: undefined // 可以设置一个初始值或留空
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
@@ -332,6 +360,19 @@ const ImageUploadDialog: React.FC<UploadDialogProps> = ({ visible, onClose, onUp
|
|||||||
</Select>
|
</Select>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
|
{/* 新增:存储模式选择 */}
|
||||||
|
<Form.Item
|
||||||
|
name="storageModeId"
|
||||||
|
label="选择存储模式"
|
||||||
|
rules={[{ required: true, message: '请选择存储模式!' }]}
|
||||||
|
>
|
||||||
|
<Select placeholder="选择图片存储模式">
|
||||||
|
{availableStorageModes.map(mode => (
|
||||||
|
<Option key={mode.id} value={mode.id}>{mode.name} ({mode.storageTypeName})</Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="permission"
|
name="permission"
|
||||||
label="图片权限"
|
label="图片权限"
|
||||||
|
|||||||
Reference in New Issue
Block a user