添加管理端和移动端的多个新功能模块,包括文件上传、在线地图、用户认证、系统设置等,优化代码结构,提升可维护性和用户体验。

This commit is contained in:
zyh
2025-04-10 02:25:25 +00:00
parent 01dea6efa1
commit b1a6b608c6
31 changed files with 1366 additions and 46 deletions

View File

@@ -0,0 +1,167 @@
import React, { useState } from 'react';
import {
Layout, Menu, Button, Table, Space,
Form, Input, Select, message, Modal,
Card, Spin, Row, Col, Breadcrumb, Avatar,
Dropdown, ConfigProvider, theme, Typography,
Switch, Badge, Image, Upload, Divider, Descriptions,
Popconfirm, Tag, Statistic, DatePicker, Radio, Progress, Tabs, List, Alert, Collapse, Empty, Drawer
} from 'antd';
import {
UploadOutlined,
} from '@ant-design/icons';
import { uploadMinIOWithPolicy , uploadOSSWithPolicy} from '@d8d-appcontainer/api';
import type { MinioUploadPolicy, OSSUploadPolicy } from '@d8d-appcontainer/types';
import 'dayjs/locale/zh-cn';
import { OssType } from '../share/types.ts';
import { FileAPI } from './api.ts';
// MinIO文件上传组件
export const Uploader = ({
onSuccess,
onError,
onProgress,
maxSize = 10 * 1024 * 1024,
prefix = 'uploads/',
allowedTypes = ['image/jpeg', 'image/png', 'application/pdf', 'text/plain']
}: {
onSuccess?: (fileUrl: string, fileInfo: any) => void;
onError?: (error: Error) => void;
onProgress?: (percent: number) => void;
maxSize?: number;
prefix?: string;
allowedTypes?: string[];
}) => {
const [uploading, setUploading] = useState(false);
const [progress, setProgress] = useState(0);
// 处理文件上传
const handleUpload = async (options: any) => {
const { file, onSuccess: uploadSuccess, onError: uploadError, onProgress: uploadProgress } = options;
setUploading(true);
setProgress(0);
// 文件大小检查
if (file.size > maxSize) {
message.error(`文件大小不能超过${maxSize / 1024 / 1024}MB`);
uploadError(new Error('文件过大'));
setUploading(false);
return;
}
// 文件类型检查
if (allowedTypes && allowedTypes.length > 0 && !allowedTypes.includes(file.type)) {
message.error(`不支持的文件类型: ${file.type}`);
uploadError(new Error('不支持的文件类型'));
setUploading(false);
return;
}
try {
// 1. 获取上传策略
const policyResponse = await FileAPI.getUploadPolicy(file.name, prefix, maxSize);
const policy = policyResponse.data;
if (!policy) {
throw new Error('获取上传策略失败');
}
// 生成随机文件名但保留原始扩展名
const fileExt = file.name.split('.').pop() || '';
const randomName = `${Date.now()}_${Math.random().toString(36).substring(2, 10)}${fileExt ? `.${fileExt}` : ''}`;
// 2. 上传文件到MinIO
const callbacks = {
onProgress: (event: { progress: number }) => {
const percent = Math.round(event.progress);
setProgress(percent);
uploadProgress({ percent });
onProgress?.(percent);
},
onComplete: () => {
setUploading(false);
setProgress(100);
},
onError: (err: Error) => {
setUploading(false);
message.error(`上传失败: ${err.message}`);
uploadError(err);
onError?.(err);
}
};
// 执行上传
const fileUrl = window.CONFIG?.OSS_TYPE === OssType.MINIO ?
await uploadMinIOWithPolicy(
policy as MinioUploadPolicy,
file,
randomName,
callbacks
) : await uploadOSSWithPolicy(
policy as OSSUploadPolicy,
file,
randomName,
callbacks
);
// 从URL中提取相对路径
const relativePath = `${policy.prefix}${randomName}`;
// 3. 保存文件信息到文件库
const fileInfo = {
file_name: randomName,
original_filename: file.name,
file_path: relativePath,
file_type: file.type,
file_size: file.size,
tags: '',
description: '',
category_id: undefined
};
const saveResponse = await FileAPI.saveFileInfo(fileInfo);
// 操作成功
uploadSuccess(relativePath);
message.success('文件上传成功');
onSuccess?.(relativePath, saveResponse.data);
} catch (error: any) {
// 上传失败
setUploading(false);
message.error(`上传失败: ${error.message}`);
uploadError(error);
onError?.(error);
}
};
return (
<Upload.Dragger
name="file"
multiple={false}
customRequest={handleUpload}
showUploadList={true}
progress={{
strokeColor: {
'0%': '#108ee9',
'100%': '#87d068',
},
format: (percent) => `${Math.round(percent || 0)}%`,
}}
>
<p className="ant-upload-drag-icon">
<UploadOutlined />
</p>
<p className="ant-upload-text"></p>
<p className="ant-upload-hint">
{maxSize / 1024 / 1024}MB
</p>
{uploading && (
<div style={{ marginTop: 16 }}>
<Progress percent={progress} />
</div>
)}
</Upload.Dragger>
);
};