# 摄影作品集网站 - 管理后台开发文档 ## 1. 项目概述 ### 1.1 项目定位 基于现有摄影作品集网站的管理后台系统,提供完整的内容管理、用户管理和系统配置功能。 ### 1.2 技术栈 - **后端**: Golang + Gin + GORM + PostgreSQL + Redis - **前端**: React + TypeScript + Tailwind CSS + shadcn/ui - **文件存储**: MinIO/AWS S3 + 本地存储 - **图片处理**: libvips + 多格式转换 - **认证**: JWT + Session管理 - **部署**: Docker + Caddy ### 1.3 设计原则 - **用户友好**: 直观的界面设计,简化操作流程 - **高性能**: 异步图片处理,智能缓存策略 - **可扩展**: 模块化设计,支持功能扩展 - **安全可靠**: 多层权限控制,操作日志审计 ## 2. 管理后台功能模块详细设计 ### 2.1 仪表板模块 (Dashboard) #### 2.1.1 核心功能 - **数据统计**: 照片总数、分类数量、标签数量、存储使用情况 - **近期活动**: 最近上传、最近修改、访问统计 - **快捷操作**: 快速上传、批量处理、系统设置 - **系统状态**: 服务器状态、缓存状态、队列状态 #### 2.1.2 界面设计 ``` ┌─────────────────────────────────────────────────────────┐ │ 仪表板 Dashboard │ ├─────────────────────────────────────────────────────────┤ │ 📊 统计卡片 │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ 总照片 │ │ 总分类 │ │ 总标签 │ │ 存储用量│ │ │ │ 1,234 │ │ 12 │ │ 45 │ │ 2.5GB │ │ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │ │ │ 📈 上传趋势图表 │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ [折线图显示最近30天上传趋势] │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ │ 📋 近期活动 │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ • 上传了 "城市夜景" 系列 5 张照片 │ │ │ │ • 创建了新分类 "建筑摄影" │ │ │ │ • 更新了标签 "城市风光" │ │ │ └─────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────┘ ``` #### 2.1.3 数据接口 ```go // GET /api/admin/dashboard/stats type DashboardStats struct { TotalPhotos int `json:"total_photos"` TotalCategories int `json:"total_categories"` TotalTags int `json:"total_tags"` StorageUsed int64 `json:"storage_used"` StorageLimit int64 `json:"storage_limit"` RecentUploads int `json:"recent_uploads"` // 上传趋势 (最近30天) UploadTrend []struct { Date string `json:"date"` Count int `json:"count"` } `json:"upload_trend"` // 热门分类 PopularCategories []struct { Name string `json:"name"` Count int `json:"count"` } `json:"popular_categories"` // 系统状态 SystemStatus struct { DatabaseStatus string `json:"database_status"` RedisStatus string `json:"redis_status"` StorageStatus string `json:"storage_status"` QueueStatus string `json:"queue_status"` } `json:"system_status"` } ``` ### 2.2 照片管理模块 (Photo Management) #### 2.2.1 照片列表页面 ``` ┌─────────────────────────────────────────────────────────┐ │ 照片管理 Photo Management │ ├─────────────────────────────────────────────────────────┤ │ 🔍 [搜索框] 📂 [分类筛选] 🏷️ [标签筛选] 📅 [时间筛选] │ │ ➕ 上传照片 📤 批量操作 ⚙️ 设置 │ ├─────────────────────────────────────────────────────────┤ │ 📷 照片网格 (支持列表/网格视图切换) │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ [缩略图] │ │ [缩略图] │ │ [缩略图] │ │ [缩略图] │ │ │ │ 标题 │ │ 标题 │ │ 标题 │ │ 标题 │ │ │ │ 分类 │ │ 分类 │ │ 分类 │ │ 分类 │ │ │ │ 日期 │ │ 日期 │ │ 日期 │ │ 日期 │ │ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │ │ │ [更多照片...] │ │ │ │ ⬅️ 上一页 [1] [2] [3] ... [10] 下一页 ➡️ │ └─────────────────────────────────────────────────────────┘ ``` #### 2.2.2 照片详情/编辑页面 ``` ┌─────────────────────────────────────────────────────────┐ │ 照片详情 Photo Detail │ ├─────────────────────────────────────────────────────────┤ │ ⬅️ 返回列表 📝 编辑模式 🗑️ 删除 💾 保存 │ ├─────────────────────────────────────────────────────────┤ │ 📸 图片预览 │ 📋 基本信息 │ │ ┌─────────────────────────────┐ │ ┌─────────────────────┐ │ │ │ │ │ │ 标题: [输入框] │ │ │ │ [原图显示] │ │ │ 描述: [文本框] │ │ │ │ │ │ │ 分类: [下拉选择] │ │ │ │ │ │ │ 标签: [标签输入] │ │ │ │ │ │ │ 状态: [开关] │ │ │ │ │ │ │ 拍摄时间: [日期] │ │ │ │ │ │ │ 位置: [输入框] │ │ │ │ │ │ └─────────────────────┘ │ │ └─────────────────────────────┘ │ │ │ │ 📷 EXIF信息 │ │ 🎨 图片处理 │ ┌─────────────────────┐ │ │ ┌─────────────────────────────┐ │ │ 相机: Canon EOS R5 │ │ │ │ [裁剪] [旋转] [滤镜] [调色] │ │ │ 镜头: 24-70mm f/2.8 │ │ │ │ [缩放] [水印] [格式转换] │ │ │ 光圈: f/2.8 │ │ │ └─────────────────────────────┘ │ │ 快门: 1/60s │ │ │ │ │ ISO: 400 │ │ │ │ │ 焦距: 35mm │ │ │ │ └─────────────────────┘ │ └─────────────────────────────────────────────────────────┘ ``` #### 2.2.3 批量上传组件 ``` ┌─────────────────────────────────────────────────────────┐ │ 批量上传 Batch Upload │ ├─────────────────────────────────────────────────────────┤ │ 📁 拖拽上传区域 │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ 📸 拖拽图片到这里 或 点击选择文件 │ │ │ │ 支持 JPG, PNG, RAW, TIFF │ │ │ │ 最大文件大小: 50MB │ │ │ │ 最多同时上传: 20个文件 │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ │ 📋 上传队列 │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ 📸 IMG_001.jpg [██████████] 100% ✅ 完成 │ │ │ │ 📸 IMG_002.jpg [█████████▒] 90% ⏳ 上传中 │ │ │ │ 📸 IMG_003.jpg [██▒▒▒▒▒▒▒▒] 20% ⏳ 上传中 │ │ │ │ 📸 IMG_004.jpg [▒▒▒▒▒▒▒▒▒▒] 0% ⏸️ 等待 │ │ │ │ 📸 IMG_005.jpg [▒▒▒▒▒▒▒▒▒▒] 0% ⏸️ 等待 │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ │ ⚙️ 批量设置 │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ 默认分类: [下拉选择] │ │ │ │ 默认标签: [标签输入] │ │ │ │ 图片质量: [滑块] 85% │ │ │ │ 生成缩略图: [✅] 生成WebP格式: [✅] │ │ │ │ 提取EXIF: [✅] 自动分类: [✅] │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ │ 🎯 操作按钮 │ │ [⏸️ 暂停全部] [▶️ 继续全部] [🗑️ 清空队列] [⚙️ 高级设置] │ └─────────────────────────────────────────────────────────┘ ``` ### 2.3 分类管理模块 (Category Management) #### 2.3.1 分类树形结构 ``` ┌─────────────────────────────────────────────────────────┐ │ 分类管理 Category Management │ ├─────────────────────────────────────────────────────────┤ │ ➕ 新建分类 📊 分类统计 🔄 重新排序 ⚙️ 批量操作 │ ├─────────────────────────────────────────────────────────┤ │ 📂 分类树 (拖拽排序) │ 📋 分类详情 │ │ ┌─────────────────────────────────┐ │ ┌─────────────────┐ │ │ │ 📁 风景摄影 (125) │ │ │ 分类名: 风景摄影 │ │ │ │ ├─ 🏔️ 山川 (45) │ │ │ 父分类: 无 │ │ │ │ ├─ 🌊 海岸 (32) │ │ │ 描述: [文本框] │ │ │ │ ├─ 🌲 森林 (28) │ │ │ 颜色: [🔴] │ │ │ │ └─ 🌅 日出日落 (20) │ │ │ 封面: [选择图片] │ │ │ │ │ │ │ 状态: [✅] 启用 │ │ │ │ 📁 人像摄影 (89) │ │ │ 排序: 1 │ │ │ │ ├─ 👤 肖像 (34) │ │ │ 创建时间: 2024-01│ │ │ │ ├─ 👥 群像 (28) │ │ │ 照片数量: 125 │ │ │ │ ├─ 💃 艺术 (15) │ │ └─────────────────┘ │ │ │ └─ 📸 街头 (12) │ │ │ │ │ │ │ 🎨 操作 │ │ │ 📁 建筑摄影 (67) │ │ ┌─────────────────┐ │ │ │ ├─ 🏢 现代建筑 (23) │ │ │ [📝 编辑] │ │ │ │ ├─ 🏛️ 古建筑 (22) │ │ │ [👁️ 查看照片] │ │ │ │ ├─ 🌃 夜景 (12) │ │ │ [📊 统计] │ │ │ │ └─ 🏘️ 城市风光 (10) │ │ │ [🗑️ 删除] │ │ │ │ │ │ └─────────────────┘ │ │ └─────────────────────────────────┘ │ │ └─────────────────────────────────────────────────────────┘ ``` #### 2.3.2 分类编辑表单 ``` ┌─────────────────────────────────────────────────────────┐ │ 编辑分类 Edit Category │ ├─────────────────────────────────────────────────────────┤ │ 📝 基本信息 │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ 分类名称: [输入框] *必填 │ │ │ │ 父分类: [下拉选择] - 选择父分类 │ │ │ │ 分类描述: [文本框] - 详细描述 │ │ │ │ 分类颜色: [🔴🟡🟢🔵🟣] - 选择标识色 │ │ │ │ 排序权重: [数字输入] - 数字越小排序越前 │ │ │ │ 状态: [开关] 启用/禁用 │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ │ 🖼️ 封面设置 │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ 封面图片: [选择图片] [上传新图片] │ │ │ │ ┌─────────────────┐ │ │ │ │ │ [预览图片] │ │ │ │ │ │ │ │ │ │ │ └─────────────────┘ │ │ │ │ 图片尺寸: 建议 400x300 像素 │ │ │ │ 文件大小: 不超过 2MB │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ │ ⚙️ 高级设置 │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ SEO设置: │ │ │ │ URL别名: [输入框] - 用于URL路径 │ │ │ │ Meta描述: [文本框] - 搜索引擎描述 │ │ │ │ 关键词: [标签输入] - SEO关键词 │ │ │ │ │ │ │ │ 权限设置: │ │ │ │ 可见性: [公开/私有/仅登录用户] │ │ │ │ 管理权限: [仅管理员/编辑者/所有用户] │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ │ 💾 操作按钮 │ │ [💾 保存] [🔄 重置] [👁️ 预览] [❌ 取消] │ └─────────────────────────────────────────────────────────┘ ``` ### 2.4 标签管理模块 (Tag Management) #### 2.4.1 标签云展示 ``` ┌─────────────────────────────────────────────────────────┐ │ 标签管理 Tag Management │ ├─────────────────────────────────────────────────────────┤ │ ➕ 新建标签 📊 使用统计 🔄 批量操作 🔍 搜索标签 │ ├─────────────────────────────────────────────────────────┤ │ ☁️ 标签云 (按使用频率显示) │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ 自然 (120) 日落 (89) 肖像 (76) │ │ │ │ 城市 (145) 风景 (156) 黑白 (45) 建筑 (67) │ │ │ │ 艺术 (34) 旅行 (123) 海岸 (32) │ │ │ │ 山川 (45) 夜景 (28) 街头 (23) 现代 (56) │ │ │ │ 森林 (28) 抽象 (19) 光影 (67) │ │ │ │ 情感 (23) 色彩 (89) 构图 (45) 纹理 (34) │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ │ 📊 使用统计 │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ 🔥 热门标签 │ │ │ │ 1. 风景 (156张) ████████████████████████████████ │ │ │ │ 2. 城市 (145张) ████████████████████████████████ │ │ │ │ 3. 旅行 (123张) ████████████████████████████ │ │ │ │ 4. 自然 (120张) ████████████████████████████ │ │ │ │ 5. 日落 (89张) ████████████████████████ │ │ │ │ │ │ │ │ 📈 增长趋势 │ │ │ │ 本周新增: 12个标签 │ │ │ │ 本月活跃: 45个标签 │ │ │ │ 平均每张照片: 3.2个标签 │ │ │ └─────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────┘ ``` #### 2.4.2 标签列表管理 ``` ┌─────────────────────────────────────────────────────────┐ │ 标签列表 Tag List │ ├─────────────────────────────────────────────────────────┤ │ 🔍 [搜索标签] 📊 [按使用量排序] 🏷️ [按颜色筛选] [批量] │ ├─────────────────────────────────────────────────────────┤ │ 标签名 │ 颜色 │ 使用数量 │ 创建时间 │ 状态 │ 操作 │ │ ─────────┼──────┼─────────┼──────────┼─────┼────── │ │ 风景 │ 🟢 │ 156张 │ 2024-01-01│ 启用 │ 编辑 │ │ 城市 │ 🔵 │ 145张 │ 2024-01-01│ 启用 │ 编辑 │ │ 旅行 │ 🟡 │ 123张 │ 2024-01-02│ 启用 │ 编辑 │ │ 自然 │ 🟢 │ 120张 │ 2024-01-01│ 启用 │ 编辑 │ │ 日落 │ 🟠 │ 89张 │ 2024-01-03│ 启用 │ 编辑 │ │ 色彩 │ 🎨 │ 89张 │ 2024-01-05│ 启用 │ 编辑 │ │ 肖像 │ 🟣 │ 76张 │ 2024-01-02│ 启用 │ 编辑 │ │ 光影 │ ⚪ │ 67张 │ 2024-01-04│ 启用 │ 编辑 │ │ 建筑 │ 🔴 │ 67张 │ 2024-01-03│ 启用 │ 编辑 │ │ 现代 │ 🔘 │ 56张 │ 2024-01-06│ 启用 │ 编辑 │ ├─────────────────────────────────────────────────────────┤ │ ⬅️ 上一页 [1] [2] [3] ... [10] 下一页 ➡️ │ └─────────────────────────────────────────────────────────┘ ``` ### 2.5 用户管理模块 (User Management) #### 2.5.1 用户列表页面 ``` ┌─────────────────────────────────────────────────────────┐ │ 用户管理 User Management │ ├─────────────────────────────────────────────────────────┤ │ ➕ 新建用户 👥 角色管理 🔍 搜索用户 📊 用户统计 │ ├─────────────────────────────────────────────────────────┤ │ 用户名 │ 邮箱 │ 角色 │ 状态 │ 最后登录 │ 操作 │ │ ─────────┼──────────┼───────┼─────┼─────────┼────── │ │ admin │ admin@.. │ 管理员 │ 🟢活跃│ 2小时前 │ 编辑 │ │ editor │ editor@.. │ 编辑者 │ 🟢活跃│ 1天前 │ 编辑 │ │ user001 │ user001@..│ 用户 │ 🟡离线│ 3天前 │ 编辑 │ │ user002 │ user002@..│ 用户 │ 🔴禁用│ 1周前 │ 编辑 │ │ guest │ guest@.. │ 访客 │ 🟢活跃│ 5分钟前 │ 编辑 │ └─────────────────────────────────────────────────────────┘ ``` #### 2.5.2 用户编辑表单 ``` ┌─────────────────────────────────────────────────────────┐ │ 编辑用户 Edit User │ ├─────────────────────────────────────────────────────────┤ │ 👤 基本信息 │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ 用户名: [输入框] *必填 │ │ │ │ 邮箱: [输入框] *必填 │ │ │ │ 姓名: [输入框] 显示名称 │ │ │ │ 头像: [选择图片] [上传新头像] │ │ │ │ 角色: [下拉选择] 管理员/编辑者/用户/访客 │ │ │ │ 状态: [开关] 启用/禁用 │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ │ 🔐 权限设置 │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ 照片管理: [✅] 查看 [✅] 创建 [✅] 编辑 [❌] 删除 │ │ │ │ 分类管理: [✅] 查看 [✅] 创建 [❌] 编辑 [❌] 删除 │ │ │ │ 标签管理: [✅] 查看 [✅] 创建 [❌] 编辑 [❌] 删除 │ │ │ │ 用户管理: [❌] 查看 [❌] 创建 [❌] 编辑 [❌] 删除 │ │ │ │ 系统设置: [❌] 查看 [❌] 编辑 │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ │ 📊 用户统计 │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ 注册时间: 2024-01-15 │ │ │ │ 最后登录: 2024-01-20 14:30 │ │ │ │ 登录次数: 25次 │ │ │ │ 上传照片: 45张 │ │ │ │ 创建分类: 3个 │ │ │ │ 创建标签: 12个 │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ │ 💾 操作按钮 │ │ [💾 保存] [🔄 重置密码] [🚫 禁用用户] [❌ 取消] │ └─────────────────────────────────────────────────────────┘ ``` ### 2.6 系统设置模块 (System Settings) #### 2.6.1 网站配置 ``` ┌─────────────────────────────────────────────────────────┐ │ 系统设置 System Settings │ ├─────────────────────────────────────────────────────────┤ │ 🌐 网站配置 📁 文件设置 🎨 主题设置 💾 缓存设置 │ ├─────────────────────────────────────────────────────────┤ │ 🌐 网站基本信息 │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ 网站名称: [输入框] 摄影作品集 │ │ │ │ 网站描述: [文本框] 专业摄影作品展示平台 │ │ │ │ 网站关键词: [标签输入] 摄影,作品集,艺术 │ │ │ │ 网站Logo: [选择图片] [上传新Logo] │ │ │ │ 网站图标: [选择图片] [上传Favicon] │ │ │ │ 联系邮箱: [输入框] admin@photography.com │ │ │ │ 版权信息: [输入框] © 2024 Photography Portfolio │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ │ 📁 文件上传设置 │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ 允许格式: [多选] JPG PNG GIF WEBP RAW TIFF │ │ │ │ 最大大小: [数字输入] 50 MB │ │ │ │ 图片质量: [滑块] 85% │ │ │ │ 缩略图尺寸: [输入框] 300x300 │ │ │ │ 水印设置: [开关] 启用 [文本/图片] [位置选择] │ │ │ │ 自动压缩: [开关] 启用 │ │ │ │ 存储方式: [单选] 本地存储/MinIO/AWS S3 │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ │ 🎨 主题设置 │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ 默认主题: [下拉选择] 浅色主题 │ │ │ │ 主色调: [颜色选择器] #3b82f6 │ │ │ │ 辅助色: [颜色选择器] #6b7280 │ │ │ │ 背景色: [颜色选择器] #ffffff │ │ │ │ 字体设置: [下拉选择] 系统默认 │ │ │ │ 布局样式: [单选] 网格布局/列表布局/瀑布流 │ │ │ └─────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────┘ ``` ### 2.7 日志管理模块 (Log Management) #### 2.7.1 日志查看器 ``` ┌─────────────────────────────────────────────────────────┐ │ 日志管理 Log Management │ ├─────────────────────────────────────────────────────────┤ │ 🔍 [搜索] 📊 [级别筛选] 📅 [时间范围] 🔄 [自动刷新] │ ├─────────────────────────────────────────────────────────┤ │ 时间 │ 级别 │ 模块 │ 消息 │ │ ───────────┼─────┼────────┼─────────────────────── │ │ 14:30:25 │ INFO │ Upload │ 文件上传成功: IMG_001.jpg │ │ 14:30:20 │ WARN │ Cache │ Redis连接超时,使用备用缓存 │ │ 14:30:15 │ ERROR│ DB │ 数据库查询超时 │ │ 14:30:10 │ DEBUG│ API │ GET /api/photos 200 │ │ 14:30:05 │ INFO │ Auth │ 用户admin登录成功 │ │ 14:30:00 │ INFO │ System │ 系统启动完成 │ ├─────────────────────────────────────────────────────────┤ │ 📊 统计信息 │ │ 总计: 1,234条 | 错误: 12条 | 警告: 45条 | 信息: 1,177条 │ └─────────────────────────────────────────────────────────┘ ``` ## 3. 技术实现方案 ### 3.1 前端架构 #### 3.1.1 项目结构 ``` admin/ ├── src/ │ ├── components/ # 通用组件 │ │ ├── Layout/ # 布局组件 │ │ ├── Form/ # 表单组件 │ │ ├── Table/ # 表格组件 │ │ ├── Upload/ # 上传组件 │ │ └── Chart/ # 图表组件 │ ├── pages/ # 页面组件 │ │ ├── Dashboard/ # 仪表板 │ │ ├── Photos/ # 照片管理 │ │ ├── Categories/ # 分类管理 │ │ ├── Tags/ # 标签管理 │ │ ├── Users/ # 用户管理 │ │ ├── Settings/ # 系统设置 │ │ └── Logs/ # 日志管理 │ ├── services/ # API服务 │ ├── stores/ # 状态管理 │ ├── utils/ # 工具函数 │ ├── types/ # TypeScript类型 │ └── styles/ # 样式文件 ├── public/ # 静态资源 ├── package.json ├── tsconfig.json └── tailwind.config.js ``` #### 3.1.2 核心依赖 ```json { "dependencies": { "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.8.0", "typescript": "^4.9.0", "tailwindcss": "^3.2.0", "@radix-ui/react-dialog": "^1.0.2", "@radix-ui/react-dropdown-menu": "^2.0.1", "@radix-ui/react-select": "^1.2.0", "lucide-react": "^0.263.0", "zustand": "^4.3.0", "axios": "^1.3.0", "react-query": "^3.39.0", "react-hook-form": "^7.43.0", "zod": "^3.20.0", "recharts": "^2.5.0", "react-dropzone": "^14.2.0" } } ``` ### 3.2 后端API设计 #### 3.2.1 RESTful API 结构 ``` /api/admin/ ├── auth/ # 认证相关 │ ├── POST /login # 登录 │ ├── POST /logout # 登出 │ ├── POST /refresh # 刷新token │ └── GET /profile # 用户信息 ├── dashboard/ # 仪表板 │ ├── GET /stats # 统计数据 │ └── GET /activities # 近期活动 ├── photos/ # 照片管理 │ ├── GET / # 照片列表 │ ├── POST / # 创建照片 │ ├── GET /:id # 照片详情 │ ├── PUT /:id # 更新照片 │ ├── DELETE /:id # 删除照片 │ ├── POST /upload # 上传文件 │ └── POST /batch # 批量操作 ├── categories/ # 分类管理 │ ├── GET / # 分类列表 │ ├── POST / # 创建分类 │ ├── GET /:id # 分类详情 │ ├── PUT /:id # 更新分类 │ ├── DELETE /:id # 删除分类 │ └── PUT /reorder # 重新排序 ├── tags/ # 标签管理 │ ├── GET / # 标签列表 │ ├── POST / # 创建标签 │ ├── GET /:id # 标签详情 │ ├── PUT /:id # 更新标签 │ ├── DELETE /:id # 删除标签 │ └── GET /suggestions # 标签建议 ├── users/ # 用户管理 │ ├── GET / # 用户列表 │ ├── POST / # 创建用户 │ ├── GET /:id # 用户详情 │ ├── PUT /:id # 更新用户 │ ├── DELETE /:id # 删除用户 │ └── PUT /:id/password # 修改密码 ├── settings/ # 系统设置 │ ├── GET / # 获取设置 │ ├── PUT / # 更新设置 │ └── POST /test # 测试配置 └── logs/ # 日志管理 ├── GET / # 日志列表 └── GET /stats # 日志统计 ``` #### 3.2.2 数据模型定义 ```go // 照片模型 type Photo struct { ID uint `json:"id" gorm:"primaryKey"` Title string `json:"title" gorm:"size:255;not null"` Description string `json:"description" gorm:"type:text"` Filename string `json:"filename" gorm:"size:255;not null"` FilePath string `json:"file_path" gorm:"size:500;not null"` FileSize int64 `json:"file_size"` MimeType string `json:"mime_type" gorm:"size:100"` Width int `json:"width"` Height int `json:"height"` CategoryID uint `json:"category_id"` Category Category `json:"category" gorm:"foreignKey:CategoryID"` Tags []Tag `json:"tags" gorm:"many2many:photo_tags;"` EXIF string `json:"exif" gorm:"type:jsonb"` TakenAt time.Time `json:"taken_at"` Location string `json:"location" gorm:"size:255"` IsPublic bool `json:"is_public" gorm:"default:true"` Status string `json:"status" gorm:"size:20;default:'draft'"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } // 分类模型 type Category struct { ID uint `json:"id" gorm:"primaryKey"` Name string `json:"name" gorm:"size:100;not null"` Description string `json:"description" gorm:"type:text"` ParentID *uint `json:"parent_id"` Parent *Category `json:"parent" gorm:"foreignKey:ParentID"` Children []Category `json:"children" gorm:"foreignKey:ParentID"` Color string `json:"color" gorm:"size:7;default:'#3b82f6'"` CoverImage string `json:"cover_image" gorm:"size:500"` Sort int `json:"sort" gorm:"default:0"` IsActive bool `json:"is_active" gorm:"default:true"` PhotoCount int `json:"photo_count" gorm:"-"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } // 标签模型 type Tag struct { ID uint `json:"id" gorm:"primaryKey"` Name string `json:"name" gorm:"size:50;not null;unique"` Color string `json:"color" gorm:"size:7;default:'#6b7280'"` UseCount int `json:"use_count" gorm:"default:0"` IsActive bool `json:"is_active" gorm:"default:true"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } // 用户模型 type User struct { ID uint `json:"id" gorm:"primaryKey"` Username string `json:"username" gorm:"size:50;not null;unique"` Email string `json:"email" gorm:"size:100;not null;unique"` Password string `json:"-" gorm:"size:255;not null"` Name string `json:"name" gorm:"size:100"` Avatar string `json:"avatar" gorm:"size:500"` Role string `json:"role" gorm:"size:20;default:'user'"` IsActive bool `json:"is_active" gorm:"default:true"` LastLogin time.Time `json:"last_login"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } ``` ### 3.3 数据库设计 #### 3.3.1 核心表结构 ```sql -- 照片表 CREATE TABLE photos ( id SERIAL PRIMARY KEY, title VARCHAR(255) NOT NULL, description TEXT, filename VARCHAR(255) NOT NULL, file_path VARCHAR(500) NOT NULL, file_size BIGINT, mime_type VARCHAR(100), width INTEGER, height INTEGER, category_id INTEGER REFERENCES categories(id), exif JSONB, taken_at TIMESTAMP, location VARCHAR(255), is_public BOOLEAN DEFAULT true, status VARCHAR(20) DEFAULT 'draft', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- 分类表 CREATE TABLE categories ( id SERIAL PRIMARY KEY, name VARCHAR(100) NOT NULL, description TEXT, parent_id INTEGER REFERENCES categories(id), color VARCHAR(7) DEFAULT '#3b82f6', cover_image VARCHAR(500), sort INTEGER DEFAULT 0, is_active BOOLEAN DEFAULT true, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- 标签表 CREATE TABLE tags ( id SERIAL PRIMARY KEY, name VARCHAR(50) NOT NULL UNIQUE, color VARCHAR(7) DEFAULT '#6b7280', use_count INTEGER DEFAULT 0, is_active BOOLEAN DEFAULT true, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- 照片标签关联表 CREATE TABLE photo_tags ( photo_id INTEGER REFERENCES photos(id) ON DELETE CASCADE, tag_id INTEGER REFERENCES tags(id) ON DELETE CASCADE, PRIMARY KEY (photo_id, tag_id) ); -- 用户表 CREATE TABLE users ( id SERIAL PRIMARY KEY, username VARCHAR(50) NOT NULL UNIQUE, email VARCHAR(100) NOT NULL UNIQUE, password VARCHAR(255) NOT NULL, name VARCHAR(100), avatar VARCHAR(500), role VARCHAR(20) DEFAULT 'user', is_active BOOLEAN DEFAULT true, last_login TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- 系统设置表 CREATE TABLE settings ( id SERIAL PRIMARY KEY, key VARCHAR(100) NOT NULL UNIQUE, value TEXT, type VARCHAR(20) DEFAULT 'string', group_name VARCHAR(50), description TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- 操作日志表 CREATE TABLE activity_logs ( id SERIAL PRIMARY KEY, user_id INTEGER REFERENCES users(id), action VARCHAR(50) NOT NULL, resource_type VARCHAR(50), resource_id INTEGER, details JSONB, ip_address INET, user_agent TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); ``` ### 3.4 认证与权限 #### 3.4.1 JWT认证流程 ``` 1. 用户登录 → 验证账号密码 2. 生成JWT Token → 包含用户信息和权限 3. 前端存储Token → localStorage/sessionStorage 4. 请求携带Token → Authorization Header 5. 后端验证Token → 中间件验证 6. 权限检查 → 基于角色的访问控制 ``` #### 3.4.2 角色权限定义 ```go // 角色定义 const ( RoleAdmin = "admin" // 管理员 - 所有权限 RoleEditor = "editor" // 编辑者 - 内容管理权限 RoleUser = "user" // 用户 - 基本权限 RoleGuest = "guest" // 访客 - 只读权限 ) // 权限定义 type Permission struct { Resource string // 资源类型 Actions []string // 允许的操作 } // 角色权限映射 var RolePermissions = map[string][]Permission{ RoleAdmin: { {Resource: "photos", Actions: []string{"create", "read", "update", "delete"}}, {Resource: "categories", Actions: []string{"create", "read", "update", "delete"}}, {Resource: "tags", Actions: []string{"create", "read", "update", "delete"}}, {Resource: "users", Actions: []string{"create", "read", "update", "delete"}}, {Resource: "settings", Actions: []string{"read", "update"}}, {Resource: "logs", Actions: []string{"read"}}, }, RoleEditor: { {Resource: "photos", Actions: []string{"create", "read", "update", "delete"}}, {Resource: "categories", Actions: []string{"create", "read", "update"}}, {Resource: "tags", Actions: []string{"create", "read", "update"}}, }, RoleUser: { {Resource: "photos", Actions: []string{"read"}}, {Resource: "categories", Actions: []string{"read"}}, {Resource: "tags", Actions: []string{"read"}}, }, RoleGuest: { {Resource: "photos", Actions: []string{"read"}}, {Resource: "categories", Actions: []string{"read"}}, }, } ``` ### 3.5 文件上传与处理 #### 3.5.1 上传流程 ``` 1. 前端选择文件 → 文件验证 (格式、大小) 2. 创建上传任务 → 生成临时文件路径 3. 分块上传 → 支持断点续传 4. 文件合并 → 合并所有分块 5. 图片处理 → 生成缩略图、提取EXIF 6. 存储文件 → 本地存储或云存储 7. 更新数据库 → 保存文件信息 8. 返回结果 → 上传成功确认 ``` #### 3.5.2 图片处理 ```go // 图片处理服务 type ImageProcessor struct { storage StorageService thumbnails []ThumbnailConfig watermark WatermarkConfig quality int } // 缩略图配置 type ThumbnailConfig struct { Name string Width int Height int Crop bool } // 处理上传的图片 func (p *ImageProcessor) ProcessImage(file *multipart.FileHeader) (*ImageResult, error) { // 1. 验证文件格式 if !p.isValidImage(file) { return nil, ErrInvalidImageFormat } // 2. 打开图片 img, err := bimg.NewFromFile(file.Filename) if err != nil { return nil, err } // 3. 提取EXIF信息 exif, err := p.extractEXIF(img) if err != nil { logger.Warn("Failed to extract EXIF", "error", err) } // 4. 生成缩略图 thumbnails := make(map[string]string) for _, config := range p.thumbnails { thumbnail, err := p.createThumbnail(img, config) if err != nil { logger.Error("Failed to create thumbnail", "config", config, "error", err) continue } thumbnails[config.Name] = thumbnail } // 5. 添加水印 (可选) if p.watermark.Enabled { img, err = p.addWatermark(img, p.watermark) if err != nil { logger.Warn("Failed to add watermark", "error", err) } } // 6. 保存原图 processed, err := img.Process(bimg.Options{ Quality: p.quality, Type: bimg.JPEG, }) if err != nil { return nil, err } // 7. 上传到存储 originalPath, err := p.storage.Save(processed, "originals") if err != nil { return nil, err } return &ImageResult{ OriginalPath: originalPath, Thumbnails: thumbnails, EXIF: exif, Width: img.Size().Width, Height: img.Size().Height, }, nil } ``` ### 3.6 性能优化 #### 3.6.1 前端优化 ```javascript // 1. 代码分割 const LazyPhotoManagement = lazy(() => import('./pages/Photos')); const LazyDashboard = lazy(() => import('./pages/Dashboard')); // 2. 虚拟滚动 (大量照片列表) import { FixedSizeGrid } from 'react-window'; // 3. 图片懒加载 const LazyImage = ({ src, alt, ...props }) => { const [isLoaded, setIsLoaded] = useState(false); const [isInView, setIsInView] = useState(false); const imgRef = useRef(); useEffect(() => { const observer = new IntersectionObserver( ([entry]) => { if (entry.isIntersecting) { setIsInView(true); observer.disconnect(); } }, { threshold: 0.1 } ); if (imgRef.current) { observer.observe(imgRef.current); } return () => observer.disconnect(); }, []); return (