|
@@ -0,0 +1,503 @@
|
|
|
|
|
+# 项目组件文档
|
|
|
|
|
+
|
|
|
|
|
+## 目录
|
|
|
|
|
+1. [管理后台组件](#管理后台组件)
|
|
|
|
|
+2. [移动端组件](#移动端组件)
|
|
|
|
|
+3. [通用工具方法](#通用工具方法)
|
|
|
|
|
+4. [使用示例](#使用示例)
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 管理后台组件
|
|
|
|
|
+
|
|
|
|
|
+### 1. MinioUploader - MinIO文件上传组件
|
|
|
|
|
+
|
|
|
|
|
+**位置**: `src/client/admin/components/MinioUploader.tsx`
|
|
|
|
|
+
|
|
|
|
|
+**作用**: 提供完整的文件上传功能,支持拖拽上传、进度显示、多文件上传等
|
|
|
|
|
+
|
|
|
|
|
+**属性**:
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface MinioUploaderProps {
|
|
|
|
|
+ uploadPath: string; // 上传路径
|
|
|
|
|
+ accept?: string; // 允许的文件类型
|
|
|
|
|
+ maxSize?: number; // 最大文件大小(MB)
|
|
|
|
|
+ multiple?: boolean; // 是否支持多文件
|
|
|
|
|
+ onUploadSuccess?: (fileKey: string, fileUrl: string, file: File) => void;
|
|
|
|
|
+ onUploadError?: (error: Error, file: File) => void;
|
|
|
|
|
+ buttonText?: string; // 自定义按钮文本
|
|
|
|
|
+ tipText?: string; // 自定义提示文本
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**使用方法**:
|
|
|
|
|
+```tsx
|
|
|
|
|
+<MinioUploader
|
|
|
|
|
+ uploadPath="/documents/"
|
|
|
|
|
+ accept=".pdf,.doc,.docx"
|
|
|
|
|
+ maxSize={10}
|
|
|
|
|
+ multiple={true}
|
|
|
|
|
+ onUploadSuccess={(fileKey, fileUrl, file) => {
|
|
|
|
|
+ console.log('上传成功:', fileUrl);
|
|
|
|
|
+ }}
|
|
|
|
|
+ buttonText="上传文档"
|
|
|
|
|
+ tipText="支持PDF、Word格式,最大10MB"
|
|
|
|
|
+/>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 2. AttachmentUploader - 附件上传组件
|
|
|
|
|
+
|
|
|
|
|
+**位置**: `src/client/admin/components/AttachmentUploader.tsx`
|
|
|
|
|
+
|
|
|
|
|
+**作用**: 专门用于上传附件文件,支持多种文档格式
|
|
|
|
|
+
|
|
|
|
|
+**支持格式**: PDF、DOC、DOCX、XLS、XLSX、PPT、PPTX、TXT、ZIP、RAR
|
|
|
|
|
+
|
|
|
|
|
+**使用方法**:
|
|
|
|
|
+```tsx
|
|
|
|
|
+<AttachmentUploader
|
|
|
|
|
+ value={attachmentUrl}
|
|
|
|
|
+ fileName={attachmentName}
|
|
|
|
|
+ onChange={(url, name) => {
|
|
|
|
|
+ setAttachmentUrl(url);
|
|
|
|
|
+ setAttachmentName(name);
|
|
|
|
|
+ }}
|
|
|
|
|
+/>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 3. CoverImageUploader - 封面图片上传组件
|
|
|
|
|
+
|
|
|
|
|
+**位置**: `src/client/admin/components/CoverImageUploader.tsx`
|
|
|
|
|
+
|
|
|
|
|
+**作用**: 专门用于上传封面图片,支持图片预览
|
|
|
|
|
+
|
|
|
|
|
+**支持格式**: JPG、PNG、GIF,最大5MB
|
|
|
|
|
+
|
|
|
|
|
+**使用方法**:
|
|
|
|
|
+```tsx
|
|
|
|
|
+<CoverImageUploader
|
|
|
|
|
+ value={coverUrl}
|
|
|
|
|
+ onChange={(url) => setCoverUrl(url)}
|
|
|
|
|
+/>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 4. CompanySelect - 公司选择器
|
|
|
|
|
+
|
|
|
|
|
+**位置**: `src/client/admin/components/CompanySelect.tsx`
|
|
|
|
|
+
|
|
|
|
|
+**作用**: 从已认证公司列表中选择公司,支持搜索功能
|
|
|
|
|
+
|
|
|
|
|
+**属性**:
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface CompanySelectProps {
|
|
|
|
|
+ value?: number;
|
|
|
|
|
+ onChange?: (value: number) => void;
|
|
|
|
|
+ placeholder?: string;
|
|
|
|
|
+ allowClear?: boolean;
|
|
|
|
|
+ showSearch?: boolean;
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**使用方法**:
|
|
|
|
|
+```tsx
|
|
|
|
|
+<CompanySelect
|
|
|
|
|
+ value={selectedCompanyId}
|
|
|
|
|
+ onChange={setSelectedCompanyId}
|
|
|
|
|
+ placeholder="选择合作公司"
|
|
|
|
|
+/>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 5. KnowledgeCategoryTreeSelect - 知识分类树形选择器
|
|
|
|
|
+
|
|
|
|
|
+**位置**: `src/client/admin/components/KnowledgeCategoryTreeSelect.tsx`
|
|
|
|
|
+
|
|
|
|
|
+**作用**: 以树形结构选择知识分类,支持多级分类
|
|
|
|
|
+
|
|
|
|
|
+**属性**:
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface KnowledgeCategoryTreeSelectProps {
|
|
|
|
|
+ value?: number | null;
|
|
|
|
|
+ onChange?: (value: number | null) => void;
|
|
|
|
|
+ placeholder?: string;
|
|
|
|
|
+ allowClear?: boolean;
|
|
|
|
|
+ multiple?: boolean;
|
|
|
|
|
+ showRoot?: boolean;
|
|
|
|
|
+ rootLabel?: string;
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**使用方法**:
|
|
|
|
|
+```tsx
|
|
|
|
|
+<KnowledgeCategoryTreeSelect
|
|
|
|
|
+ value={categoryId}
|
|
|
|
|
+ onChange={setCategoryId}
|
|
|
|
|
+ placeholder="选择知识分类"
|
|
|
|
|
+ showRoot={true}
|
|
|
|
|
+ rootLabel="全部分类"
|
|
|
|
|
+/>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 6. StatCard - 统计卡片组件
|
|
|
|
|
+
|
|
|
|
|
+**位置**: `src/client/admin/components/StatCard.tsx`
|
|
|
|
|
+
|
|
|
|
|
+**作用**: 显示统计数据的卡片组件,带趋势指示
|
|
|
|
|
+
|
|
|
|
|
+**属性**:
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface StatCardProps {
|
|
|
|
|
+ title: string;
|
|
|
|
|
+ value: number;
|
|
|
|
|
+ prefix?: React.ReactNode;
|
|
|
|
|
+ suffix?: string;
|
|
|
|
|
+ trend?: 'up' | 'down';
|
|
|
|
|
+ trendValue?: string;
|
|
|
|
|
+ color: string; // 'blue' | 'green' | 'orange' | 'purple' | 'red' | 'pink'
|
|
|
|
|
+ icon: React.ReactNode;
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**使用方法**:
|
|
|
|
|
+```tsx
|
|
|
|
|
+<StatCard
|
|
|
|
|
+ title="总用户数"
|
|
|
|
|
+ value={12580}
|
|
|
|
|
+ trend="up"
|
|
|
|
|
+ trendValue="+12.5%"
|
|
|
|
|
+ color="blue"
|
|
|
|
|
+ icon={<UserOutlined />}
|
|
|
|
|
+ suffix="本月新增"
|
|
|
|
|
+/>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 移动端组件
|
|
|
|
|
+
|
|
|
|
|
+### 1. AvatarUpload - 头像上传组件 (移动端)
|
|
|
|
|
+
|
|
|
|
|
+**位置**: `src/client/mobile/components/AvatarUpload.tsx`
|
|
|
|
|
+
|
|
|
|
|
+**作用**: 移动端头像上传,支持图片裁剪和压缩
|
|
|
|
|
+
|
|
|
|
|
+**属性**:
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface AvatarUploadProps {
|
|
|
|
|
+ currentAvatar?: string | null;
|
|
|
|
|
+ onUploadSuccess?: (avatarUrl: string) => void;
|
|
|
|
|
+ size?: number; // 头像大小,默认96px
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**特色功能**:
|
|
|
|
|
+- 图片压缩
|
|
|
|
|
+- 圆形裁剪
|
|
|
|
|
+- 水墨风格UI
|
|
|
|
|
+- 实时预览
|
|
|
|
|
+
|
|
|
|
|
+**使用方法**:
|
|
|
|
|
+```tsx
|
|
|
|
|
+<AvatarUpload
|
|
|
|
|
+ currentAvatar={user.avatar}
|
|
|
|
|
+ onUploadSuccess={(url) => updateUserAvatar(url)}
|
|
|
|
|
+ size={120}
|
|
|
|
|
+/>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 2. AvatarCropper - 头像裁剪组件
|
|
|
|
|
+
|
|
|
|
|
+**位置**: `src/client/mobile/components/AvatarCropper.tsx`
|
|
|
|
|
+
|
|
|
|
|
+**作用**: 提供图片裁剪功能,支持拖拽和缩放
|
|
|
|
|
+
|
|
|
|
|
+**属性**:
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface AvatarCropperProps {
|
|
|
|
|
+ imageUrl: string;
|
|
|
|
|
+ onCrop: (croppedBlob: Blob) => void;
|
|
|
|
|
+ onCancel: () => void;
|
|
|
|
|
+ size?: number; // 裁剪区域大小
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**使用方法**:
|
|
|
|
|
+```tsx
|
|
|
|
|
+<AvatarCropper
|
|
|
|
|
+ imageUrl={previewImage}
|
|
|
|
|
+ onCrop={(blob) => handleCropComplete(blob)}
|
|
|
|
|
+ onCancel={() => setShowCropper(false)}
|
|
|
|
|
+ size={300}
|
|
|
|
|
+/>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 3. SmartAssistant - 智能助手组件
|
|
|
|
|
+
|
|
|
|
|
+**位置**: `src/client/mobile/components/SmartAssistant/`
|
|
|
|
|
+
|
|
|
|
|
+**作用**: 智能对话助手,支持多种AI Agent
|
|
|
|
|
+
|
|
|
|
|
+**主要组件**:
|
|
|
|
|
+- `SmartAssistant`: 主组件
|
|
|
|
|
+- `ChatWindow`: 聊天窗口
|
|
|
|
|
+- `MessageBubble`: 消息气泡
|
|
|
|
|
+- `AgentSelector`: Agent选择器
|
|
|
|
|
+- `FloatingButton`: 悬浮按钮
|
|
|
|
|
+
|
|
|
|
|
+**使用方法**:
|
|
|
|
|
+```tsx
|
|
|
|
|
+import { SmartAssistant } from '@/client/mobile/components/SmartAssistant';
|
|
|
|
|
+
|
|
|
|
|
+<SmartAssistant />
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 通用工具方法
|
|
|
|
|
+
|
|
|
|
|
+### 1. 文件上传工具 - minio.ts
|
|
|
|
|
+
|
|
|
|
|
+**位置**: `src/client/utils/minio.ts`
|
|
|
|
|
+
|
|
|
|
|
+**主要功能**:
|
|
|
|
|
+- MinIO文件上传
|
|
|
|
|
+- 分段上传大文件
|
|
|
|
|
+- 进度回调
|
|
|
|
|
+- 上传策略获取
|
|
|
|
|
+
|
|
|
|
|
+**使用方法**:
|
|
|
|
|
+
|
|
|
|
|
+#### 基础上传
|
|
|
|
|
+```typescript
|
|
|
|
|
+import { uploadFile } from '@/client/utils/minio';
|
|
|
|
|
+
|
|
|
|
|
+const url = await uploadFile(file, 'avatars');
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+#### 带进度上传
|
|
|
|
|
+```typescript
|
|
|
|
|
+import { uploadMinIOWithPolicy } from '@/client/utils/minio';
|
|
|
|
|
+
|
|
|
|
|
+const result = await uploadMinIOWithPolicy(
|
|
|
|
|
+ 'avatars',
|
|
|
|
|
+ file,
|
|
|
|
|
+ `user-${userId}.jpg`,
|
|
|
|
|
+ {
|
|
|
|
|
+ onProgress: (event) => {
|
|
|
|
|
+ console.log(`进度: ${event.progress}%`);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+);
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 2. 图片处理工具 - upload.ts
|
|
|
|
|
+
|
|
|
|
|
+**位置**: `src/client/utils/upload.ts`
|
|
|
|
|
+
|
|
|
|
|
+**主要功能**:
|
|
|
|
|
+- 图片压缩
|
|
|
|
|
+- Base64转换
|
|
|
|
|
+- 文件类型检查
|
|
|
|
|
+- 文件大小验证
|
|
|
|
|
+
|
|
|
|
|
+**使用方法**:
|
|
|
|
|
+
|
|
|
|
|
+#### 图片压缩
|
|
|
|
|
+```typescript
|
|
|
|
|
+import { compressImage } from '@/client/utils/upload';
|
|
|
|
|
+
|
|
|
|
|
+const compressedFile = await compressImage(file, 800, 800, 0.8);
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+#### 文件验证
|
|
|
|
|
+```typescript
|
|
|
|
|
+import { isImageFile, checkFileSize } from '@/client/utils/upload';
|
|
|
|
|
+
|
|
|
|
|
+if (!isImageFile(file)) {
|
|
|
|
|
+ alert('请选择图片文件');
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+if (!checkFileSize(file, 2)) {
|
|
|
|
|
+ alert('文件大小不能超过2MB');
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 3. API客户端 - api.ts
|
|
|
|
|
+
|
|
|
|
|
+**位置**: `src/client/api.ts`
|
|
|
|
|
+
|
|
|
|
|
+**主要功能**:
|
|
|
|
|
+- 统一的API调用接口
|
|
|
|
|
+- 类型安全的API调用
|
|
|
|
|
+- 自动处理认证
|
|
|
|
|
+
|
|
|
|
|
+**使用方法**:
|
|
|
|
|
+```typescript
|
|
|
|
|
+import { userClient } from '@/client/api';
|
|
|
|
|
+
|
|
|
|
|
+// 获取用户信息
|
|
|
|
|
+const response = await userClient[userId].$get();
|
|
|
|
|
+const userData = await response.json();
|
|
|
|
|
+
|
|
|
|
|
+// 更新用户信息
|
|
|
|
|
+await userClient[userId].$put({
|
|
|
|
|
+ json: { username: 'newName' }
|
|
|
|
|
+});
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 使用示例
|
|
|
|
|
+
|
|
|
|
|
+### 1. 完整的上传流程示例
|
|
|
|
|
+
|
|
|
|
|
+```tsx
|
|
|
|
|
+import React, { useState } from 'react';
|
|
|
|
|
+import { MinioUploader } from '@/client/admin/components/MinioUploader';
|
|
|
|
|
+import { message } from 'antd';
|
|
|
|
|
+
|
|
|
|
|
+const DocumentUploadExample: React.FC = () => {
|
|
|
|
|
+ const [fileUrl, setFileUrl] = useState<string>('');
|
|
|
|
|
+
|
|
|
|
|
+ const handleUploadSuccess = (fileKey: string, fileUrl: string, file: File) => {
|
|
|
|
|
+ setFileUrl(fileUrl);
|
|
|
|
|
+ message.success(`文件 ${file.name} 上传成功`);
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const handleUploadError = (error: Error, file: File) => {
|
|
|
|
|
+ message.error(`文件 ${file.name} 上传失败: ${error.message}`);
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ return (
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <MinioUploader
|
|
|
|
|
+ uploadPath="/documents/2024/"
|
|
|
|
|
+ accept=".pdf,.doc,.docx"
|
|
|
|
|
+ maxSize={10}
|
|
|
|
|
+ multiple={false}
|
|
|
|
|
+ onUploadSuccess={handleUploadSuccess}
|
|
|
|
|
+ onUploadError={handleUploadError}
|
|
|
|
|
+ buttonText="上传文档"
|
|
|
|
|
+ tipText="支持PDF、Word格式,最大10MB"
|
|
|
|
|
+ />
|
|
|
|
|
+
|
|
|
|
|
+ {fileUrl && (
|
|
|
|
|
+ <div className="mt-4">
|
|
|
|
|
+ <a href={fileUrl} target="_blank" rel="noopener noreferrer">
|
|
|
|
|
+ 查看已上传文件
|
|
|
|
|
+ </a>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ )}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ );
|
|
|
|
|
+};
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 2. 移动端头像上传示例
|
|
|
|
|
+
|
|
|
|
|
+```tsx
|
|
|
|
|
+import React, { useState } from 'react';
|
|
|
|
|
+import { AvatarUpload } from '@/client/mobile/components/AvatarUpload';
|
|
|
|
|
+import { useAuth } from '@/client/mobile/hooks/AuthProvider';
|
|
|
|
|
+
|
|
|
|
|
+const ProfileAvatar: React.FC = () => {
|
|
|
|
|
+ const { user, updateUser } = useAuth();
|
|
|
|
|
+ const [avatar, setAvatar] = useState(user?.avatar);
|
|
|
|
|
+
|
|
|
|
|
+ const handleAvatarUpload = (avatarUrl: string) => {
|
|
|
|
|
+ setAvatar(avatarUrl);
|
|
|
|
|
+ updateUser({ avatar: avatarUrl });
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ return (
|
|
|
|
|
+ <div className="flex flex-col items-center">
|
|
|
|
|
+ <AvatarUpload
|
|
|
|
|
+ currentAvatar={avatar}
|
|
|
|
|
+ onUploadSuccess={handleAvatarUpload}
|
|
|
|
|
+ size={120}
|
|
|
|
|
+ />
|
|
|
|
|
+ <p className="mt-2 text-gray-600">点击头像更换</p>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ );
|
|
|
|
|
+};
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 3. 公司选择器使用示例
|
|
|
|
|
+
|
|
|
|
|
+```tsx
|
|
|
|
|
+import React, { useState } from 'react';
|
|
|
|
|
+import { CompanySelect } from '@/client/admin/components/CompanySelect';
|
|
|
|
|
+
|
|
|
|
|
+const JobForm: React.FC = () => {
|
|
|
|
|
+ const [companyId, setCompanyId] = useState<number>();
|
|
|
|
|
+
|
|
|
|
|
+ const handleCompanyChange = (value: number) => {
|
|
|
|
|
+ setCompanyId(value);
|
|
|
|
|
+ // 触发其他逻辑,如加载公司详情
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ return (
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <label>选择公司</label>
|
|
|
|
|
+ <CompanySelect
|
|
|
|
|
+ value={companyId}
|
|
|
|
|
+ onChange={handleCompanyChange}
|
|
|
|
|
+ placeholder="请选择发布职位的公司"
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ );
|
|
|
|
|
+};
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 4. 批量文件上传示例
|
|
|
|
|
+
|
|
|
|
|
+```tsx
|
|
|
|
|
+import React, { useState } from 'react';
|
|
|
|
|
+import { MinioUploader } from '@/client/admin/components/MinioUploader';
|
|
|
|
|
+import type { UploadFile } from 'antd';
|
|
|
|
|
+
|
|
|
|
|
+const BatchUploadExample: React.FC = () => {
|
|
|
|
|
+ const [uploadedFiles, setUploadedFiles] = useState<string[]>([]);
|
|
|
|
|
+
|
|
|
|
|
+ const handleUploadSuccess = (fileKey: string, fileUrl: string, file: File) => {
|
|
|
|
|
+ setUploadedFiles(prev => [...prev, fileUrl]);
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ return (
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <h3>批量上传图片</h3>
|
|
|
|
|
+ <MinioUploader
|
|
|
|
|
+ uploadPath="/gallery/2024/"
|
|
|
|
|
+ accept="image/*"
|
|
|
|
|
+ maxSize={5}
|
|
|
|
|
+ multiple={true}
|
|
|
|
|
+ onUploadSuccess={handleUploadSuccess}
|
|
|
|
|
+ buttonText="选择图片"
|
|
|
|
|
+ tipText="支持JPG、PNG、GIF格式,每张最大5MB"
|
|
|
|
|
+ />
|
|
|
|
|
+
|
|
|
|
|
+ <div className="mt-4">
|
|
|
|
|
+ <h4>已上传文件:</h4>
|
|
|
|
|
+ {uploadedFiles.map((url, index) => (
|
|
|
|
|
+ <img key={index} src={url} alt={`uploaded-${index}`} className="w-32 h-32" />
|
|
|
|
|
+ ))}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ );
|
|
|
|
|
+};
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## 注意事项
|
|
|
|
|
+
|
|
|
|
|
+1. **文件大小限制**: 不同类型的上传组件有不同的文件大小限制
|
|
|
|
|
+2. **文件格式验证**: 上传前务必验证文件格式和大小
|
|
|
|
|
+3. **进度显示**: 大文件上传建议使用进度条显示
|
|
|
|
|
+4. **错误处理**: 所有上传操作都应该有完善的错误处理
|
|
|
|
|
+5. **安全性**: 敏感文件上传需要额外的权限验证
|
|
|
|
|
+
|
|
|
|
|
+## 最佳实践
|
|
|
|
|
+
|
|
|
|
|
+1. **统一文件命名**: 使用时间戳或UUID避免文件名冲突
|
|
|
|
|
+2. **分目录存储**: 按类型、日期或用户分目录存储
|
|
|
|
|
+3. **压缩优化**: 大图片上传前先压缩
|
|
|
|
|
+4. **缓存清理**: 定期清理无用文件
|
|
|
|
|
+5. **权限控制**: 根据用户角色限制上传权限
|