初始化
This commit is contained in:
869
docs/architecture/api-contracts.md
Normal file
869
docs/architecture/api-contracts.md
Normal file
@@ -0,0 +1,869 @@
|
||||
# API Contracts — Hyperf RESTful API 契约
|
||||
|
||||
> 定义 API 设计规范和端点文档。AI Agent 在生成 Controller 和前端 API 调用时参考本文档。
|
||||
>
|
||||
> **服务对象标注说明**:
|
||||
> - 🟦 `[user]` — 仅用户端(`Case-Database-Frontend-user/`)调用
|
||||
> - 🟧 `[admin]` — 仅管理端(`Case-Database-Frontend-admin/`)调用
|
||||
> - 🟩 `[both]` — 两个前端均可调用
|
||||
|
||||
---
|
||||
|
||||
## 1. 通用规范
|
||||
|
||||
### Base URL
|
||||
```
|
||||
# 管理端 API
|
||||
开发: http://localhost:9501/admin
|
||||
生产: https://api.example.com/admin
|
||||
|
||||
# 用户端 API
|
||||
开发: http://localhost:9501/api
|
||||
生产: https://api.example.com/api
|
||||
```
|
||||
|
||||
### 统一响应格式
|
||||
|
||||
**成功**
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "ok",
|
||||
"data": {}
|
||||
}
|
||||
```
|
||||
|
||||
**列表(带分页)**
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "ok",
|
||||
"data": {
|
||||
"items": [],
|
||||
"total": 100
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**错误**
|
||||
```json
|
||||
{
|
||||
"code": 422,
|
||||
"message": "Validation failed",
|
||||
"data": {
|
||||
"errors": {
|
||||
"email": ["The email field is required."]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### HTTP 状态码
|
||||
|
||||
| 状态码 | 含义 |
|
||||
|--------|------|
|
||||
| 200 | 成功 |
|
||||
| 201 | 创建成功 |
|
||||
| 400 | 请求参数错误 |
|
||||
| 401 | 未认证 (Token 无效/过期) |
|
||||
| 403 | 无权限 |
|
||||
| 404 | 资源不存在 |
|
||||
| 409 | 资源冲突 (锁定) |
|
||||
| 422 | 验证失败 |
|
||||
| 429 | 请求频率过高 |
|
||||
| 500 | 服务器内部错误 |
|
||||
|
||||
### 认证
|
||||
|
||||
所有需要认证的接口在 Header 中携带:
|
||||
```
|
||||
Authorization: Bearer <access_token>
|
||||
```
|
||||
|
||||
Token 过期返回 `401`,客户端用 Refresh Token 刷新。
|
||||
|
||||
### 分页参数
|
||||
|
||||
| 参数 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| `page` | int | 1 | 页码 |
|
||||
| `page_size` | int | 10 | 每页数量 (max: 100) |
|
||||
|
||||
### 排序参数
|
||||
|
||||
```
|
||||
?sort=created_at&order=desc
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 核心 API 端点
|
||||
|
||||
### 2.1 🟦 用户端认证 `[user]` — 16 端点
|
||||
|
||||
| 方法 | 路径 | 说明 | 认证 |
|
||||
|------|------|------|------|
|
||||
| POST | `/api/auth/captcha/challenge` | 获取图形验证码挑战(返回 `captcha_token`, `width`, `target_x`) | 否 |
|
||||
| POST | `/api/auth/captcha/verify` | 校验滑块位置(`captcha_token` + `answer_x`,tolerance=10px) | 否 |
|
||||
| POST | `/api/auth/register` | 用户注册 | 否 |
|
||||
| POST | `/api/auth/login` | 账号密码登录 | 否 |
|
||||
| POST | `/api/auth/sms/send` | 发送短信验证码 | 否 |
|
||||
| POST | `/api/auth/sms/login` | 短信验证码登录 | 否 |
|
||||
| POST | `/api/auth/forgot-password` | 忘记密码(账号/手机号校验后重置) | 否 |
|
||||
| POST | `/api/auth/logout` | 登出 | 是 |
|
||||
| POST | `/api/auth/refresh` | 刷新 Token | 否(需 Refresh Token) |
|
||||
| GET | `/api/auth/profile` | 当前用户信息 | 是 |
|
||||
| PUT | `/api/auth/profile` | 更新个人信息 | 是 |
|
||||
| GET | `/api/auth/sessions` | 获取当前账号会话列表 | 是 |
|
||||
| POST | `/api/auth/sessions/:sessionId/revoke` | 踢出指定会话 | 是 |
|
||||
| GET | `/api/auth/enterprise-sso/redirect` | 企业 SSO 跳转入口 | 否 |
|
||||
| POST | `/api/auth/enterprise-sso/callback` | 企业 SSO 回调登录 | 否 |
|
||||
| POST | `/api/auth/enterprise-sso/direct-login` | 企业平台直达登录(签名票据) | 否 |
|
||||
|
||||
#### 认证请求字段约定
|
||||
|
||||
- `/api/auth/register` 必填字段:`username`, `phone`, `sms_code`, `password`, `password_confirm`, `captcha_token`, `agree`。
|
||||
- `/api/auth/login` 必填字段:`username_or_phone`, `password`, `captcha_token`。
|
||||
- `/api/auth/sms/send` 必填字段:`phone`, `captcha_token`。
|
||||
- `/api/auth/sms/login` 必填字段:`phone`, `code`, `captcha_token`。
|
||||
- `/api/auth/forgot-password` 必填字段:`username_or_phone`, `phone`, `sms_code`, `new_password`, `new_password_confirm`, `captcha_token`。
|
||||
- 协议同意字段:`agree=true`,并由后端记录 `agree_at` 与 `agreement_version`。
|
||||
|
||||
#### 认证限流策略
|
||||
|
||||
| 接口 | 限流规则 |
|
||||
|------|----------|
|
||||
| 登录 `/api/auth/login` | 同 IP 5 次/分钟;同账号 10 次/小时 |
|
||||
| 短信发送 `/api/auth/sms/send` | 同手机号 1 次/分钟,5 次/天 |
|
||||
| 注册 `/api/auth/register` | 同 IP 3 次/小时 |
|
||||
| 找回密码 `/api/auth/forgot-password` | 同账号 3 次/天 |
|
||||
|
||||
#### 第三方登录
|
||||
|
||||
| 方法 | 路径 | 说明 | 认证 |
|
||||
|------|------|------|------|
|
||||
| GET | `/api/auth/oauth/:provider` | OAuth 跳转(provider: wechat / qq) | 否 |
|
||||
| GET | `/api/auth/oauth/:provider/callback` | OAuth 回调 | 否 |
|
||||
|
||||
---
|
||||
|
||||
### 2.2 🟦 用户端案例 `[user]` — 8 端点
|
||||
|
||||
| 方法 | 路径 | 说明 | 认证 |
|
||||
|------|------|------|------|
|
||||
| GET | `/api/cases` | 案例列表(支持多维筛选) | 否 |
|
||||
| GET | `/api/cases/:id` | 案例详情 | 否 |
|
||||
| GET | `/api/cases/:id/comments` | 案例评论列表 | 否 |
|
||||
| POST | `/api/cases/:id/comments` | 发表评论 | 是 |
|
||||
| POST | `/api/cases/:id/favorite` | 收藏 / 取消收藏 (toggle) | 是 |
|
||||
| POST | `/api/cases/:id/like` | 点赞 / 取消点赞 (toggle) | 是 |
|
||||
| GET | `/api/cases/:id/related` | 相关推荐案例 | 否 |
|
||||
| GET | `/api/cases/:id/files` | 案例文件列表(按阶段分组) | 否 |
|
||||
|
||||
#### 案例列表筛选参数
|
||||
|
||||
| 参数 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `category_id` | int | 建筑类型分类 |
|
||||
| `style` | string | 风格标签 slug |
|
||||
| `keyword` | string | 搜索关键词(标题 / 编号) |
|
||||
| `area_min` | number | 最小占地面积 |
|
||||
| `area_max` | number | 最大占地面积 |
|
||||
| `cost_min` | number | 最低造价 |
|
||||
| `cost_max` | number | 最高造价 |
|
||||
| `floors` | int | 层数 |
|
||||
| `bedroom_count` | int | 卧室数量 |
|
||||
| `site_width_min` | number | 最小面宽 |
|
||||
| `site_depth_min` | number | 最小进深 |
|
||||
| `tag_ids` | string | 标签 ID(逗号分隔) |
|
||||
| `is_featured` | boolean | 仅看精选 |
|
||||
| `sort` | string | 排序字段:`created_at` / `view_count` / `like_count` |
|
||||
| `order` | string | `asc` / `desc` |
|
||||
|
||||
---
|
||||
|
||||
### 2.3 🟦 用户端设计师 `[user]` — 4 端点
|
||||
|
||||
| 方法 | 路径 | 说明 | 认证 |
|
||||
|------|------|------|------|
|
||||
| GET | `/api/designers/:id` | 设计师详情 | 否 |
|
||||
| GET | `/api/designers/:id/cases` | 设计师作品集 | 否 |
|
||||
| POST | `/api/designers/:id/follow` | 关注 / 取消关注 (toggle) | 是 |
|
||||
| GET | `/api/designers/:id/awards` | 设计师荣誉奖项 | 否 |
|
||||
|
||||
---
|
||||
|
||||
### 2.4 🟦 用户端内容 `[user]` — 8 端点
|
||||
|
||||
| 方法 | 路径 | 说明 | 认证 |
|
||||
|------|------|------|------|
|
||||
| GET | `/api/banners` | 首页轮播列表 | 否 |
|
||||
| GET | `/api/categories` | 分类列表 | 否 |
|
||||
| GET | `/api/tags` | 标签列表(支持 `?type=style` 筛选) | 否 |
|
||||
| GET | `/api/tags/hot` | 热门标签 | 否 |
|
||||
| GET | `/api/topics` | 专题列表 | 否 |
|
||||
| GET | `/api/topics/:id` | 专题详情(含关联案例列表) | 否 |
|
||||
| POST | `/api/newsletter/subscribe` | 邮箱订阅 | 否 |
|
||||
| GET | `/api/my/favorites` | 我的收藏列表 | 是 |
|
||||
|
||||
---
|
||||
|
||||
### 2.5 🟧 管理端认证 `[admin]` — 4 端点
|
||||
|
||||
| 方法 | 路径 | 说明 | 认证 |
|
||||
|------|------|------|------|
|
||||
| POST | `/admin/auth/login` | 管理员登录 | 否 |
|
||||
| POST | `/admin/auth/logout` | 登出 | 是 |
|
||||
| POST | `/admin/auth/refresh` | 刷新 Token | 否(需 Refresh Token) |
|
||||
| GET | `/admin/auth/info` | 当前管理员信息(含角色权限) | 是 |
|
||||
|
||||
---
|
||||
|
||||
### 2.6 🟧 管理端案例管理 `[admin]` — 9 端点
|
||||
|
||||
| 方法 | 路径 | 说明 | 权限 |
|
||||
|------|------|------|------|
|
||||
| GET | `/admin/cases` | 案例列表(含草稿 / 待审 / 已发布 / 已归档筛选) | `case:list` |
|
||||
| GET | `/admin/cases/:id` | 案例详情 | `case:detail` |
|
||||
| POST | `/admin/cases` | 创建案例 | `case:create` |
|
||||
| PUT | `/admin/cases/:id` | 更新案例 | `case:update` |
|
||||
| DELETE | `/admin/cases/:id` | 删除案例(软删除) | `case:delete` |
|
||||
| PUT | `/admin/cases/:id/status` | 变更案例状态 | `case:status` |
|
||||
| PUT | `/admin/cases/:id/featured` | 精选标记 toggle | `case:feature` |
|
||||
| POST | `/admin/cases/:id/files` | 上传案例文件(分阶段) | `case:upload` |
|
||||
| DELETE | `/admin/cases/:id/files/:fileId` | 删除案例文件 | `case:upload` |
|
||||
|
||||
---
|
||||
|
||||
### 2.7 🟧 管理端轮播管理 `[admin]` — 5 端点
|
||||
|
||||
| 方法 | 路径 | 说明 | 权限 |
|
||||
|------|------|------|------|
|
||||
| GET | `/admin/banners` | 轮播列表 | `banner:list` |
|
||||
| POST | `/admin/banners` | 创建轮播 | `banner:create` |
|
||||
| PUT | `/admin/banners/:id` | 更新轮播 | `banner:update` |
|
||||
| DELETE | `/admin/banners/:id` | 删除轮播 | `banner:delete` |
|
||||
| PUT | `/admin/banners/sort` | 批量排序 | `banner:update` |
|
||||
|
||||
---
|
||||
|
||||
### 2.8 🟧 管理端专题管理 `[admin]` — 6 端点
|
||||
|
||||
| 方法 | 路径 | 说明 | 权限 |
|
||||
|------|------|------|------|
|
||||
| GET | `/admin/topics` | 专题列表 | `topic:list` |
|
||||
| POST | `/admin/topics` | 创建专题 | `topic:create` |
|
||||
| PUT | `/admin/topics/:id` | 更新专题 | `topic:update` |
|
||||
| DELETE | `/admin/topics/:id` | 删除专题 | `topic:delete` |
|
||||
| POST | `/admin/topics/:id/cases` | 关联案例到专题 | `topic:update` |
|
||||
| DELETE | `/admin/topics/:id/cases/:caseId` | 取消关联案例 | `topic:update` |
|
||||
|
||||
---
|
||||
|
||||
### 2.9 🟧 管理端分类标签 `[admin]` — 7 端点
|
||||
|
||||
| 方法 | 路径 | 说明 | 权限 |
|
||||
|------|------|------|------|
|
||||
| GET | `/admin/categories` | 分类列表 | `category:list` |
|
||||
| POST | `/admin/categories` | 创建分类 | `category:create` |
|
||||
| PUT | `/admin/categories/:id` | 更新分类 | `category:update` |
|
||||
| DELETE | `/admin/categories/:id` | 删除分类(需判断无关联案例) | `category:delete` |
|
||||
| GET | `/admin/tags` | 标签列表(支持 `?type=` 筛选) | `tag:list` |
|
||||
| POST | `/admin/tags` | 创建标签 | `tag:create` |
|
||||
| PUT | `/admin/tags/:id` | 更新标签 | `tag:update` |
|
||||
| DELETE | `/admin/tags/:id` | 删除标签 | `tag:delete` |
|
||||
|
||||
---
|
||||
|
||||
### 2.10 🟧 管理端设计师管理 `[admin]` — 5 端点
|
||||
|
||||
| 方法 | 路径 | 说明 | 权限 |
|
||||
|------|------|------|------|
|
||||
| GET | `/admin/designers` | 设计师列表 | `designer:list` |
|
||||
| POST | `/admin/designers` | 创建设计师 | `designer:create` |
|
||||
| PUT | `/admin/designers/:id` | 更新设计师 | `designer:update` |
|
||||
| DELETE | `/admin/designers/:id` | 删除设计师 | `designer:delete` |
|
||||
| PUT | `/admin/designers/:id/active` | 启用/停用设计师 | `designer:update` |
|
||||
|
||||
---
|
||||
|
||||
### 2.11 🟧 管理端评论管理 `[admin]` — 4 端点
|
||||
|
||||
| 方法 | 路径 | 说明 | 权限 |
|
||||
|------|------|------|------|
|
||||
| GET | `/admin/comments` | 评论列表(支持 `?status=pending` 筛选) | `comment:list` |
|
||||
| PUT | `/admin/comments/:id/approve` | 审核通过 | `comment:audit` |
|
||||
| PUT | `/admin/comments/:id/reject` | 审核拒绝 | `comment:audit` |
|
||||
| DELETE | `/admin/comments/:id` | 删除评论 | `comment:delete` |
|
||||
|
||||
---
|
||||
|
||||
### 2.12 🟧 管理端用户与权限 `[admin]` — 8 端点
|
||||
|
||||
| 方法 | 路径 | 说明 | 权限 |
|
||||
|------|------|------|------|
|
||||
| GET | `/admin/users` | 用户列表 | `user:list` |
|
||||
| POST | `/admin/users` | 创建管理员 | `user:create` |
|
||||
| PUT | `/admin/users/:id` | 更新用户 | `user:update` |
|
||||
| PUT | `/admin/users/:id/status` | 启用/禁用用户 | `user:update` |
|
||||
| GET | `/admin/roles` | 角色列表 | `role:list` |
|
||||
| POST | `/admin/roles` | 创建角色(含菜单权限分配) | `role:create` |
|
||||
| PUT | `/admin/roles/:id` | 更新角色 | `role:update` |
|
||||
| GET | `/admin/menus` | 菜单权限树 | `menu:list` |
|
||||
|
||||
---
|
||||
|
||||
### 2.13 🟧 管理端系统配置 `[admin]` — 2 端点
|
||||
|
||||
| 方法 | 路径 | 说明 | 权限 |
|
||||
|------|------|------|------|
|
||||
| GET | `/admin/configs` | 获取系统配置(支持 `?group=site` 筛选) | `config:list` |
|
||||
| PUT | `/admin/configs` | 批量更新系统配置 | `config:update` |
|
||||
|
||||
---
|
||||
|
||||
### 2.14 🟧 管理端数据仪表盘 `[admin]` — 3 端点
|
||||
|
||||
| 方法 | 路径 | 说明 | 权限 |
|
||||
|------|------|------|------|
|
||||
| GET | `/admin/dashboard/overview` | 概览统计(总案例数 / 总用户数 / 今日浏览量等) | `dashboard:view` |
|
||||
| GET | `/admin/dashboard/trends` | 趋势数据(按日/周/月的浏览 / 注册曲线) | `dashboard:view` |
|
||||
| GET | `/admin/dashboard/rankings` | 热门排行(案例浏览 TOP / 下载 TOP / 活跃设计师) | `dashboard:view` |
|
||||
|
||||
---
|
||||
|
||||
### 2.15 🟧 管理端日志 `[admin]` — 2 端点
|
||||
|
||||
| 方法 | 路径 | 说明 | 权限 |
|
||||
|------|------|------|------|
|
||||
| GET | `/admin/logs/operations` | 操作日志列表 | `log:list` |
|
||||
| GET | `/admin/logs/downloads` | 下载日志列表 | `log:list` |
|
||||
|
||||
---
|
||||
|
||||
### 2.16 🟩 通用上传 `[both]` — 1 端点
|
||||
|
||||
| 方法 | 路径 | 说明 | 认证 |
|
||||
|------|------|------|------|
|
||||
| POST | `/api/upload/image` | 上传图片(头像/封面/banner) | 是 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 请求/响应示例
|
||||
|
||||
### 3.1 管理端登录
|
||||
|
||||
```bash
|
||||
POST /admin/auth/login
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"username": "admin",
|
||||
"password": "password123"
|
||||
}
|
||||
|
||||
# Response 200
|
||||
{
|
||||
"code": 200,
|
||||
"message": "ok",
|
||||
"data": {
|
||||
"access_token": "eyJhbGci...",
|
||||
"refresh_token": "eyJhbGci...",
|
||||
"expires_in": 7200,
|
||||
"user": {
|
||||
"id": 1,
|
||||
"username": "admin",
|
||||
"nickname": "超级管理员",
|
||||
"avatar": "https://cdn.example.com/avatars/admin.jpg",
|
||||
"roles": ["super_admin"],
|
||||
"permissions": ["case:*", "banner:*", "topic:*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 用户端登录(账号密码)
|
||||
|
||||
```bash
|
||||
POST /api/auth/login
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"phone": "13800138000",
|
||||
"password": "password123"
|
||||
}
|
||||
|
||||
# Response 200
|
||||
{
|
||||
"code": 200,
|
||||
"message": "ok",
|
||||
"data": {
|
||||
"access_token": "eyJhbGci...",
|
||||
"refresh_token": "eyJhbGci...",
|
||||
"expires_in": 7200,
|
||||
"user": {
|
||||
"id": 42,
|
||||
"nickname": "建筑师小李",
|
||||
"avatar": "https://cdn.example.com/avatars/42.jpg",
|
||||
"phone": "138****8000",
|
||||
"role_label": "Architect"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.3 用户端短信登录
|
||||
|
||||
```bash
|
||||
# Step 1: 发送验证码
|
||||
POST /api/auth/sms/send
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"phone": "13800138000"
|
||||
}
|
||||
|
||||
# Response 200
|
||||
{
|
||||
"code": 200,
|
||||
"message": "验证码已发送",
|
||||
"data": {
|
||||
"expires_in": 300
|
||||
}
|
||||
}
|
||||
|
||||
# Step 2: 验证码登录
|
||||
POST /api/auth/sms/login
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"phone": "13800138000",
|
||||
"code": "123456"
|
||||
}
|
||||
|
||||
# Response 200 (同 3.2 登录响应)
|
||||
```
|
||||
|
||||
### 3.4 案例列表(多维筛选)
|
||||
|
||||
```bash
|
||||
GET /api/cases?category_id=1&style=modern&area_min=100&area_max=300&cost_max=60&floors=3&sort=created_at&order=desc&page=1&page_size=12
|
||||
Authorization: Bearer eyJhbGci... (可选)
|
||||
|
||||
# Response 200
|
||||
{
|
||||
"code": 200,
|
||||
"message": "ok",
|
||||
"data": {
|
||||
"items": [
|
||||
{
|
||||
"id": 88,
|
||||
"title": "云端墅 The Cloud Villa",
|
||||
"code": "P-2024-8839",
|
||||
"cover_image": "https://cdn.example.com/cases/88/cover.jpg",
|
||||
"category": {
|
||||
"id": 1,
|
||||
"name": "别墅",
|
||||
"slug": "villa"
|
||||
},
|
||||
"layout": "3室2厅3卫",
|
||||
"floors_above": 3,
|
||||
"site_area": 128.50,
|
||||
"total_building_area": 340.00,
|
||||
"cost_min": 45.00,
|
||||
"cost_max": 55.00,
|
||||
"architecture_style": "现代主义",
|
||||
"is_featured": true,
|
||||
"tags": [
|
||||
{ "id": 1, "name": "现代", "type": "style" },
|
||||
{ "id": 5, "name": "落地窗", "type": "feature" }
|
||||
],
|
||||
"lead_designer": {
|
||||
"id": 12,
|
||||
"name_cn": "张明远",
|
||||
"title_badge": "Lead Architect"
|
||||
},
|
||||
"view_count": 1234,
|
||||
"like_count": 56,
|
||||
"favorite_count": 23,
|
||||
"is_liked": false,
|
||||
"is_favorited": true,
|
||||
"published_at": "2024-12-15T10:00:00Z"
|
||||
}
|
||||
],
|
||||
"total": 156
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.5 案例详情
|
||||
|
||||
```bash
|
||||
GET /api/cases/88
|
||||
Authorization: Bearer eyJhbGci... (可选)
|
||||
|
||||
# Response 200
|
||||
{
|
||||
"code": 200,
|
||||
"message": "ok",
|
||||
"data": {
|
||||
"id": 88,
|
||||
"title": "云端墅 The Cloud Villa",
|
||||
"code": "P-2024-8839",
|
||||
"cover_image": "https://cdn.example.com/cases/88/cover.jpg",
|
||||
"category": { "id": 1, "name": "别墅", "slug": "villa" },
|
||||
"status": "published",
|
||||
"is_featured": true,
|
||||
"layout": "3室2厅3卫",
|
||||
"floor_height": "3.6/3.3/3.3m",
|
||||
|
||||
"dimensions": {
|
||||
"site": {
|
||||
"site_width": "面宽 ≥ 10.5m",
|
||||
"site_depth": "进深 ≥ 12.2m",
|
||||
"site_area": 128.50,
|
||||
"lighting_restriction": "南侧无遮挡",
|
||||
"site_shape": "规则矩形"
|
||||
},
|
||||
"scale": {
|
||||
"floors_above": 3,
|
||||
"floors_below": 1,
|
||||
"cost_min": 45.00,
|
||||
"cost_max": 55.00,
|
||||
"total_building_area": 340.00,
|
||||
"bedroom_count": 5,
|
||||
"bedroom_note": "含1主卧套房"
|
||||
},
|
||||
"function": {
|
||||
"stair_type": "旋转楼梯 + 电梯",
|
||||
"special_space": "地下影音室 / 露台花园",
|
||||
"bedroom_config": "主卧套房含衣帽间",
|
||||
"leisure_space": "屋顶露台 / 下沉式客厅",
|
||||
"kitchen_dining": "开放式西厨 + 独立中厨",
|
||||
"bathroom_config": "5卫 (含2套干湿分离)"
|
||||
},
|
||||
"appearance": {
|
||||
"architecture_style": "现代主义",
|
||||
"roof_type": "平屋顶 + 局部坡屋顶",
|
||||
"facade_material": "白色真石漆 + 深灰铝板"
|
||||
},
|
||||
"structure": {
|
||||
"structure_type": "框架结构",
|
||||
"foundation_type": "筏板基础",
|
||||
"layout_logic": "南北通透 / 动静分区",
|
||||
"wall_thickness": "240mm (外) + 120mm (内)",
|
||||
"seismic_rating": "7度设防",
|
||||
"insulation_type": "外墙外保温 EPS",
|
||||
"roof_structure": "SBS防水 + 挤塑板保温"
|
||||
}
|
||||
},
|
||||
|
||||
"design_concept": "<p>设计理念正文...</p>",
|
||||
"concept_style": "现代主义",
|
||||
"concept_material": "混凝土 / 玻璃 / 石材",
|
||||
"concept_target": "追求品质生活的年轻家庭",
|
||||
"meta": {},
|
||||
|
||||
"images": {
|
||||
"effect": [
|
||||
{ "id": 1, "url": "https://cdn.example.com/cases/88/effect-1.jpg", "thumbnail_url": "..." }
|
||||
],
|
||||
"floor_plan": [
|
||||
{ "id": 2, "url": "https://cdn.example.com/cases/88/plan-1f.jpg", "thumbnail_url": "..." }
|
||||
],
|
||||
"elevation": [
|
||||
{ "id": 3, "url": "https://cdn.example.com/cases/88/elev-south.jpg", "thumbnail_url": "..." }
|
||||
]
|
||||
},
|
||||
|
||||
"files": {
|
||||
"floor_plan": [
|
||||
{ "id": 1, "file_name": "一层平面图.dwg", "file_ext": "dwg", "file_size": 2048000 }
|
||||
],
|
||||
"exterior": [],
|
||||
"construction": [
|
||||
{ "id": 2, "file_name": "施工图全套.pdf", "file_ext": "pdf", "file_size": 15360000 }
|
||||
],
|
||||
"structure": [],
|
||||
"interior": [],
|
||||
"courtyard": []
|
||||
},
|
||||
|
||||
"team": [
|
||||
{
|
||||
"designer": {
|
||||
"id": 12,
|
||||
"name_cn": "张明远",
|
||||
"name_en": "Zhang Mingyuan",
|
||||
"title": "方案主创设计师",
|
||||
"title_badge": "Lead Architect",
|
||||
"portrait": "https://cdn.example.com/designers/12/portrait.jpg"
|
||||
},
|
||||
"role": "scheme",
|
||||
"is_lead": true
|
||||
},
|
||||
{
|
||||
"designer": {
|
||||
"id": 15,
|
||||
"name_cn": "李结构",
|
||||
"title": "结构工程师",
|
||||
"title_badge": "Structural Eng."
|
||||
},
|
||||
"role": "structure",
|
||||
"is_lead": false
|
||||
}
|
||||
],
|
||||
|
||||
"tags": [
|
||||
{ "id": 1, "name": "现代", "type": "style" },
|
||||
{ "id": 5, "name": "落地窗", "type": "feature" }
|
||||
],
|
||||
|
||||
"stats": {
|
||||
"view_count": 1234,
|
||||
"like_count": 56,
|
||||
"favorite_count": 23,
|
||||
"download_count": 8,
|
||||
"comment_count": 12
|
||||
},
|
||||
|
||||
"user_interaction": {
|
||||
"is_liked": false,
|
||||
"is_favorited": true
|
||||
},
|
||||
|
||||
"published_at": "2024-12-15T10:00:00Z",
|
||||
"created_at": "2024-12-10T08:00:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.6 管理端文件上传(分阶段)
|
||||
|
||||
```bash
|
||||
POST /admin/cases/88/files
|
||||
Authorization: Bearer eyJhbGci...
|
||||
Content-Type: multipart/form-data
|
||||
|
||||
# Form Data
|
||||
stage: construction
|
||||
file: (binary) 施工图全套.pdf
|
||||
|
||||
# Response 201
|
||||
{
|
||||
"code": 201,
|
||||
"message": "上传成功",
|
||||
"data": {
|
||||
"id": 156,
|
||||
"case_id": 88,
|
||||
"stage": "construction",
|
||||
"file_name": "施工图全套.pdf",
|
||||
"file_path": "cases/88/construction/施工图全套.pdf",
|
||||
"file_size": 15360000,
|
||||
"file_ext": "pdf",
|
||||
"mime_type": "application/pdf"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.7 管理端创建案例
|
||||
|
||||
```bash
|
||||
POST /admin/cases
|
||||
Authorization: Bearer eyJhbGci...
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"title": "云端墅 The Cloud Villa",
|
||||
"code": "P-2024-8839",
|
||||
"category_id": 1,
|
||||
"cover_image": "https://cdn.example.com/cases/88/cover.jpg",
|
||||
"layout": "3室2厅3卫",
|
||||
"floor_height": "3.6/3.3/3.3m",
|
||||
"site_width": "面宽 ≥ 10.5m",
|
||||
"site_depth": "进深 ≥ 12.2m",
|
||||
"site_area": 128.50,
|
||||
"floors_above": 3,
|
||||
"floors_below": 1,
|
||||
"cost_min": 45.00,
|
||||
"cost_max": 55.00,
|
||||
"total_building_area": 340.00,
|
||||
"bedroom_count": 5,
|
||||
"bedroom_note": "含1主卧套房",
|
||||
"architecture_style": "现代主义",
|
||||
"structure_type": "框架结构",
|
||||
"design_concept": "<p>设计理念正文...</p>",
|
||||
"tag_ids": [1, 5, 12],
|
||||
"team": [
|
||||
{ "designer_id": 12, "role": "scheme", "is_lead": true },
|
||||
{ "designer_id": 15, "role": "structure", "is_lead": false }
|
||||
]
|
||||
}
|
||||
|
||||
# Response 201
|
||||
{
|
||||
"code": 201,
|
||||
"message": "创建成功",
|
||||
"data": {
|
||||
"id": 88,
|
||||
"code": "P-2024-8839",
|
||||
"status": "draft"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.8 管理端案例状态变更
|
||||
|
||||
```bash
|
||||
PUT /admin/cases/88/status
|
||||
Authorization: Bearer eyJhbGci...
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"status": "published"
|
||||
}
|
||||
|
||||
# Response 200
|
||||
{
|
||||
"code": 200,
|
||||
"message": "状态已更新",
|
||||
"data": {
|
||||
"id": 88,
|
||||
"status": "published",
|
||||
"published_at": "2024-12-15T10:00:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.9 设计师详情
|
||||
|
||||
```bash
|
||||
GET /api/designers/12
|
||||
|
||||
# Response 200
|
||||
{
|
||||
"code": 200,
|
||||
"message": "ok",
|
||||
"data": {
|
||||
"id": 12,
|
||||
"name_cn": "张明远",
|
||||
"name_en": "Zhang Mingyuan",
|
||||
"title": "方案主创设计师",
|
||||
"title_badge": "Lead Architect",
|
||||
"company": "ZM 建筑事务所",
|
||||
"city": "上海",
|
||||
"portrait": "https://cdn.example.com/designers/12/portrait.jpg",
|
||||
"portrait_caption": "STUDIO PORTRAIT © 2023",
|
||||
"years_of_experience": 15,
|
||||
"project_count": 42,
|
||||
"design_philosophy_quote": "建筑是凝固的音乐",
|
||||
"design_philosophy": "<p>设计理念详述...</p>",
|
||||
"specialties": [
|
||||
{ "id": 20, "name": "参数化设计" },
|
||||
{ "id": 21, "name": "可持续建筑" }
|
||||
],
|
||||
"awards": [
|
||||
{
|
||||
"year": 2023,
|
||||
"title": "红点设计大奖 Red Dot Award",
|
||||
"description": "最佳室内设计类 - The Cloud Villa"
|
||||
},
|
||||
{
|
||||
"year": 2022,
|
||||
"title": "Architizer A+ Awards",
|
||||
"description": "住宅建筑类 - 山水间"
|
||||
}
|
||||
],
|
||||
"stats": {
|
||||
"follower_count": 326,
|
||||
"view_count": 8920,
|
||||
"project_count": 42
|
||||
},
|
||||
"user_interaction": {
|
||||
"is_followed": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.10 管理端创建轮播
|
||||
|
||||
```bash
|
||||
POST /admin/banners
|
||||
Authorization: Bearer eyJhbGci...
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"title": "云端墅 — 现代都市别墅的极致诠释",
|
||||
"description": "三层框架结构,340㎡ 全功能空间",
|
||||
"image": "https://cdn.example.com/banners/cloud-villa.jpg",
|
||||
"label": "精选项目",
|
||||
"link_type": "case",
|
||||
"link_url": "/cases/88",
|
||||
"sort": 1,
|
||||
"is_active": true
|
||||
}
|
||||
|
||||
# Response 201
|
||||
{
|
||||
"code": 201,
|
||||
"message": "创建成功",
|
||||
"data": {
|
||||
"id": 5,
|
||||
"title": "云端墅 — 现代都市别墅的极致诠释",
|
||||
"sort": 1,
|
||||
"is_active": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.11 管理端仪表盘概览
|
||||
|
||||
```bash
|
||||
GET /admin/dashboard/overview
|
||||
Authorization: Bearer eyJhbGci...
|
||||
|
||||
# Response 200
|
||||
{
|
||||
"code": 200,
|
||||
"message": "ok",
|
||||
"data": {
|
||||
"total_cases": 256,
|
||||
"published_cases": 198,
|
||||
"total_designers": 42,
|
||||
"total_users": 3680,
|
||||
"today_views": 1250,
|
||||
"today_registers": 15,
|
||||
"pending_comments": 8,
|
||||
"pending_cases": 3
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 端点汇总统计
|
||||
|
||||
| 分组 | 服务对象 | 端点数 |
|
||||
|------|----------|--------|
|
||||
| 用户端认证 | 🟦 user | 16 |
|
||||
| 用户端案例 | 🟦 user | 8 |
|
||||
| 用户端设计师 | 🟦 user | 4 |
|
||||
| 用户端内容 | 🟦 user | 8 |
|
||||
| 管理端认证 | 🟧 admin | 4 |
|
||||
| 管理端案例管理 | 🟧 admin | 9 |
|
||||
| 管理端轮播管理 | 🟧 admin | 5 |
|
||||
| 管理端专题管理 | 🟧 admin | 6 |
|
||||
| 管理端分类标签 | 🟧 admin | 8 |
|
||||
| 管理端设计师管理 | 🟧 admin | 5 |
|
||||
| 管理端评论管理 | 🟧 admin | 4 |
|
||||
| 管理端用户权限 | 🟧 admin | 8 |
|
||||
| 管理端系统配置 | 🟧 admin | 2 |
|
||||
| 管理端仪表盘 | 🟧 admin | 3 |
|
||||
| 管理端日志 | 🟧 admin | 2 |
|
||||
| 通用上传 | 🟩 both | 1 |
|
||||
| **合计** | | **93** |
|
||||
|
||||
---
|
||||
|
||||
*最后更新: 2026-02-28*
|
||||
748
docs/architecture/data-model.md
Normal file
748
docs/architecture/data-model.md
Normal file
@@ -0,0 +1,748 @@
|
||||
# Data Model — MySQL 数据建模
|
||||
|
||||
> 定义数据库表结构、关系和设计约定。AI Agent 在生成 Migration 和 Model 时参考本文档。
|
||||
|
||||
---
|
||||
|
||||
## 1. 设计原则
|
||||
|
||||
- 主键统一使用 `BIGINT UNSIGNED AUTO_INCREMENT`
|
||||
- 字符集 `utf8mb4`,排序规则 `utf8mb4_unicode_ci`
|
||||
- 所有表包含 `created_at`, `updated_at`, `deleted_at` (软删除)
|
||||
- 外键字段命名 `<table_singular>_id`,必须有索引
|
||||
- 金额字段使用 `DECIMAL(10,2)`
|
||||
- 状态字段使用 `VARCHAR(20)` 或 `TINYINT`(避免 ENUM)
|
||||
- 时间字段使用 `TIMESTAMP`
|
||||
- 排序字段使用 `INT UNSIGNED DEFAULT 0`
|
||||
|
||||
## 2. 命名规范
|
||||
|
||||
### 2.1 表命名规则
|
||||
|
||||
**表名必须以所属模块名作为前缀**(snake_case),格式:`<module>_<entity_plural>`。
|
||||
|
||||
| 模块 | 前缀 | 说明 |
|
||||
|------|------|------|
|
||||
| 用户与权限 | `auth_` | 用户、角色、菜单、OAuth 等 |
|
||||
| 案例核心 | `case_` | 案例主表、图库、文件、分类等 |
|
||||
| 设计师 | `designer_` | 设计师档案、奖项、标签关联等 |
|
||||
| 运营内容 | `operation_` | 轮播图、专题、标签字典等 |
|
||||
| 用户互动 | `interaction_` | 收藏、点赞、评论、关注、订阅等 |
|
||||
| 日志 | `log_` | 登录日志、操作日志、下载日志等 |
|
||||
| 安全风控 | `security_` | 黑名单、风控事件、会话等 |
|
||||
| 系统配置 | `system_` | 系统参数配置等 |
|
||||
|
||||
> **规则说明**:
|
||||
> - 同一业务域下的所有表使用相同前缀,避免不同模块表名冲突
|
||||
> - 多对多关联表同样需要加模块前缀:`<module>_<a>_belongs_<b>`
|
||||
> - 跨模块关联的中间表,以**主体模块**的前缀命名
|
||||
|
||||
### 2.2 通用命名约定
|
||||
|
||||
| 类型 | 规范 | 示例 |
|
||||
|------|------|------|
|
||||
| 表名 | `<module>_` 前缀 + snake_case 复数 | `case_cases`, `auth_users` |
|
||||
| 字段名 | snake_case | `total_building_area` |
|
||||
| 主键 | `id` | `BIGINT UNSIGNED` |
|
||||
| 外键 | `<singular>_id` | `case_id`, `designer_id` |
|
||||
| 索引 | `idx_<table>_<cols>` | `idx_case_cases_status` |
|
||||
| 唯一索引 | `uk_<table>_<cols>` | `uk_case_cases_code` |
|
||||
| 多对多关联表 | `<module>_<a>_belongs_<b>` | `case_case_belongs_tag` |
|
||||
| 布尔字段 | `is_<adj>` | `is_featured`, `is_active` |
|
||||
| 计数缓存 | `<noun>_count` | `view_count`, `like_count` |
|
||||
|
||||
### 2.3 各模块表名对照
|
||||
|
||||
| 当前表名 | 所属模块 | 规范表名 |
|
||||
|----------|----------|----------|
|
||||
| `users` | 用户与权限 | `auth_users` |
|
||||
| `oauth_bindings` | 用户与权限 | `auth_oauth_bindings` |
|
||||
| `roles` | 用户与权限 | `auth_roles` |
|
||||
| `menus` | 用户与权限 | `auth_menus` |
|
||||
| `user_belongs_role` | 用户与权限 | `auth_user_belongs_role` |
|
||||
| `role_belongs_menu` | 用户与权限 | `auth_role_belongs_menu` |
|
||||
| `categories` | 案例核心 | `case_categories` |
|
||||
| `tags` | 运营内容 | `operation_tags` |
|
||||
| `cases` | 案例核心 | `case_cases` |
|
||||
| `case_images` | 案例核心 | `case_images`(已有前缀) |
|
||||
| `case_files` | 案例核心 | `case_files`(已有前缀) |
|
||||
| `case_belongs_tag` | 案例核心 | `case_belongs_tag`(已有前缀) |
|
||||
| `case_team_members` | 案例核心 | `case_team_members`(已有前缀) |
|
||||
| `designers` | 设计师 | `designer_profiles` |
|
||||
| `designer_awards` | 设计师 | `designer_awards`(已有前缀) |
|
||||
| `designer_belongs_tag` | 设计师 | `designer_belongs_tag`(已有前缀) |
|
||||
| `banners` | 运营内容 | `operation_banners` |
|
||||
| `topics` | 运营内容 | `operation_topics` |
|
||||
| `topic_belongs_case` | 运营内容 | `operation_topic_belongs_case` |
|
||||
| `favorites` | 用户互动 | `interaction_favorites` |
|
||||
| `likes` | 用户互动 | `interaction_likes` |
|
||||
| `comments` | 用户互动 | `interaction_comments` |
|
||||
| `follows` | 用户互动 | `interaction_follows` |
|
||||
| `newsletter_subscriptions` | 用户互动 | `interaction_newsletter_subscriptions` |
|
||||
| `user_login_logs` | 日志 | `log_user_logins` |
|
||||
| `admin_operation_logs` | 日志 | `log_admin_operations` |
|
||||
| `download_logs` | 日志 | `log_downloads` |
|
||||
| `user_sessions` | 安全风控 | `security_user_sessions` |
|
||||
| `security_risk_events` | 安全风控 | `security_risk_events`(已有前缀) |
|
||||
| `security_blacklists` | 安全风控 | `security_blacklists`(已有前缀) |
|
||||
| `system_configs` | 系统配置 | `system_configs`(已有前缀) |
|
||||
|
||||
---
|
||||
|
||||
## 3. ER 关系总览
|
||||
|
||||
```
|
||||
用户与权限
|
||||
─────────
|
||||
users ←→ user_belongs_role ←→ roles
|
||||
│ │
|
||||
└→ oauth_bindings role_belongs_menu ←→ menus
|
||||
|
||||
案例核心
|
||||
────────
|
||||
categories ←── cases ──→ case_images
|
||||
│ └──→ case_files
|
||||
│ └──→ case_belongs_tag ←── tags
|
||||
│ └──→ case_team_members ──→ designers
|
||||
│ │
|
||||
│ └→ designer_awards
|
||||
│ └→ designer_belongs_tag ←── tags
|
||||
│
|
||||
└──→ favorites ←── users
|
||||
└──→ likes ←── users
|
||||
└──→ comments ←── users
|
||||
|
||||
运营内容
|
||||
────────
|
||||
banners (独立)
|
||||
topics ←→ topic_belongs_case ←→ cases
|
||||
|
||||
会话与安全
|
||||
──────────
|
||||
users ──→ user_sessions
|
||||
users ──→ security_risk_events
|
||||
security_blacklists (独立)
|
||||
|
||||
日志与系统
|
||||
──────────
|
||||
user_login_logs
|
||||
admin_operation_logs
|
||||
download_logs
|
||||
system_configs
|
||||
newsletter_subscriptions
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 核心数据表
|
||||
|
||||
### 4.1 用户与权限域
|
||||
|
||||
#### `users` — 统一用户表
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `id` | BIGINT UNSIGNED | PK, AUTO_INCREMENT | |
|
||||
| `user_type` | VARCHAR(20) | NOT NULL, DEFAULT 'user' | user / admin |
|
||||
| `username` | VARCHAR(50) | NULL, UNIQUE | 登录账号 |
|
||||
| `phone` | VARCHAR(20) | NULL, UNIQUE | 手机号 |
|
||||
| `password` | VARCHAR(255) | NULL | bcrypt 哈希 |
|
||||
| `enterprise_user_id` | VARCHAR(100) | NULL, UNIQUE | 企业平台用户唯一标识 |
|
||||
| `source` | VARCHAR(20) | NOT NULL, DEFAULT 'local' | local / enterprise / wechat / qq |
|
||||
| `is_enterprise_linked` | TINYINT | NOT NULL, DEFAULT 0 | 是否已绑定企业账号 |
|
||||
| `nickname` | VARCHAR(50) | NULL | 显示昵称 |
|
||||
| `avatar` | VARCHAR(500) | NULL | 头像 URL |
|
||||
| `role_label` | VARCHAR(50) | NULL | 展示角色标签(如 Architect) |
|
||||
| `previous_password_hash` | VARCHAR(255) | NULL | 上次密码哈希(防重复使用) |
|
||||
| `agree_at` | TIMESTAMP | NULL | 用户同意协议时间 |
|
||||
| `agreement_version` | VARCHAR(30) | NULL | 同意时协议版本 |
|
||||
| `status` | TINYINT | NOT NULL, DEFAULT 1 | 1=启用, 0=禁用 |
|
||||
| `deactivation_requested_at` | TIMESTAMP | NULL | 注销申请时间(冷静期起始) |
|
||||
| `scheduled_deletion_at` | TIMESTAMP | NULL | 计划删除时间(冷静期结束) |
|
||||
| `last_login_at` | TIMESTAMP | NULL | |
|
||||
| `created_at` | TIMESTAMP | | |
|
||||
| `updated_at` | TIMESTAMP | | |
|
||||
| `deleted_at` | TIMESTAMP | NULL | |
|
||||
|
||||
索引:`uk_users_username`, `uk_users_phone`, `uk_users_enterprise_user_id`, `idx_users_user_type`, `idx_users_status`
|
||||
|
||||
#### `oauth_bindings` — 第三方登录绑定
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `id` | BIGINT UNSIGNED | PK | |
|
||||
| `user_id` | BIGINT UNSIGNED | FK → users | |
|
||||
| `provider` | VARCHAR(20) | NOT NULL | wechat / qq / enterprise |
|
||||
| `provider_user_id` | VARCHAR(100) | NOT NULL | 第三方平台用户 ID |
|
||||
| `access_token` | VARCHAR(500) | NULL | |
|
||||
| `refresh_token` | VARCHAR(500) | NULL | |
|
||||
| `expires_at` | TIMESTAMP | NULL | |
|
||||
| `created_at` | TIMESTAMP | | |
|
||||
| `updated_at` | TIMESTAMP | | |
|
||||
|
||||
索引:`uk_oauth_provider_uid (provider, provider_user_id)`, `idx_oauth_user_id`
|
||||
|
||||
#### `roles` — 角色表
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `id` | BIGINT UNSIGNED | PK | |
|
||||
| `name` | VARCHAR(50) | NOT NULL, UNIQUE | 角色标识:super_admin / content_ops / reviewer |
|
||||
| `display_name` | VARCHAR(50) | NOT NULL | 超级管理员 / 内容运营 / 审核员 |
|
||||
| `description` | VARCHAR(200) | NULL | |
|
||||
| `created_at` | TIMESTAMP | | |
|
||||
| `updated_at` | TIMESTAMP | | |
|
||||
|
||||
#### `menus` — 菜单/权限表
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `id` | BIGINT UNSIGNED | PK | |
|
||||
| `parent_id` | BIGINT UNSIGNED | DEFAULT 0 | 树形结构 |
|
||||
| `name` | VARCHAR(50) | NOT NULL | 权限标识 `case:create` |
|
||||
| `display_name` | VARCHAR(50) | NOT NULL | 菜单显示名 |
|
||||
| `type` | VARCHAR(10) | NOT NULL | menu / button |
|
||||
| `path` | VARCHAR(200) | NULL | 前端路由路径 |
|
||||
| `icon` | VARCHAR(50) | NULL | 图标名 |
|
||||
| `sort` | INT UNSIGNED | DEFAULT 0 | |
|
||||
| `is_visible` | TINYINT | DEFAULT 1 | |
|
||||
| `created_at` | TIMESTAMP | | |
|
||||
| `updated_at` | TIMESTAMP | | |
|
||||
|
||||
#### `user_belongs_role` — 用户-角色关联
|
||||
|
||||
| 字段 | 类型 | 约束 |
|
||||
|------|------|------|
|
||||
| `user_id` | BIGINT UNSIGNED | PK(联合), FK → users |
|
||||
| `role_id` | BIGINT UNSIGNED | PK(联合), FK → roles |
|
||||
|
||||
#### `role_belongs_menu` — 角色-菜单关联
|
||||
|
||||
| 字段 | 类型 | 约束 |
|
||||
|------|------|------|
|
||||
| `role_id` | BIGINT UNSIGNED | PK(联合), FK → roles |
|
||||
| `menu_id` | BIGINT UNSIGNED | PK(联合), FK → menus |
|
||||
|
||||
---
|
||||
|
||||
### 4.2 案例核心域
|
||||
|
||||
#### `categories` — 建筑类型分类
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `id` | BIGINT UNSIGNED | PK | |
|
||||
| `name` | VARCHAR(50) | NOT NULL, UNIQUE | 别墅 / 民宿 / 室内 / 景观 / 农村自建房 / 庭院 |
|
||||
| `slug` | VARCHAR(50) | NOT NULL, UNIQUE | villa / homestay / interior / landscape |
|
||||
| `icon` | VARCHAR(50) | NULL | |
|
||||
| `sort` | INT UNSIGNED | DEFAULT 0 | |
|
||||
| `case_count` | INT UNSIGNED | DEFAULT 0 | 缓存引用计数 |
|
||||
| `created_at` | TIMESTAMP | | |
|
||||
| `updated_at` | TIMESTAMP | | |
|
||||
|
||||
#### `tags` — 统一标签字典
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `id` | BIGINT UNSIGNED | PK | |
|
||||
| `type` | VARCHAR(20) | NOT NULL | style / feature / specialty |
|
||||
| `name` | VARCHAR(50) | NOT NULL | 现代 / 落地窗 / 参数化设计 |
|
||||
| `sort` | INT UNSIGNED | DEFAULT 0 | |
|
||||
| `reference_count` | INT UNSIGNED | DEFAULT 0 | 被引用次数 |
|
||||
| `created_at` | TIMESTAMP | | |
|
||||
| `updated_at` | TIMESTAMP | | |
|
||||
|
||||
索引:`uk_tags_type_name (type, name)`, `idx_tags_type`
|
||||
|
||||
#### `cases` — 案例主表
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `id` | BIGINT UNSIGNED | PK | |
|
||||
| `category_id` | BIGINT UNSIGNED | FK → categories | 建筑类型 |
|
||||
| `title` | VARCHAR(200) | NOT NULL | 项目名称 |
|
||||
| `code` | VARCHAR(30) | NOT NULL, UNIQUE | 项目编号 P-2024-8839 |
|
||||
| `cover_image` | VARCHAR(500) | NULL | 封面图 URL |
|
||||
| `status` | VARCHAR(20) | NOT NULL, DEFAULT 'draft' | draft / pending / published / archived |
|
||||
| `is_featured` | TINYINT | DEFAULT 0 | 是否精选 |
|
||||
| `featured_sort` | INT UNSIGNED | DEFAULT 0 | 精选排序 |
|
||||
| — **户型布局** — | | | |
|
||||
| `layout` | VARCHAR(50) | NULL | 3室2厅3卫 |
|
||||
| `floor_height` | VARCHAR(50) | NULL | 3.6/3.3/3.3m |
|
||||
| — **用地条件** — | | | |
|
||||
| `site_width` | VARCHAR(50) | NULL | 面宽 ≥ 10.5m |
|
||||
| `site_depth` | VARCHAR(50) | NULL | 进深 ≥ 12.2m |
|
||||
| `site_area` | DECIMAL(10,2) | NULL | 占地面积 m² |
|
||||
| `lighting_restriction` | VARCHAR(100) | NULL | 采光限制 |
|
||||
| `site_shape` | VARCHAR(50) | NULL | 用地形状 |
|
||||
| — **规模造价** — | | | |
|
||||
| `floors_above` | TINYINT UNSIGNED | NULL | 地上层数 |
|
||||
| `floors_below` | TINYINT UNSIGNED | NULL | 地下层数 |
|
||||
| `cost_min` | DECIMAL(12,2) | NULL | 造价预估下限(万元) |
|
||||
| `cost_max` | DECIMAL(12,2) | NULL | 造价预估上限(万元) |
|
||||
| `total_building_area` | DECIMAL(10,2) | NULL | 建筑总面积 m² |
|
||||
| `bedroom_count` | TINYINT UNSIGNED | NULL | 卧室数量 |
|
||||
| `bedroom_note` | VARCHAR(100) | NULL | 含1主卧套房 |
|
||||
| — **平面功能** — | | | |
|
||||
| `stair_type` | VARCHAR(100) | NULL | 楼梯类型 |
|
||||
| `special_space` | VARCHAR(200) | NULL | 特色空间 / 农村特色 |
|
||||
| `bedroom_config` | VARCHAR(200) | NULL | 卧室配置 |
|
||||
| `leisure_space` | VARCHAR(200) | NULL | 休闲空间 |
|
||||
| `kitchen_dining` | VARCHAR(200) | NULL | 厨房餐厅 |
|
||||
| `bathroom_config` | VARCHAR(100) | NULL | 卫生间配置 |
|
||||
| — **外观风格** — | | | |
|
||||
| `architecture_style` | VARCHAR(100) | NULL | 建筑风格 |
|
||||
| `roof_type` | VARCHAR(100) | NULL | 屋顶形式 |
|
||||
| `facade_material` | VARCHAR(200) | NULL | 外立面材料 |
|
||||
| — **结构与性能** — | | | |
|
||||
| `structure_type` | VARCHAR(100) | NULL | 结构类型 |
|
||||
| `foundation_type` | VARCHAR(100) | NULL | 基础类型 |
|
||||
| `layout_logic` | VARCHAR(200) | NULL | 户型逻辑 |
|
||||
| `wall_thickness` | VARCHAR(100) | NULL | 墙体厚度 |
|
||||
| `seismic_rating` | VARCHAR(100) | NULL | 抗震设防 |
|
||||
| `insulation_type` | VARCHAR(100) | NULL | 保温形式 |
|
||||
| `roof_structure` | VARCHAR(200) | NULL | 屋面构造 |
|
||||
| — **设计理念** — | | | |
|
||||
| `design_concept` | TEXT | NULL | 设计理念富文本 |
|
||||
| `concept_style` | VARCHAR(100) | NULL | 风格提炼 |
|
||||
| `concept_material` | VARCHAR(100) | NULL | 材质提炼 |
|
||||
| `concept_target` | VARCHAR(100) | NULL | 受众提炼 |
|
||||
| — **分类特有扩展** — | | | |
|
||||
| `meta` | JSON | NULL | 分类特有参数(景观面积 / 客房数 / 主材等) |
|
||||
| — **统计计数** — | | | |
|
||||
| `view_count` | INT UNSIGNED | DEFAULT 0 | |
|
||||
| `like_count` | INT UNSIGNED | DEFAULT 0 | |
|
||||
| `favorite_count` | INT UNSIGNED | DEFAULT 0 | |
|
||||
| `download_count` | INT UNSIGNED | DEFAULT 0 | |
|
||||
| `comment_count` | INT UNSIGNED | DEFAULT 0 | |
|
||||
| — **时间** — | | | |
|
||||
| `published_at` | TIMESTAMP | NULL | 发布时间 |
|
||||
| `created_at` | TIMESTAMP | | |
|
||||
| `updated_at` | TIMESTAMP | | |
|
||||
| `deleted_at` | TIMESTAMP | NULL | |
|
||||
|
||||
索引:`uk_cases_code`, `idx_cases_category_id`, `idx_cases_status`, `idx_cases_is_featured`, `idx_cases_status_created (status, created_at)`, `idx_cases_status_featured (status, is_featured, featured_sort)`
|
||||
|
||||
> `meta` JSON 用于存储不同分类的特有参数。例如:
|
||||
> - 景观类案例:`{"landscape_area": 270, "main_vegetation": "黑松/苔藓", "paving_material": "花岗岩/白砂"}`
|
||||
> - 民宿类案例:`{"room_count": 12, "room_note": "12间套房"}`
|
||||
> - 室内类案例:`{"main_material": "微水泥/钢构"}`
|
||||
> - 商业类案例:`{"building_height": "120m", "function_layout": "办公/商业"}`
|
||||
|
||||
#### `case_images` — 案例图库
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `id` | BIGINT UNSIGNED | PK | |
|
||||
| `case_id` | BIGINT UNSIGNED | FK → cases | |
|
||||
| `type` | VARCHAR(20) | NOT NULL | effect / floor_plan / elevation |
|
||||
| `url` | VARCHAR(500) | NOT NULL | 图片 URL |
|
||||
| `thumbnail_url` | VARCHAR(500) | NULL | 缩略图 URL |
|
||||
| `sort` | INT UNSIGNED | DEFAULT 0 | |
|
||||
| `created_at` | TIMESTAMP | | |
|
||||
| `updated_at` | TIMESTAMP | | |
|
||||
|
||||
索引:`idx_case_images_case_type (case_id, type)`
|
||||
|
||||
#### `case_files` — 案例文件资产
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `id` | BIGINT UNSIGNED | PK | |
|
||||
| `case_id` | BIGINT UNSIGNED | FK → cases | |
|
||||
| `stage` | VARCHAR(20) | NOT NULL | floor_plan / exterior / construction / structure / interior / courtyard |
|
||||
| `file_name` | VARCHAR(200) | NOT NULL | 原始文件名 |
|
||||
| `file_path` | VARCHAR(500) | NOT NULL | 存储路径 / OSS key |
|
||||
| `file_size` | BIGINT UNSIGNED | NOT NULL | 字节数 |
|
||||
| `file_ext` | VARCHAR(20) | NOT NULL | dwg / pdf / rvt / jpg / png / zip |
|
||||
| `mime_type` | VARCHAR(100) | NULL | |
|
||||
| `uploader_id` | BIGINT UNSIGNED | FK → users | 上传者 |
|
||||
| `sort` | INT UNSIGNED | DEFAULT 0 | |
|
||||
| `created_at` | TIMESTAMP | | |
|
||||
| `updated_at` | TIMESTAMP | | |
|
||||
|
||||
索引:`idx_case_files_case_stage (case_id, stage)`
|
||||
|
||||
> `stage` 枚举值对应 PRD F5.1 的 6 个设计阶段:
|
||||
> - `floor_plan` — 平面阶段
|
||||
> - `exterior` — 外观阶段
|
||||
> - `construction` — 施工图阶段
|
||||
> - `structure` — 结构阶段
|
||||
> - `interior` — 室内阶段
|
||||
> - `courtyard` — 庭院阶段
|
||||
|
||||
#### `case_belongs_tag` — 案例-标签关联
|
||||
|
||||
| 字段 | 类型 | 约束 |
|
||||
|------|------|------|
|
||||
| `case_id` | BIGINT UNSIGNED | PK(联合), FK → cases |
|
||||
| `tag_id` | BIGINT UNSIGNED | PK(联合), FK → tags |
|
||||
|
||||
#### `case_team_members` — 案例主创团队
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `id` | BIGINT UNSIGNED | PK | |
|
||||
| `case_id` | BIGINT UNSIGNED | FK → cases | |
|
||||
| `designer_id` | BIGINT UNSIGNED | FK → designers | |
|
||||
| `role` | VARCHAR(30) | NOT NULL | scheme / structure / mep (方案/结构/水电) |
|
||||
| `is_lead` | TINYINT | DEFAULT 0 | 是否主创 |
|
||||
| `sort` | INT UNSIGNED | DEFAULT 0 | |
|
||||
| `created_at` | TIMESTAMP | | |
|
||||
|
||||
索引:`uk_case_team_case_designer_role (case_id, designer_id, role)`, `idx_case_team_designer_id`
|
||||
|
||||
---
|
||||
|
||||
### 4.3 设计师域
|
||||
|
||||
#### `designers` — 设计师档案
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `id` | BIGINT UNSIGNED | PK | |
|
||||
| `name_cn` | VARCHAR(50) | NOT NULL | 中文姓名 |
|
||||
| `name_en` | VARCHAR(100) | NULL | 英文姓名 |
|
||||
| `title` | VARCHAR(50) | NULL | 职位:方案主创设计师 |
|
||||
| `title_badge` | VARCHAR(50) | NULL | 职位徽章:Lead Architect |
|
||||
| `company` | VARCHAR(100) | NULL | 所属机构 |
|
||||
| `city` | VARCHAR(50) | NULL | 所在城市 |
|
||||
| `portrait` | VARCHAR(500) | NULL | 个人写真 URL |
|
||||
| `portrait_caption` | VARCHAR(100) | NULL | STUDIO PORTRAIT © 2023 |
|
||||
| `years_of_experience` | TINYINT UNSIGNED | NULL | 从业年限 |
|
||||
| `project_count` | INT UNSIGNED | DEFAULT 0 | 完成项目数 |
|
||||
| `design_philosophy_quote` | TEXT | NULL | 设计理念引用语 |
|
||||
| `design_philosophy` | TEXT | NULL | 设计理念详述(富文本) |
|
||||
| `follower_count` | INT UNSIGNED | DEFAULT 0 | 关注者数量 |
|
||||
| `view_count` | INT UNSIGNED | DEFAULT 0 | 主页浏览量 |
|
||||
| `is_active` | TINYINT | DEFAULT 1 | 是否公开展示 |
|
||||
| `created_at` | TIMESTAMP | | |
|
||||
| `updated_at` | TIMESTAMP | | |
|
||||
| `deleted_at` | TIMESTAMP | NULL | |
|
||||
|
||||
索引:`idx_designers_is_active`
|
||||
|
||||
#### `designer_awards` — 设计师荣誉奖项
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `id` | BIGINT UNSIGNED | PK | |
|
||||
| `designer_id` | BIGINT UNSIGNED | FK → designers | |
|
||||
| `year` | SMALLINT UNSIGNED | NOT NULL | 获奖年份 |
|
||||
| `title` | VARCHAR(200) | NOT NULL | 红点设计大奖 Red Dot Award |
|
||||
| `description` | VARCHAR(300) | NULL | 最佳室内设计类 - The Cloud Villa |
|
||||
| `sort` | INT UNSIGNED | DEFAULT 0 | |
|
||||
| `created_at` | TIMESTAMP | | |
|
||||
| `updated_at` | TIMESTAMP | | |
|
||||
|
||||
索引:`idx_awards_designer_year (designer_id, year DESC)`
|
||||
|
||||
#### `designer_belongs_tag` — 设计师-专长标签
|
||||
|
||||
| 字段 | 类型 | 约束 |
|
||||
|------|------|------|
|
||||
| `designer_id` | BIGINT UNSIGNED | PK(联合), FK → designers |
|
||||
| `tag_id` | BIGINT UNSIGNED | PK(联合), FK → tags (type=specialty) |
|
||||
|
||||
---
|
||||
|
||||
### 4.4 运营内容域
|
||||
|
||||
#### `banners` — 首页轮播
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `id` | BIGINT UNSIGNED | PK | |
|
||||
| `title` | VARCHAR(200) | NOT NULL | 大标题 |
|
||||
| `description` | TEXT | NULL | 描述摘要 |
|
||||
| `image` | VARCHAR(500) | NOT NULL | 背景大图 URL |
|
||||
| `label` | VARCHAR(50) | NULL | 标签文字:精选项目 |
|
||||
| `link_type` | VARCHAR(20) | NOT NULL, DEFAULT 'case' | case / topic / external |
|
||||
| `link_url` | VARCHAR(500) | NOT NULL | 跳转链接 |
|
||||
| `sort` | INT UNSIGNED | DEFAULT 0 | |
|
||||
| `is_active` | TINYINT | DEFAULT 1 | 启用/停用 |
|
||||
| `published_at` | TIMESTAMP | NULL | 展示日期 |
|
||||
| `created_at` | TIMESTAMP | | |
|
||||
| `updated_at` | TIMESTAMP | | |
|
||||
|
||||
索引:`idx_banners_active_sort (is_active, sort)`
|
||||
|
||||
#### `topics` — 专题合集
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `id` | BIGINT UNSIGNED | PK | |
|
||||
| `title` | VARCHAR(200) | NOT NULL | 专题标题 |
|
||||
| `cover_image` | VARCHAR(500) | NULL | 封面图 |
|
||||
| `description` | TEXT | NULL | 富文本描述 |
|
||||
| `status` | VARCHAR(20) | NOT NULL, DEFAULT 'draft' | draft / published |
|
||||
| `case_count` | INT UNSIGNED | DEFAULT 0 | 关联案例数 |
|
||||
| `created_at` | TIMESTAMP | | |
|
||||
| `updated_at` | TIMESTAMP | | |
|
||||
| `deleted_at` | TIMESTAMP | NULL | |
|
||||
|
||||
#### `topic_belongs_case` — 专题-案例关联
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `topic_id` | BIGINT UNSIGNED | PK(联合), FK → topics | |
|
||||
| `case_id` | BIGINT UNSIGNED | PK(联合), FK → cases | |
|
||||
| `sort` | INT UNSIGNED | DEFAULT 0 | 专题内排序 |
|
||||
|
||||
---
|
||||
|
||||
### 4.5 用户互动域
|
||||
|
||||
#### `favorites` — 收藏
|
||||
|
||||
| 字段 | 类型 | 约束 |
|
||||
|------|------|------|
|
||||
| `id` | BIGINT UNSIGNED | PK |
|
||||
| `user_id` | BIGINT UNSIGNED | FK → users |
|
||||
| `case_id` | BIGINT UNSIGNED | FK → cases |
|
||||
| `created_at` | TIMESTAMP | |
|
||||
|
||||
索引:`uk_favorites_user_case (user_id, case_id)`, `idx_favorites_case_id`
|
||||
|
||||
#### `likes` — 点赞
|
||||
|
||||
| 字段 | 类型 | 约束 |
|
||||
|------|------|------|
|
||||
| `id` | BIGINT UNSIGNED | PK |
|
||||
| `user_id` | BIGINT UNSIGNED | FK → users |
|
||||
| `case_id` | BIGINT UNSIGNED | FK → cases |
|
||||
| `created_at` | TIMESTAMP | |
|
||||
|
||||
索引:`uk_likes_user_case (user_id, case_id)`, `idx_likes_case_id`
|
||||
|
||||
#### `comments` — 评论
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `id` | BIGINT UNSIGNED | PK | |
|
||||
| `case_id` | BIGINT UNSIGNED | FK → cases | |
|
||||
| `user_id` | BIGINT UNSIGNED | FK → users | |
|
||||
| `parent_id` | BIGINT UNSIGNED | NULL, FK → comments | 回复嵌套 |
|
||||
| `content` | TEXT | NOT NULL | 评论内容 |
|
||||
| `status` | VARCHAR(20) | DEFAULT 'pending' | pending / approved / rejected |
|
||||
| `created_at` | TIMESTAMP | | |
|
||||
| `updated_at` | TIMESTAMP | | |
|
||||
| `deleted_at` | TIMESTAMP | NULL | |
|
||||
|
||||
索引:`idx_comments_case_status (case_id, status)`, `idx_comments_user_id`, `idx_comments_parent_id`
|
||||
|
||||
#### `follows` — 关注设计师
|
||||
|
||||
| 字段 | 类型 | 约束 |
|
||||
|------|------|------|
|
||||
| `id` | BIGINT UNSIGNED | PK |
|
||||
| `user_id` | BIGINT UNSIGNED | FK → users |
|
||||
| `designer_id` | BIGINT UNSIGNED | FK → designers |
|
||||
| `created_at` | TIMESTAMP | |
|
||||
|
||||
索引:`uk_follows_user_designer (user_id, designer_id)`, `idx_follows_designer_id`
|
||||
|
||||
#### `newsletter_subscriptions` — 邮箱订阅
|
||||
|
||||
| 字段 | 类型 | 约束 |
|
||||
|------|------|------|
|
||||
| `id` | BIGINT UNSIGNED | PK |
|
||||
| `email` | VARCHAR(200) | NOT NULL, UNIQUE |
|
||||
| `created_at` | TIMESTAMP | |
|
||||
|
||||
---
|
||||
|
||||
### 4.6 日志与系统域
|
||||
|
||||
#### `user_login_logs` — 登录日志
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `id` | BIGINT UNSIGNED | PK | |
|
||||
| `user_id` | BIGINT UNSIGNED | FK → users | |
|
||||
| `login_type` | VARCHAR(20) | NOT NULL | password / sms / qr / wechat / qq / enterprise_sso |
|
||||
| `ip` | VARCHAR(45) | NULL | |
|
||||
| `login_location` | VARCHAR(100) | NULL | 登录地理位置(由 IP 库反查填充) |
|
||||
| `device_fingerprint` | VARCHAR(128) | NULL | 设备指纹 |
|
||||
| `risk_level` | VARCHAR(10) | NULL | L1 / L2 / L3 / L4 |
|
||||
| `risk_reason` | VARCHAR(255) | NULL | 命中策略摘要 |
|
||||
| `result` | VARCHAR(20) | NOT NULL, DEFAULT 'success' | success / failed / blocked |
|
||||
| `user_agent` | VARCHAR(500) | NULL | |
|
||||
| `created_at` | TIMESTAMP | | |
|
||||
|
||||
索引:`idx_login_logs_user_created (user_id, created_at)`, `idx_login_logs_ip_created (ip, created_at)`
|
||||
|
||||
#### `user_sessions` — 活跃会话
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `id` | BIGINT UNSIGNED | PK | |
|
||||
| `user_id` | BIGINT UNSIGNED | FK → users | |
|
||||
| `session_token` | VARCHAR(255) | NOT NULL, UNIQUE | Refresh Token 标识(哈希值) |
|
||||
| `device_name` | VARCHAR(100) | NULL | 设备名称(如 Chrome on macOS) |
|
||||
| `device_fingerprint` | VARCHAR(128) | NULL | 设备指纹 |
|
||||
| `ip` | VARCHAR(45) | NULL | 登录 IP |
|
||||
| `login_location` | VARCHAR(100) | NULL | 登录地理位置 |
|
||||
| `is_current` | TINYINT | NOT NULL, DEFAULT 0 | 是否为当前请求会话 |
|
||||
| `last_active_at` | TIMESTAMP | NULL | 最近活跃时间 |
|
||||
| `expires_at` | TIMESTAMP | NOT NULL | 会话过期时间 |
|
||||
| `revoked_at` | TIMESTAMP | NULL | 被踢出/注销时间(非空即失效) |
|
||||
| `created_at` | TIMESTAMP | | |
|
||||
|
||||
索引:`idx_sessions_user_active (user_id, revoked_at, expires_at)`, `uk_sessions_token (session_token)`
|
||||
|
||||
> 活跃会话表用于 F1.9 多端会话管理。创建会话时写入,Token 刷新时更新 `last_active_at`,退出/踢出时设置 `revoked_at`。定期清理过期记录。
|
||||
|
||||
#### `security_risk_events` — 风控事件日志
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `id` | BIGINT UNSIGNED | PK | |
|
||||
| `user_id` | BIGINT UNSIGNED | NULL, FK → users | 可为空(未登录攻击流量) |
|
||||
| `event_type` | VARCHAR(30) | NOT NULL | login / sms_send / register / reset_password / sso_callback |
|
||||
| `risk_level` | VARCHAR(10) | NOT NULL | L1 / L2 / L3 / L4 |
|
||||
| `action` | VARCHAR(30) | NOT NULL | captcha_upgrade / rate_limit / temporary_block / blacklist |
|
||||
| `ip` | VARCHAR(45) | NULL | |
|
||||
| `device_fingerprint` | VARCHAR(128) | NULL | |
|
||||
| `user_agent` | VARCHAR(500) | NULL | |
|
||||
| `payload` | JSON | NULL | 事件上下文 |
|
||||
| `created_at` | TIMESTAMP | | |
|
||||
|
||||
索引:`idx_risk_events_user_created (user_id, created_at)`, `idx_risk_events_level_created (risk_level, created_at)`, `idx_risk_events_ip_created (ip, created_at)`
|
||||
|
||||
> 风控事件日志不可编辑、不可删除,无 `updated_at` 和 `deleted_at`。
|
||||
|
||||
#### `security_blacklists` — 安全黑名单
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `id` | BIGINT UNSIGNED | PK | |
|
||||
| `target_type` | VARCHAR(20) | NOT NULL | ip / device / account |
|
||||
| `target_value` | VARCHAR(255) | NOT NULL | IP、设备指纹或账号标识 |
|
||||
| `reason` | VARCHAR(255) | NULL | 拉黑原因 |
|
||||
| `source` | VARCHAR(20) | NOT NULL, DEFAULT 'system' | system / manual |
|
||||
| `status` | VARCHAR(20) | NOT NULL, DEFAULT 'active' | active / released / expired |
|
||||
| `expire_at` | TIMESTAMP | NULL | 为空表示永久 |
|
||||
| `created_by` | BIGINT UNSIGNED | NULL, FK → users | 手动操作人(系统自动为空) |
|
||||
| `created_at` | TIMESTAMP | | |
|
||||
| `updated_at` | TIMESTAMP | | |
|
||||
|
||||
索引:`uk_blacklists_target (target_type, target_value)`, `idx_blacklists_status_expire (status, expire_at)`
|
||||
|
||||
#### `admin_operation_logs` — 管理端操作日志
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `id` | BIGINT UNSIGNED | PK | |
|
||||
| `user_id` | BIGINT UNSIGNED | FK → users | 操作人 |
|
||||
| `action` | VARCHAR(30) | NOT NULL | create / update / delete / status_change |
|
||||
| `resource_type` | VARCHAR(50) | NOT NULL | case / banner / topic / designer / comment |
|
||||
| `resource_id` | BIGINT UNSIGNED | NOT NULL | 操作对象 ID |
|
||||
| `before_value` | JSON | NULL | 变更前值 |
|
||||
| `after_value` | JSON | NULL | 变更后值 |
|
||||
| `ip` | VARCHAR(45) | NULL | |
|
||||
| `created_at` | TIMESTAMP | | |
|
||||
|
||||
索引:`idx_op_logs_user_created (user_id, created_at)`, `idx_op_logs_resource (resource_type, resource_id)`
|
||||
|
||||
> 操作日志不可编辑、不可删除,无 `updated_at` 和 `deleted_at`。
|
||||
|
||||
#### `download_logs` — 文件下载日志
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `id` | BIGINT UNSIGNED | PK | |
|
||||
| `user_id` | BIGINT UNSIGNED | FK → users | |
|
||||
| `case_id` | BIGINT UNSIGNED | FK → cases | |
|
||||
| `case_file_id` | BIGINT UNSIGNED | FK → case_files | |
|
||||
| `ip` | VARCHAR(45) | NULL | |
|
||||
| `created_at` | TIMESTAMP | | |
|
||||
|
||||
索引:`idx_dl_logs_user_created (user_id, created_at)`, `idx_dl_logs_case_id`
|
||||
|
||||
#### `system_configs` — 系统配置
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `id` | BIGINT UNSIGNED | PK | |
|
||||
| `group` | VARCHAR(50) | NOT NULL | site / seo / upload / comment / watermark / security |
|
||||
| `key` | VARCHAR(100) | NOT NULL | |
|
||||
| `value` | TEXT | NULL | |
|
||||
| `created_at` | TIMESTAMP | | |
|
||||
| `updated_at` | TIMESTAMP | | |
|
||||
|
||||
索引:`uk_configs_group_key (group, key)`
|
||||
|
||||
---
|
||||
|
||||
## 5. 索引策略
|
||||
|
||||
### 必须索引
|
||||
- 所有外键字段
|
||||
- `status` 字段
|
||||
- `created_at` 字段
|
||||
- 唯一业务标识(`cases.code`、`tags.type+name`、`users.phone`)
|
||||
|
||||
### 核心复合索引
|
||||
```sql
|
||||
-- 案例列表查询(分类 + 状态 + 时间)
|
||||
idx_cases_category_status_created (category_id, status, created_at)
|
||||
|
||||
-- 案例精选排序
|
||||
idx_cases_featured_sort (status, is_featured, featured_sort)
|
||||
|
||||
-- 文件按阶段查询
|
||||
idx_case_files_case_stage (case_id, stage)
|
||||
|
||||
-- 评论列表
|
||||
idx_comments_case_status (case_id, status, created_at)
|
||||
```
|
||||
|
||||
### 索引限制
|
||||
- 单表索引不超过 6 个
|
||||
- 避免冗余索引
|
||||
- 定期检查未使用的索引
|
||||
|
||||
---
|
||||
|
||||
## 6. 百万级数据表设计
|
||||
|
||||
### 分页优化
|
||||
```sql
|
||||
-- 游标分页(案例列表推荐使用)
|
||||
SELECT * FROM cases WHERE status = 'published' AND id > :last_id ORDER BY id DESC LIMIT 20;
|
||||
```
|
||||
|
||||
### 大表 COUNT 优化
|
||||
```sql
|
||||
-- 使用 categories.case_count / tags.reference_count 缓存计数
|
||||
-- 使用 cases.view_count / like_count / favorite_count 避免 COUNT JOIN
|
||||
```
|
||||
|
||||
### 分区策略(日志表)
|
||||
```sql
|
||||
-- 管理操作日志
|
||||
ALTER TABLE admin_operation_logs PARTITION BY RANGE (YEAR(created_at) * 100 + MONTH(created_at)) (
|
||||
PARTITION p202601 VALUES LESS THAN (202602),
|
||||
PARTITION p202602 VALUES LESS THAN (202603),
|
||||
PARTITION pmax VALUES LESS THAN MAXVALUE
|
||||
);
|
||||
|
||||
-- 用户登录日志(数据量最大,优先分区)
|
||||
ALTER TABLE user_login_logs PARTITION BY RANGE (YEAR(created_at) * 100 + MONTH(created_at)) (
|
||||
PARTITION p202601 VALUES LESS THAN (202602),
|
||||
PARTITION p202602 VALUES LESS THAN (202603),
|
||||
PARTITION pmax VALUES LESS THAN MAXVALUE
|
||||
);
|
||||
|
||||
-- 风控事件日志
|
||||
ALTER TABLE security_risk_events PARTITION BY RANGE (YEAR(created_at) * 100 + MONTH(created_at)) (
|
||||
PARTITION p202601 VALUES LESS THAN (202602),
|
||||
PARTITION p202602 VALUES LESS THAN (202603),
|
||||
PARTITION pmax VALUES LESS THAN MAXVALUE
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
*最后更新: 2026-02-28*
|
||||
76
docs/architecture/decisions/_template.md
Normal file
76
docs/architecture/decisions/_template.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# ADR-XXX: [决策标题]
|
||||
|
||||
> Architecture Decision Record (架构决策记录)
|
||||
|
||||
## 状态
|
||||
|
||||
**[提议中 | 已接受 | 已废弃 | 已取代 → ADR-YYY]**
|
||||
|
||||
## 日期
|
||||
|
||||
YYYY-MM-DD
|
||||
|
||||
## 上下文
|
||||
|
||||
描述促使此决策的背景、问题或需求。
|
||||
|
||||
**问题陈述**:
|
||||
我们需要解决 [什么问题]...
|
||||
|
||||
**约束条件**:
|
||||
- 约束1
|
||||
- 约束2
|
||||
|
||||
## 决策
|
||||
|
||||
我们决定采用 [方案]。
|
||||
|
||||
**选定方案的详细描述**:
|
||||
...
|
||||
|
||||
## 考虑的备选方案
|
||||
|
||||
### 方案 A: [名称]
|
||||
**描述**: ...
|
||||
**优点**:
|
||||
- 优点1
|
||||
- 优点2
|
||||
|
||||
**缺点**:
|
||||
- 缺点1
|
||||
- 缺点2
|
||||
|
||||
### 方案 B: [名称]
|
||||
**描述**: ...
|
||||
**优点**:
|
||||
- 优点1
|
||||
|
||||
**缺点**:
|
||||
- 缺点1
|
||||
|
||||
## 为什么选择此方案
|
||||
|
||||
解释选择该方案而非其他方案的理由。
|
||||
|
||||
## 影响
|
||||
|
||||
### 正面影响
|
||||
- 影响1
|
||||
- 影响2
|
||||
|
||||
### 负面影响/权衡
|
||||
- 权衡1
|
||||
|
||||
### 需要的后续行动
|
||||
- [ ] 行动1
|
||||
- [ ] 行动2
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [系统架构](../system-design.md)
|
||||
- [相关 ADR](./xxx.md)
|
||||
|
||||
---
|
||||
|
||||
*记录人: [姓名]*
|
||||
*审核人: [姓名]*
|
||||
128
docs/architecture/frontend-strategy.md
Normal file
128
docs/architecture/frontend-strategy.md
Normal file
@@ -0,0 +1,128 @@
|
||||
# 🖥️ 双前端架构策略
|
||||
|
||||
> AI Agent 在生成前端代码时必须先阅读本文档,明确目标前端的职责边界、技术约束和设计原则。
|
||||
|
||||
---
|
||||
|
||||
## 1. 整体架构
|
||||
|
||||
本项目采用「一后端 + 双前端 + 共享层」架构:
|
||||
|
||||
```
|
||||
vibe-cursor-pro/(Cursor 工作区)
|
||||
├── Case-Database-Backend/ ← PHP Hyperf + Swoole 后端(统一 API 服务)
|
||||
├── Case-Database-Frontend-user/ ← Vue 3 用户端(面向终端用户)
|
||||
├── Case-Database-Frontend-admin/ ← Vue 3 管理端(面向运营/管理人员)
|
||||
└── Case-Database-Frontend-shared/ ← 共享类型定义、工具函数、API 契约常量
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 前端职责边界
|
||||
|
||||
### Case-Database-Frontend-user/(用户端)
|
||||
|
||||
| 维度 | 说明 |
|
||||
|---|---|
|
||||
| **目标用户** | 普通终端用户(公开访问 + 登录用户) |
|
||||
| **核心体验** | 性能优先、流畅交互、移动端友好 |
|
||||
| **设计风格** | 品牌化、轻量、视觉吸引力强 |
|
||||
| **页面规模** | 中小型页面,单页功能聚焦 |
|
||||
| **权限模型** | 简单(登录/未登录、会员等级) |
|
||||
| **SEO 需求** | 有(落地页、详情页考虑 SSG/SSR) |
|
||||
| **API 前缀** | `/api/`(用户端接口) |
|
||||
|
||||
**典型页面**:首页、商品详情、购物车、个人中心、订单查询
|
||||
|
||||
### Case-Database-Frontend-admin/(管理端)
|
||||
|
||||
| 维度 | 说明 |
|
||||
|---|---|
|
||||
| **目标用户** | 内部运营人员、管理员 |
|
||||
| **核心体验** | 功能完整、信息密度高、操作高效 |
|
||||
| **设计风格** | 专业、实用、Element Plus 标准组件优先(仅管理端) |
|
||||
| **页面规模** | 复杂页面(多 Tab、嵌套表单、数据大表格) |
|
||||
| **权限模型** | 精细(RBAC:角色、菜单、按钮级权限) |
|
||||
| **SEO 需求** | 无(内部系统,登录后访问) |
|
||||
| **API 前缀** | `/admin/`(管理端接口) |
|
||||
|
||||
**典型页面**:数据看板、订单管理、用户管理、权限配置、系统设置
|
||||
|
||||
---
|
||||
|
||||
## 3. 共享层(Case-Database-Frontend-shared/)
|
||||
|
||||
仅包含**纯 TypeScript**内容(配合 JSDoc 类型注释),不引入任何 UI 框架:
|
||||
|
||||
```
|
||||
Case-Database-Frontend-shared/
|
||||
├── constants/ ← 业务枚举(订单状态、权限码等)
|
||||
├── utils/ ← 纯函数工具(日期格式化、金额计算等)
|
||||
└── api-schema/ ← API 请求/响应的 JSDoc 类型定义
|
||||
```
|
||||
|
||||
> **规则**:Case-Database-Frontend-shared/ 中的代码必须可被两个前端同时使用,不得包含平台特定代码。
|
||||
|
||||
---
|
||||
|
||||
## 4. 技术差异对比
|
||||
|
||||
| 技术点 | Case-Database-Frontend-user/ | Case-Database-Frontend-admin/ |
|
||||
|---|---|---|
|
||||
| **UI 框架** | 自定义组件 + Tailwind | Element Plus(优先使用标准组件) |
|
||||
| **响应式** | 移动优先(xs → xl) | 桌面优先(≥ 1280px 为主) |
|
||||
| **路由** | Vue Router(History 模式) | Vue Router(History 模式 + 权限守卫) |
|
||||
| **状态管理** | Pinia(轻量 Store) | Pinia(含权限 Store、菜单 Store) |
|
||||
| **打包优化** | 激进代码分割、图片优化、SSG 评估 | 按需分割(菜单级懒加载) |
|
||||
| **错误处理** | 用户友好提示(Toast) | 详细错误码 + 日志上报 |
|
||||
| **主题** | 品牌色(见 ui-specs-user.md) | 专业蓝灰(见 ui-specs-admin.md) |
|
||||
|
||||
---
|
||||
|
||||
## 5. AI Agent 工作约定
|
||||
|
||||
### 目录前缀约定
|
||||
|
||||
**每次前端相关任务,必须在 prompt 中明确指定目标目录**:
|
||||
|
||||
```
|
||||
✅ 正确:在 Case-Database-Frontend-user/ 中创建商品详情页
|
||||
✅ 正确:在 Case-Database-Frontend-admin/ 中创建订单管理页
|
||||
❌ 错误:创建商品详情页(未指定前端)
|
||||
```
|
||||
|
||||
### 设计原则差异
|
||||
|
||||
当 Agent 在 `Case-Database-Frontend-user/` 工作时:
|
||||
- 移动端优先(先写 xs 断点,再扩展到 lg)
|
||||
- 组件必须考虑骨架屏 / 懒加载
|
||||
- 图片必须有 alt 属性、考虑 WebP 格式
|
||||
- 交互反馈必须流畅(避免页面跳动)
|
||||
|
||||
当 Agent 在 `Case-Database-Frontend-admin/` 工作时:
|
||||
- 桌面端优先(以 1280px 为基准设计)
|
||||
- 优先使用 Element Plus 标准组件(`el-table`、`el-form`、`el-dialog` 等)
|
||||
- 页面操作必须有权限守卫(`v-permission` 指令 或 `hasPermission()` 检查)
|
||||
- 数据操作必须有二次确认(删除、批量操作等危险操作)
|
||||
|
||||
### 共享代码优先
|
||||
|
||||
在生成 API 调用代码时:
|
||||
1. 先检查 `Case-Database-Frontend-shared/constants/` 是否已有对应枚举或常量
|
||||
2. 先检查 `Case-Database-Frontend-shared/api-schema/` 是否已有接口契约
|
||||
3. 有则复用,无则在 Case-Database-Frontend-shared/ 中新建后再引用
|
||||
|
||||
---
|
||||
|
||||
## 6. 部署架构
|
||||
|
||||
```
|
||||
用户端: https://www.example.com → Nginx → Case-Database-Frontend-user/dist/
|
||||
管理端: https://admin.example.com → Nginx → Case-Database-Frontend-admin/dist/
|
||||
API: https://api.example.com → Nginx → Hyperf (9501)
|
||||
WebSocket: wss://api.example.com/ws → Nginx → Swoole (9502)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
*最后更新: 2026-02-26*
|
||||
133
docs/architecture/system-design.md
Normal file
133
docs/architecture/system-design.md
Normal file
@@ -0,0 +1,133 @@
|
||||
# 🏗️ System Design — 百万级并发企业数字化平台
|
||||
|
||||
> 填写本文档,为 AI Agent 提供系统架构上下文。
|
||||
|
||||
---
|
||||
|
||||
## 1. 技术栈
|
||||
|
||||
| 层级 | 技术 | 版本 |
|
||||
|------|------|------|
|
||||
| 前端框架 | Vue 3 + Vite | 3.5+ / 7.x |
|
||||
| UI 库 (管理端) | Element Plus + Tailwind CSS | 2.x / 4.x |
|
||||
| UI 库 (用户端) | Headless UI + Tailwind CSS | 1.x / 4.x |
|
||||
| 状态管理 | Pinia | 3.x |
|
||||
| 路由 | Vue Router | 4.x |
|
||||
| HTTP 客户端 | Axios | 1.x |
|
||||
| 后端框架 | Hyperf | 3.1 |
|
||||
| 协程引擎 | Swoole | 5.0+ |
|
||||
| 编程语言 | PHP | 8.1+ |
|
||||
| 数据库 | MySQL | 8.1 |
|
||||
| 缓存 | Redis | 7.x |
|
||||
| 反向代理 | Nginx | 1.25+ |
|
||||
| 容器化 | Docker + Docker Compose | - |
|
||||
|
||||
## 2. 架构总览
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 用户层 │
|
||||
│ PC 浏览器 │ 移动端 (响应式) │ 平板 │ 管理后台 │
|
||||
└───────────────────────────┬─────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌───────────────────────────────────────────────────────────────────┐
|
||||
│ CDN + WAF (可选) │
|
||||
└───────────────────────────┬───────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌───────────────────────────────────────────────────────────────────┐
|
||||
│ Nginx 集群 (负载均衡 + SSL + 静态资源) │
|
||||
│ - upstream hyperf_cluster │
|
||||
│ - WebSocket proxy │
|
||||
└───────────────────────────┬───────────────────────────────────────┘
|
||||
│
|
||||
┌─────────────┼─────────────┐
|
||||
▼ ▼ ▼
|
||||
┌──────────┐ ┌──────────┐ ┌──────────┐
|
||||
│ Hyperf-1 │ │ Hyperf-2 │ │ Hyperf-N │ (水平扩展)
|
||||
│ HTTP:9501│ │ HTTP:9501│ │ HTTP:9501│
|
||||
│ WS:9502 │ │ WS:9502 │ │ WS:9502 │
|
||||
└────┬─────┘ └────┬─────┘ └────┬─────┘
|
||||
│ │ │
|
||||
└──────┬───────┴──────┬───────┘
|
||||
│ │
|
||||
┌──────┴──────┐ ┌────┴────────┐
|
||||
│ Redis │ │ MySQL │
|
||||
│ Sentinel/ │ │ Master │
|
||||
│ Cluster │ │ ├─Slave 1 │
|
||||
│ │ │ └─Slave 2 │
|
||||
└─────────────┘ └─────────────┘
|
||||
```
|
||||
|
||||
## 3. 分层架构
|
||||
|
||||
```
|
||||
请求 → Nginx → Hyperf HTTP Server → 中间件链 → Controller
|
||||
│
|
||||
▼
|
||||
Service 层
|
||||
│
|
||||
┌───────────────┼───────────────┐
|
||||
▼ ▼ ▼
|
||||
Repository Redis Cache Event Bus
|
||||
│ │
|
||||
▼ ▼
|
||||
MySQL Async Queue
|
||||
```
|
||||
|
||||
## 4. 核心模块
|
||||
|
||||
<!-- 根据实际项目填写 -->
|
||||
|
||||
| 模块 | 说明 | 关键接口 |
|
||||
|------|------|---------|
|
||||
| 用户认证 | JWT + RBAC 权限 | `/admin/auth/login`, `/admin/auth/refresh` |
|
||||
| 权限管理 | 用户/角色/菜单/数据权限 | `/admin/users`, `/admin/roles`, `/admin/menus` |
|
||||
| 生产管理 | 订单/子订单/发货/收款 | `/admin/production-orders`, `/admin/sub-orders` |
|
||||
| 工作流 | 审批流程定义与执行 | `/admin/workflows`, `/admin/tasks` |
|
||||
| 通知中心 | WebSocket + 站内消息 + 短信 | `/admin/notifications`, `ws://9502` |
|
||||
| 客户管理 | 客户/平台/店铺 | `/admin/customers`, `/admin/platforms` |
|
||||
|
||||
## 5. 并发设计要点
|
||||
|
||||
| 设计要点 | 实现方式 |
|
||||
|---------|---------|
|
||||
| 无状态服务 | Session/Token 存 Redis,文件存对象存储 |
|
||||
| 数据库高可用 | MySQL 主从 + 读写分离 + 连接池 |
|
||||
| 缓存策略 | Cache-Aside + 穿透/击穿/雪崩防护 |
|
||||
| 异步削峰 | Hyperf AsyncQueue (Redis 驱动) |
|
||||
| 分布式锁 | Redis SET NX + Lua 脚本 |
|
||||
| 限流 | 令牌桶 (API) + 滑动窗口 (用户) |
|
||||
| 实时通信 | Swoole WebSocket + Redis Pub/Sub |
|
||||
| 水平扩展 | Docker Compose → K8s HPA |
|
||||
|
||||
## 6. 部署拓扑
|
||||
|
||||
<!-- 根据实际部署环境填写 -->
|
||||
|
||||
### 开发环境
|
||||
- 单机 Docker Compose (Nginx + Hyperf + MySQL + Redis)
|
||||
|
||||
### 生产环境
|
||||
- Nginx 集群 (2+ 节点)
|
||||
- Hyperf 应用 (4+ 实例)
|
||||
- MySQL 主从 (1 写 + 2 读)
|
||||
- Redis Sentinel (3 节点)
|
||||
|
||||
## 7. 决策记录
|
||||
|
||||
<!-- 重要架构决策记录在 docs/architecture/decisions/ -->
|
||||
|
||||
| 决策 | 选择 | 原因 |
|
||||
|------|------|------|
|
||||
| 后端框架 | Hyperf + Swoole | 协程高性能,连接池,与旧项目技术栈一致 |
|
||||
| 数据库 | MySQL 8.1 | 成熟稳定,JSON 支持,与旧项目一致 |
|
||||
| 缓存 | Redis 7 | 数据结构丰富,连接池,队列支持 |
|
||||
| 前端框架 | Vue 3 + Vite | 生态成熟,与旧项目一致,Composition API |
|
||||
| UI 库 | 管理端 Element Plus + Tailwind / 用户端 Headless UI + Tailwind | 管理端企业级组件 + 用户端轻量交互 |
|
||||
| 部署 | Docker Compose → K8s | 渐进式扩展 |
|
||||
|
||||
---
|
||||
|
||||
*最后更新: YYYY-MM-DD*
|
||||
138
docs/guides/style-guide.md
Normal file
138
docs/guides/style-guide.md
Normal file
@@ -0,0 +1,138 @@
|
||||
# 📐 Code Style Guide
|
||||
|
||||
> 团队代码风格约定,AI 在生成代码时自动遵循
|
||||
|
||||
---
|
||||
|
||||
## 通用
|
||||
|
||||
- 缩进: 2 spaces (前端) / 4 spaces (PHP)
|
||||
- 行宽: 100 chars (前端) / 120 chars (PHP)
|
||||
- 行尾: LF
|
||||
- 文件末尾: 空行
|
||||
- 字符编码: UTF-8
|
||||
|
||||
---
|
||||
|
||||
## TypeScript / Vue 3 前端
|
||||
|
||||
- 分号: 使用 (`;`)
|
||||
- 引号: 单引号 (`'`)
|
||||
- 尾逗号: 无 (`trailing comma: none`)
|
||||
- 箭头函数参数: 始终括号 (`(x) => x`)
|
||||
|
||||
### 导入顺序
|
||||
|
||||
```typescript
|
||||
// 1. Vue 运行时和内置组合式
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
|
||||
// 2. 第三方库
|
||||
// 管理端:import { ElMessage } from 'element-plus'
|
||||
// 用户端:import { Dialog } from '@headlessui/vue'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
// 3. 内部模块 (绝对路径)
|
||||
import AppButton from '@/components/ui/AppButton.vue'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
|
||||
// 4. 相对路径
|
||||
import { helper } from './utils'
|
||||
|
||||
// 5. JSDoc 类型引用(JS 项目无需 import type)
|
||||
// @typedef {import('@/types').User} User
|
||||
|
||||
// 6. 样式
|
||||
import './styles.css'
|
||||
```
|
||||
|
||||
### 文件命名
|
||||
|
||||
| 类型 | 规范 | 示例 |
|
||||
|------|------|------|
|
||||
| 组件 | PascalCase | `UserProfile.vue` |
|
||||
| Composable | camelCase + use | `useAuth.ts` |
|
||||
| 工具函数 | kebab-case | `format-date.ts` |
|
||||
| 常量 | kebab-case | `api-routes.ts` |
|
||||
| 类型文件 | kebab-case | `user.types.ts` |
|
||||
| 测试 | 同源 + .test | `UserProfile.test.ts` |
|
||||
| Store | camelCase | `user.ts` (in store/modules/) |
|
||||
| 指令 | camelCase | `auth.ts` (in directives/) |
|
||||
| API | camelCase | `production.ts` (in api/) |
|
||||
|
||||
---
|
||||
|
||||
## PHP 后端 (PSR-12)
|
||||
|
||||
- 分号: 必须
|
||||
- 引号: 单引号优先,含变量用双引号
|
||||
- 缩进: 4 spaces
|
||||
- 行宽: 120 chars
|
||||
- 大括号: 类/方法 `{` 换行,控制流 `{` 同行
|
||||
|
||||
### PHP 命名规范
|
||||
|
||||
| 类型 | 规范 | 示例 |
|
||||
|------|------|------|
|
||||
| 类 | PascalCase | `OrderService` |
|
||||
| 方法 | camelCase | `createOrder()` |
|
||||
| 变量 | camelCase | `$orderData` |
|
||||
| 常量 | SCREAMING_SNAKE | `MAX_RETRY_COUNT` |
|
||||
| 数据库字段 | snake_case | `created_at` |
|
||||
| 路由 | kebab-case 复数 | `/admin/production-orders` |
|
||||
| 迁移文件 | snake_case 时间戳 | `2026_02_24_100000_create_orders_table.php` |
|
||||
|
||||
### PHP 文件结构
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service\Production;
|
||||
|
||||
use App\Model\Production\ProductionOrder;
|
||||
use App\Repository\Production\OrderRepository;
|
||||
use Hyperf\Di\Annotation\Inject;
|
||||
|
||||
class OrderService
|
||||
{
|
||||
#[Inject]
|
||||
protected OrderRepository $orderRepository;
|
||||
|
||||
public function create(array $data): ProductionOrder
|
||||
{
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### PHP 必须遵循
|
||||
|
||||
- `declare(strict_types=1);` — 所有 PHP 文件
|
||||
- 类属性使用类型声明
|
||||
- 方法参数和返回值使用类型声明
|
||||
- 使用 PHPStan Level max 进行静态分析
|
||||
- 使用 PHP CS Fixer 格式化代码
|
||||
|
||||
---
|
||||
|
||||
## Prettier 配置 (.prettierrc)
|
||||
|
||||
```json
|
||||
{
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"printWidth": 100,
|
||||
"tabWidth": 2,
|
||||
"arrowParens": "always",
|
||||
"endOfLine": "lf",
|
||||
"plugins": ["prettier-plugin-tailwindcss"]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
*最后更新: 2026-02-24*
|
||||
125
docs/guides/testing-strategy.md
Normal file
125
docs/guides/testing-strategy.md
Normal file
@@ -0,0 +1,125 @@
|
||||
# 🧪 Testing Strategy
|
||||
|
||||
> 测试策略指南,AI 在编写测试时参考 (PHP Hyperf + Vue 3 双栈)
|
||||
|
||||
---
|
||||
|
||||
## 前端测试框架
|
||||
|
||||
| 类型 | 框架 | 配置文件 |
|
||||
|------|------|----------|
|
||||
| 单元测试 | Vitest | `vitest.config.ts` |
|
||||
| 集成测试 | Vitest + MSW | — |
|
||||
| E2E 测试 | Playwright | `playwright.config.ts` |
|
||||
|
||||
## 后端测试框架
|
||||
|
||||
| 类型 | 框架 | 配置文件 |
|
||||
|------|------|----------|
|
||||
| 单元测试 | PHPUnit | `phpunit.xml` |
|
||||
| 功能测试 | PHPUnit (HTTP) | `phpunit.xml` |
|
||||
| 静态分析 | PHPStan | `phpstan.neon` |
|
||||
| 代码规范 | PHP CS Fixer | `.php-cs-fixer.php` |
|
||||
|
||||
---
|
||||
|
||||
## 测试金字塔目标
|
||||
|
||||
### 前端
|
||||
- Unit: 70% (快速、大量)
|
||||
- Integration: 20% (模块协作)
|
||||
- E2E: 10% (关键用户路径)
|
||||
|
||||
### 后端
|
||||
- Unit: 60% (Service、Repository、工具类)
|
||||
- Integration: 30% (API 端点、数据库交互)
|
||||
- Static Analysis: 持续 (PHPStan Level max)
|
||||
|
||||
---
|
||||
|
||||
## 覆盖率目标
|
||||
|
||||
| 维度 | 前端 | 后端 |
|
||||
|------|------|------|
|
||||
| 行覆盖 | ≥ 80% | ≥ 75% |
|
||||
| 分支覆盖 | ≥ 75% | ≥ 70% |
|
||||
| 关键路径 | 100% | 100% |
|
||||
| Service 层 | — | 100% |
|
||||
|
||||
---
|
||||
|
||||
## 运行命令
|
||||
|
||||
### 前端
|
||||
|
||||
```bash
|
||||
npm run test # 运行所有单元测试
|
||||
npm run test:watch # 监听模式
|
||||
npm run test:coverage # 覆盖率报告
|
||||
npm run test:e2e # E2E 测试 (Playwright)
|
||||
```
|
||||
|
||||
### 后端
|
||||
|
||||
```bash
|
||||
composer test # PHPUnit 所有测试
|
||||
composer test:unit # 仅单元测试
|
||||
composer test:feature # 仅功能测试 (API)
|
||||
composer test:coverage # PHPUnit + 覆盖率报告
|
||||
composer analyse # PHPStan 静态分析
|
||||
composer cs-fix # PHP CS Fixer 格式化
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 后端测试目录结构
|
||||
|
||||
```
|
||||
tests/
|
||||
├── Unit/ # 纯单元测试(不依赖框架)
|
||||
│ ├── Service/
|
||||
│ │ ├── OrderServiceTest.php
|
||||
│ │ └── PaymentServiceTest.php
|
||||
│ ├── Repository/
|
||||
│ └── Utils/
|
||||
├── Feature/ # 功能测试(HTTP API 级别)
|
||||
│ ├── Auth/
|
||||
│ │ ├── LoginTest.php
|
||||
│ │ └── PermissionTest.php
|
||||
│ ├── Production/
|
||||
│ │ └── OrderApiTest.php
|
||||
│ └── System/
|
||||
│ └── HealthCheckTest.php
|
||||
├── bootstrap.php
|
||||
└── phpunit.xml
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## CI/CD 中的测试
|
||||
|
||||
```yaml
|
||||
# .github/workflows/ci.yml 中双栈测试
|
||||
jobs:
|
||||
frontend-test:
|
||||
steps:
|
||||
- npm ci
|
||||
- npm run lint
|
||||
- npm run type-check
|
||||
- npm run test:coverage
|
||||
|
||||
backend-test:
|
||||
services:
|
||||
mysql:
|
||||
image: mysql:8
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
steps:
|
||||
- composer install
|
||||
- composer analyse # PHPStan
|
||||
- composer test # PHPUnit
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
*最后更新: 2026-02-24*
|
||||
228
docs/guides/ui-specs-admin.md
Normal file
228
docs/guides/ui-specs-admin.md
Normal file
@@ -0,0 +1,228 @@
|
||||
# 🖥️ UI 规范 — 管理端(Case-Database-Frontend-admin)
|
||||
|
||||
> 管理端设计规范。AI 在 `Case-Database-Frontend-admin/` 中新建页面或组件时参考本文档。
|
||||
> 核心原则:**桌面优先、功能完整、Element Plus 标准优先**
|
||||
|
||||
---
|
||||
|
||||
## 1. 设计系统
|
||||
|
||||
| 项目 | 选型 |
|
||||
|---|---|
|
||||
| UI 组件库 | Element Plus(优先使用标准组件,不自定义重复造轮子) |
|
||||
| CSS 方案 | Tailwind CSS(辅助布局,不覆盖 Element Plus 样式) |
|
||||
| 图标 | Element Plus Icons(`@element-plus/icons-vue`) |
|
||||
| 字体 | 系统字体栈 |
|
||||
| 布局框架 | 侧边导航 + 顶部栏 + 内容区(标准后台布局) |
|
||||
|
||||
---
|
||||
|
||||
## 2. 色彩系统
|
||||
|
||||
```css
|
||||
:root {
|
||||
/* 主色(Element Plus 默认蓝) */
|
||||
--el-color-primary: #409EFF;
|
||||
|
||||
/* 管理端背景层级 */
|
||||
--admin-bg-sidebar: #001529; /* 深色侧边栏 */
|
||||
--admin-bg-header: #FFFFFF; /* 白色顶栏 */
|
||||
--admin-bg-content: #F0F2F5; /* 内容区浅灰 */
|
||||
--admin-bg-card: #FFFFFF; /* 卡片/表格白 */
|
||||
|
||||
/* 状态色 */
|
||||
--status-active: #52C41A; /* 启用/正常 */
|
||||
--status-inactive: #D9D9D9; /* 停用/禁用 */
|
||||
--status-pending: #FAAD14; /* 待处理 */
|
||||
--status-danger: #FF4D4F; /* 危险/错误 */
|
||||
}
|
||||
```
|
||||
|
||||
Element Plus 主题色配置(`src/styles/element-vars.scss`):
|
||||
```scss
|
||||
@forward 'element-plus/theme-chalk/src/common/var.scss' with (
|
||||
$colors: (
|
||||
'primary': ('base': #409EFF),
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 布局规范
|
||||
|
||||
### 整体框架
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ 顶栏(60px 固定):Logo + 面包屑 + 用户信息 + 通知 │
|
||||
├──────────────┬──────────────────────────────────────────┤
|
||||
│ │ 内容区(padding: 16px) │
|
||||
│ 侧边栏 │ ┌──────────────────────────────────────┐ │
|
||||
│ (220px) │ │ 页面标题 + 操作按钮(顶部工具栏) │ │
|
||||
│ │ ├──────────────────────────────────────┤ │
|
||||
│ 折叠后 │ │ 主内容(表格/表单/卡片) │ │
|
||||
│ → 64px │ │ │ │
|
||||
│ │ └──────────────────────────────────────┘ │
|
||||
└──────────────┴──────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 响应式
|
||||
|
||||
管理端以桌面端为主,但需支持:
|
||||
- `≥ 1280px`:完整布局(侧边栏展开)
|
||||
- `1024px ~ 1279px`:侧边栏折叠(64px 图标模式)
|
||||
- `< 1024px`:侧边栏收起为抽屉(移动端兜底)
|
||||
|
||||
---
|
||||
|
||||
## 4. Element Plus 组件使用规范
|
||||
|
||||
### 数据表格(el-table)
|
||||
|
||||
```vue
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="tableData"
|
||||
stripe
|
||||
border
|
||||
highlight-current-row
|
||||
style="width: 100%"
|
||||
>
|
||||
<!-- 数据列 -->
|
||||
<el-table-column prop="id" label="ID" width="80" sortable />
|
||||
<el-table-column prop="name" label="名称" min-width="180" show-overflow-tooltip />
|
||||
|
||||
<!-- 状态列(Tag) -->
|
||||
<el-table-column label="状态" width="100">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.status === 1 ? 'success' : 'danger'">
|
||||
{{ row.status === 1 ? '启用' : '停用' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 操作列(固定右侧) -->
|
||||
<el-table-column label="操作" fixed="right" width="160">
|
||||
<template #default="{ row }">
|
||||
<el-button v-permission="'module:edit'" link type="primary" @click="handleEdit(row)">编辑</el-button>
|
||||
<el-popconfirm title="确定删除?" @confirm="handleDelete(row.id)">
|
||||
<template #reference>
|
||||
<el-button v-permission="'module:delete'" link type="danger">删除</el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页(固定格式) -->
|
||||
<el-pagination
|
||||
v-model:current-page="query.page"
|
||||
v-model:page-size="query.page_size"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:total="total"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
class="mt-4 justify-end"
|
||||
@change="fetchData"
|
||||
/>
|
||||
```
|
||||
|
||||
### 搜索表单
|
||||
|
||||
```vue
|
||||
<!-- 搜索栏(折叠设计,超过 3 个条件可折叠) -->
|
||||
<el-card class="mb-4" shadow="never">
|
||||
<el-form :model="query" inline @keyup.enter="handleSearch">
|
||||
<el-form-item label="关键词">
|
||||
<el-input v-model="query.keyword" placeholder="请输入" clearable style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleSearch">搜索</el-button>
|
||||
<el-button @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
```
|
||||
|
||||
### 弹窗表单
|
||||
|
||||
```vue
|
||||
<el-dialog v-model="dialogVisible" :title="isEdit ? '编辑' : '新建'" width="600px" @close="handleDialogClose">
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="名称" prop="name">
|
||||
<el-input v-model="form.name" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="submitting" @click="handleSubmit">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
```
|
||||
|
||||
规则:
|
||||
- 弹窗宽度:简单表单 500px,复杂表单 700-900px
|
||||
- 弹窗关闭时必须调用 `formRef.value?.resetFields()`
|
||||
- 提交按钮加 `:loading` 防重复提交
|
||||
|
||||
---
|
||||
|
||||
## 5. 页面标准结构
|
||||
|
||||
每个管理端页面遵循以下结构:
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="admin-page">
|
||||
<!-- 页面头部:标题 + 主要操作按钮 -->
|
||||
<div class="mb-4 flex items-center justify-between">
|
||||
<h2 class="text-lg font-semibold text-gray-800">页面标题</h2>
|
||||
<el-button v-permission="'module:create'" type="primary" @click="handleCreate">
|
||||
<el-icon><Plus /></el-icon> 新建
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 搜索区 -->
|
||||
<!-- 表格区 -->
|
||||
<!-- 分页区 -->
|
||||
<!-- 弹窗区 -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
// 1. 导入
|
||||
// 2. 响应式状态
|
||||
// 3. 表单/验证规则
|
||||
// 4. 数据获取
|
||||
// 5. 事件处理(CRUD)
|
||||
// 6. 生命周期
|
||||
</script>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 间距规范
|
||||
|
||||
| 场景 | 间距 |
|
||||
|---|---|
|
||||
| 内容区内边距 | `p-4`(16px) |
|
||||
| 卡片间距 | `mb-4`(16px) |
|
||||
| 表单项间距 | Element Plus 默认(`el-form` 管理) |
|
||||
| 操作按钮间距 | `ml-2`(8px,同行按钮) |
|
||||
|
||||
---
|
||||
|
||||
## 7. 状态规范
|
||||
|
||||
| 状态 | 实现方式 |
|
||||
|---|---|
|
||||
| 加载中 | `v-loading="loading"`(`el-table`、`el-card`) |
|
||||
| 空状态 | `el-empty`(有描述、有图) |
|
||||
| 错误状态 | `el-result` type="error"(提供重试按钮) |
|
||||
| 操作成功 | `ElMessage.success('操作成功')` |
|
||||
| 操作失败 | `ElMessage.error(error.message)` |
|
||||
| 危险操作确认 | `el-popconfirm`(行内)/ `ElMessageBox.confirm`(批量) |
|
||||
|
||||
---
|
||||
|
||||
*最后更新: 2026-02-26*
|
||||
157
docs/guides/ui-specs-user.md
Normal file
157
docs/guides/ui-specs-user.md
Normal file
@@ -0,0 +1,157 @@
|
||||
# 🎨 UI 规范 — 用户端(Case-Database-Frontend-user)
|
||||
|
||||
> 用户端设计规范。AI 在 `Case-Database-Frontend-user/` 中还原设计稿或新建页面时参考本文档。
|
||||
> 核心原则:**移动优先、性能优先、品牌一致**
|
||||
|
||||
---
|
||||
|
||||
## 1. 设计系统
|
||||
|
||||
| 项目 | 选型 |
|
||||
|---|---|
|
||||
| CSS 方案 | Tailwind CSS v3 |
|
||||
| 图标 | Lucide Icons(`lucide-vue-next`) |
|
||||
| 字体 | 系统字体栈(中文优先)|
|
||||
| 动效 | CSS Transition(避免 JS 动画影响性能) |
|
||||
|
||||
---
|
||||
|
||||
## 2. 色彩系统
|
||||
|
||||
```css
|
||||
:root {
|
||||
/* 品牌主色 — 根据实际品牌替换 */
|
||||
--color-primary: #3B82F6; /* blue-500 */
|
||||
--color-primary-dark: #1D4ED8; /* blue-700(hover) */
|
||||
--color-primary-light: #EFF6FF; /* blue-50(背景) */
|
||||
|
||||
/* 功能色 */
|
||||
--color-success: #10B981; /* green-500 */
|
||||
--color-warning: #F59E0B; /* amber-500 */
|
||||
--color-danger: #EF4444; /* red-500 */
|
||||
--color-info: #6B7280; /* gray-500 */
|
||||
|
||||
/* 文本层级 */
|
||||
--color-text-primary: #111827; /* gray-900 */
|
||||
--color-text-secondary: #6B7280; /* gray-500 */
|
||||
--color-text-disabled: #D1D5DB; /* gray-300 */
|
||||
|
||||
/* 背景 */
|
||||
--color-bg-page: #F9FAFB; /* gray-50 */
|
||||
--color-bg-card: #FFFFFF;
|
||||
--color-border: #E5E7EB; /* gray-200 */
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 字体规范
|
||||
|
||||
| 用途 | 大小 | 字重 | Tailwind 类 |
|
||||
|---|---|---|---|
|
||||
| 页面大标题 | 24px / 1.5rem | 700 | `text-2xl font-bold` |
|
||||
| 卡片标题 | 18px / 1.125rem | 600 | `text-lg font-semibold` |
|
||||
| 正文 | 14px / 0.875rem | 400 | `text-sm` |
|
||||
| 辅助/标签 | 12px / 0.75rem | 400 | `text-xs` |
|
||||
| 按钮文字 | 14px / 0.875rem | 500 | `text-sm font-medium` |
|
||||
|
||||
---
|
||||
|
||||
## 4. 间距系统(4px 基准)
|
||||
|
||||
| 场景 | 间距 | Tailwind 类 |
|
||||
|---|---|---|
|
||||
| 行内元素间距 | 8px | `gap-2` / `space-x-2` |
|
||||
| 卡片内边距 | 16px | `p-4` |
|
||||
| 区块间间距 | 24px | `gap-6` / `mb-6` |
|
||||
| 页面两侧边距 | 16px(移动)/ 24px(桌面) | `px-4 md:px-6` |
|
||||
| 页面顶部安全区 | 16px | `pt-4` |
|
||||
|
||||
---
|
||||
|
||||
## 5. 响应式断点(移动优先)
|
||||
|
||||
| 断点 | 最小宽度 | 典型设备 | 设计优先级 |
|
||||
|---|---|---|---|
|
||||
| `默认` | 375px | 手机(主力) | ⭐⭐⭐⭐⭐ |
|
||||
| `sm` | 640px | 大屏手机 | ⭐⭐⭐⭐ |
|
||||
| `md` | 768px | 平板竖屏 | ⭐⭐⭐ |
|
||||
| `lg` | 1024px | 平板横屏/小桌面 | ⭐⭐ |
|
||||
| `xl` | 1280px | 桌面 | ⭐ |
|
||||
|
||||
**断点使用顺序**(必须从小写起):
|
||||
```html
|
||||
<!-- ✅ 正确:移动端默认,再扩展 -->
|
||||
<div class="w-full md:w-1/2 lg:w-1/3">
|
||||
|
||||
<!-- ❌ 错误:桌面优先写法 -->
|
||||
<div class="w-1/3 lg:w-full">
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 组件规范
|
||||
|
||||
### 按钮
|
||||
|
||||
```html
|
||||
<!-- 主要操作 -->
|
||||
<button class="w-full rounded-lg bg-primary py-3 text-sm font-medium text-white active:opacity-80">
|
||||
立即购买
|
||||
</button>
|
||||
|
||||
<!-- 次要操作 -->
|
||||
<button class="w-full rounded-lg border border-gray-300 py-3 text-sm font-medium text-gray-700">
|
||||
加入购物车
|
||||
</button>
|
||||
```
|
||||
|
||||
规则:
|
||||
- 移动端主操作按钮通常 `w-full`,高度 ≥ 44px
|
||||
- 按钮文字简短(≤ 6 字)
|
||||
- 加载中禁用按钮并显示 Spinner
|
||||
|
||||
### 卡片
|
||||
|
||||
```html
|
||||
<div class="rounded-xl bg-white p-4 shadow-sm">
|
||||
<!-- 内容 -->
|
||||
</div>
|
||||
```
|
||||
|
||||
### 空状态 / 错误状态(必须实现)
|
||||
|
||||
```html
|
||||
<!-- 空状态 -->
|
||||
<div class="flex flex-col items-center py-16 text-gray-400">
|
||||
<LucidePackageOpen class="mb-3 h-12 w-12" />
|
||||
<p class="text-sm">暂无数据</p>
|
||||
</div>
|
||||
|
||||
<!-- 骨架屏(优先于 Loading Spinner) -->
|
||||
<div class="animate-pulse rounded-xl bg-gray-100 h-24 w-full" />
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 触摸交互规范
|
||||
|
||||
- 所有可点击元素最小尺寸:**44 × 44px**
|
||||
- 相邻可点击元素间距 ≥ **8px**
|
||||
- 列表项点击区域铺满整行
|
||||
- 避免 hover 专属交互(移动端无 hover)
|
||||
|
||||
---
|
||||
|
||||
## 8. 视觉还原流程
|
||||
|
||||
1. 识别所属前端(用户端 = 本文档)
|
||||
2. 分析设计稿的色彩、间距(对齐上方规范)
|
||||
3. 移动端布局先行,再添加 md/lg 断点适配
|
||||
4. 使用 Tailwind 语义类(避免任意值 `w-[123px]`)
|
||||
5. 实现空状态、加载状态、错误状态
|
||||
6. 验证触摸目标尺寸
|
||||
|
||||
---
|
||||
|
||||
*最后更新: 2026-02-26*
|
||||
47
docs/guides/ui-specs.md
Normal file
47
docs/guides/ui-specs.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# 🎨 UI Specifications
|
||||
|
||||
> 通用 UI 设计规范。具体以 `ui-specs-user.md`(用户端)和 `ui-specs-admin.md`(管理端)为准。
|
||||
|
||||
---
|
||||
|
||||
## 设计系统
|
||||
|
||||
| 维度 | 用户端 (Case-Database-Frontend-user/) | 管理端 (Case-Database-Frontend-admin/) |
|
||||
|---|---|---|
|
||||
| **组件方案** | Tailwind CSS + 自定义组件 | Element Plus + Tailwind CSS |
|
||||
| **图标** | Lucide Icons | @element-plus/icons-vue |
|
||||
| **字体** | 系统字体栈 (system-ui) | 系统字体栈 (system-ui) |
|
||||
| **设计风格** | 品牌化、轻量、视觉吸引力 | 专业、实用、信息密度高 |
|
||||
| **响应式** | 移动优先 (xs → xl) | 桌面优先 (≥ 1280px) |
|
||||
|
||||
## 间距
|
||||
|
||||
使用 Tailwind 默认间距 (4px 基准):
|
||||
- 紧凑: `gap-2` (8px)
|
||||
- 标准: `gap-4` (16px)
|
||||
- 宽松: `gap-6` (24px)
|
||||
- 区块: `gap-8` (32px)
|
||||
|
||||
## 响应式断点
|
||||
|
||||
| 断点 | 宽度 | 说明 |
|
||||
|------|------|------|
|
||||
| sm | 640px | 大手机 |
|
||||
| md | 768px | 平板 |
|
||||
| lg | 1024px | 小桌面 |
|
||||
| xl | 1280px | 桌面 |
|
||||
| 2xl | 1536px | 大屏 |
|
||||
|
||||
## 视觉还原流程
|
||||
|
||||
当提供设计稿截图时:
|
||||
1. 确认目标前端(用户端 or 管理端)
|
||||
2. 分析颜色、间距、字体
|
||||
3. 识别组件层级
|
||||
4. 用户端:使用 Tailwind CSS 还原;管理端:优先使用 Element Plus 组件
|
||||
5. 注意细节: 阴影、圆角、边框
|
||||
6. 如不确定,列出选项询问
|
||||
|
||||
---
|
||||
|
||||
*最后更新: 2026-02-26*
|
||||
304
docs/runbooks/backend-debug.md
Normal file
304
docs/runbooks/backend-debug.md
Normal file
@@ -0,0 +1,304 @@
|
||||
# Backend Debug Runbook
|
||||
|
||||
## 常见问题排查
|
||||
|
||||
### 1. 登录返回 401 "账号或密码错误"
|
||||
|
||||
#### 症状
|
||||
```bash
|
||||
curl -X POST http://127.0.0.1:9501/api/auth/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"username": "superadmin", "password": "Admin@2026"}'
|
||||
# 返回: {"code": 401, "message": "账号或密码错误"}
|
||||
```
|
||||
|
||||
#### 排查步骤
|
||||
|
||||
1. **检查数据库是否有用户**
|
||||
```bash
|
||||
docker exec hyperf-mysql mysql -uroot -p123456 case_db \
|
||||
-e "SELECT id, username, phone FROM auth_users WHERE deleted_at IS NULL;"
|
||||
```
|
||||
|
||||
2. **如果用户不存在,运行 Seeder**
|
||||
```bash
|
||||
docker exec hyperf-skeleton php bin/hyperf.php db:seed --class=DatabaseSeeder
|
||||
```
|
||||
|
||||
3. **验证密码比对逻辑**
|
||||
```bash
|
||||
# 检查 User Model 是否使用 password_hash 和 password_verify
|
||||
# 确保 Seeder 中的密码也是用 password_hash 加密的
|
||||
```
|
||||
|
||||
### 2. 返回 500 "Internal Server Error" - env() 未定义
|
||||
|
||||
#### 症状
|
||||
```bash
|
||||
curl -X POST http://127.0.0.1:9501/api/auth/sms/send \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"phone": "18970867739", "purpose": "login"}'
|
||||
# 返回: {"code": 500, "message": "Internal Server Error"}
|
||||
```
|
||||
|
||||
#### 日志错误
|
||||
```
|
||||
[ERROR] Call to undefined function env()[43] in /opt/www/modules/Auth/src/Service/SmsService.php
|
||||
[ERROR] #0 /opt/www/runtime/container/proxy/Modules_Auth_Http_Controller_Api_SmsController.proxy.php(42):
|
||||
Modules\Auth\Service\SmsService->send()
|
||||
```
|
||||
|
||||
#### 根因
|
||||
PHP CLI 和 Swoole Worker 环境中**不提供全局 `env()` 函数**(这是 Laravel 特有的),会导致 `Call to undefined function env()` 错误。
|
||||
|
||||
#### 解决方案
|
||||
|
||||
**修改前(错误)**:
|
||||
```php
|
||||
// ❌ 在 Service/Middleware 中直接使用 env()
|
||||
if (env('APP_ENV', 'development') !== 'production') {
|
||||
// ...
|
||||
}
|
||||
$secret = env('JWT_SECRET', 'default');
|
||||
```
|
||||
|
||||
**修改后(正确)**:
|
||||
```php
|
||||
// ✅ 使用 Hyperf 的 config() 函数读取配置
|
||||
$appEnv = \Hyperf\Config\config('app.env', 'development');
|
||||
if ($appEnv !== 'production') {
|
||||
// ...
|
||||
}
|
||||
$secret = \Hyperf\Config\config('jwt.secret', 'default-secret');
|
||||
```
|
||||
|
||||
**配置文件正确写法**(在配置文件中可以使用 env()):
|
||||
```php
|
||||
// config/autoload/jwt.php
|
||||
use function Hyperf\Support\env;
|
||||
|
||||
return [
|
||||
'secret' => env('JWT_SECRET', 'dev-fallback-secret'),
|
||||
'ttl' => (int) env('JWT_TTL', 7200),
|
||||
];
|
||||
```
|
||||
|
||||
**常见错误场景**:
|
||||
```php
|
||||
// ❌ Service 层中使用 env()
|
||||
class SmsService {
|
||||
public function send() {
|
||||
if (env('APP_ENV') !== 'production') { // 报错
|
||||
// ...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ❌ Middleware 层中使用 env()
|
||||
class JwtAuthMiddleware {
|
||||
public function process() {
|
||||
$secret = env('JWT_SECRET'); // 报错
|
||||
}
|
||||
}
|
||||
|
||||
// ❌ 即使添加命名空间前缀也不行
|
||||
if (\env('APP_ENV') !== 'production') { // 仍然报错
|
||||
```
|
||||
|
||||
**正确实践**:
|
||||
```php
|
||||
// ✅ Service 层使用 config()
|
||||
use Hyperf\Config\config;
|
||||
|
||||
class SmsService {
|
||||
public function send() {
|
||||
$appEnv = config('app.env', 'development');
|
||||
if ($appEnv !== 'production') {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ✅ 配置文件中使用 env()(正确位置)
|
||||
// config/autoload/app.php
|
||||
use function Hyperf\Support\env;
|
||||
|
||||
return [
|
||||
'env' => env('APP_ENV', 'development'),
|
||||
'debug' => env('APP_DEBUG', false),
|
||||
];
|
||||
```
|
||||
|
||||
### 3. Token 验证失败 - Secret 不一致
|
||||
|
||||
#### 症状
|
||||
```bash
|
||||
# 登录成功
|
||||
TOKEN=$(curl -s -X POST http://127.0.0.1:9501/api/auth/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"username": "superadmin", "password": "Admin@2026"}' | jq -r '.data.access_token')
|
||||
|
||||
# 但 profile 接口返回 40102
|
||||
curl -X GET "http://127.0.0.1:9501/api/auth/profile" \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
# 返回: {"code": 40102, "message": "Token invalid"}
|
||||
```
|
||||
|
||||
#### 根因
|
||||
AuthService 和 JwtAuthMiddleware 使用不同的 JWT secret。
|
||||
|
||||
#### 解决方案
|
||||
|
||||
**确保两处使用相同的 secret**:
|
||||
|
||||
```php
|
||||
// AuthService.php
|
||||
protected function generateToken(User $user, string $type = 'access', ?int $ttlOverride = null): string
|
||||
{
|
||||
$secret = 'dev-only-insecure-secret-20260304'; // 固定值,不要用 md5(__DIR__)
|
||||
// ...
|
||||
}
|
||||
|
||||
// JwtAuthMiddleware.php
|
||||
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
||||
{
|
||||
// ...
|
||||
$secret = 'dev-only-insecure-secret-20260304'; // 与 AuthService 完全相同
|
||||
$decoded = JWT::decode($token, new Key($secret, 'HS256'));
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
**禁止的做法**:
|
||||
```php
|
||||
// ❌ 使用 md5(__DIR__) 会导致路径不一致
|
||||
$secret = 'dev-only-insecure-key-' . md5(__DIR__);
|
||||
```
|
||||
|
||||
### 4. 服务启动失败 - 异步队列配置缺失
|
||||
|
||||
#### 症状
|
||||
```bash
|
||||
docker compose restart hyperf-skeleton
|
||||
docker logs hyperf-skeleton --tail 50
|
||||
```
|
||||
|
||||
#### 日志错误
|
||||
```
|
||||
[ERROR] Entry "Modules\Security\Listener\SecurityEventListener" cannot be resolved:
|
||||
Entry "Hyperf\AsyncQueue\Driver\DriverFactory" cannot be resolved
|
||||
```
|
||||
|
||||
或
|
||||
|
||||
```
|
||||
[ERROR] [Error] default is a invalid driver
|
||||
```
|
||||
|
||||
#### 根因
|
||||
使用了异步队列,但缺少 `config/autoload/async_queue.php` 配置。
|
||||
|
||||
#### 解决方案
|
||||
|
||||
创建配置文件:
|
||||
```php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use function Hyperf\Support\env;
|
||||
|
||||
return [
|
||||
'default' => [
|
||||
'driver' => env('ASYNC_QUEUE_DRIVER', 'redis'),
|
||||
'channel' => 'queue',
|
||||
'retry_after' => 60,
|
||||
'block_seconds' => 5,
|
||||
'max_messages' => 100,
|
||||
'redis' => [
|
||||
'pool' => 'default',
|
||||
],
|
||||
],
|
||||
];
|
||||
```
|
||||
|
||||
### 5. 服务启动失败 - Config 对象未注入
|
||||
|
||||
#### 症状
|
||||
```
|
||||
[ERROR] Entry "Hyperf\Config\Config" cannot be resolved:
|
||||
Parameter $configs of __construct() has no value defined or guessable
|
||||
```
|
||||
|
||||
#### 根因
|
||||
Hyperf Config 对象未在 dependencies.php 中注册。
|
||||
|
||||
#### 解决方案
|
||||
|
||||
**检查 `config/autoload/dependencies.php`**:
|
||||
```php
|
||||
return [
|
||||
Hyperf\Database\Migrations\Migrator::class => App\Database\MigratorFactory::class,
|
||||
Hyperf\Database\Seeders\Seed::class => App\Database\SeedFactory::class,
|
||||
// 确保 Config 不在这里注册(Hyperf 会自动注册)
|
||||
];
|
||||
```
|
||||
|
||||
## 验证清单
|
||||
|
||||
### 新模块开发前
|
||||
- [ ] 检查是否需要队列配置
|
||||
- [ ] 检查是否需要缓存配置
|
||||
- [ ] 检查是否需要 JWT 配置
|
||||
- [ ] 所有 `env()` 都有默认值
|
||||
|
||||
### 代码修改后
|
||||
- [ ] 不在 Service/Middleware 中使用 `config()`
|
||||
- [ ] JWT secret 使用固定值或环境变量
|
||||
- [ ] AuthService 和 JwtAuthMiddleware 使用相同 secret
|
||||
- [ ] 重启服务并测试关键路径
|
||||
|
||||
### 部署前
|
||||
- [ ] 生产环境设置 `JWT_SECRET` 环境变量
|
||||
- [ ] 检查 .env.example 是否包含所有必要的环境变量
|
||||
- [ ] 运行 Seeder 确保初始数据正确
|
||||
|
||||
## 调试命令
|
||||
|
||||
### 查看日志
|
||||
```bash
|
||||
# Hyperf 应用日志
|
||||
docker logs hyperf-skeleton --tail 100 -f
|
||||
|
||||
# 数据库日志
|
||||
docker logs hyperf-mysql --tail 50
|
||||
|
||||
# Redis 日志
|
||||
docker logs hyperf-redis --tail 50
|
||||
```
|
||||
|
||||
### 进入容器调试
|
||||
```bash
|
||||
docker exec -it hyperf-skeleton bash
|
||||
|
||||
# 运行迁移
|
||||
php bin/hyperf.php migrate
|
||||
|
||||
# 运行 Seeder
|
||||
php bin/hyperf.php db:seed
|
||||
|
||||
# 检查 PHP 语法
|
||||
php -l modules/Auth/src/Service/AuthService.php
|
||||
```
|
||||
|
||||
### 测试 API
|
||||
```bash
|
||||
# 登录
|
||||
curl -X POST http://127.0.0.1:9501/api/auth/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"username": "superadmin", "password": "Admin@2026"}'
|
||||
|
||||
# 使用 token 访问受保护接口
|
||||
TOKEN="your-access-token-here"
|
||||
curl -X GET "http://127.0.0.1:9501/api/auth/profile" \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
226
docs/runbooks/deployment.md
Normal file
226
docs/runbooks/deployment.md
Normal file
@@ -0,0 +1,226 @@
|
||||
# 🚢 Deployment Runbook
|
||||
|
||||
> PHP Hyperf + Swoole + Vue 3 部署流程指南
|
||||
|
||||
---
|
||||
|
||||
## 环境
|
||||
|
||||
| 环境 | URL | 触发 |
|
||||
|------|-----|------|
|
||||
| Development | `localhost:8200` (前端) / `localhost:9501` (后端) | 本地开发 |
|
||||
| Staging | `staging.example.com` | merge to `develop` |
|
||||
| Production | `www.example.com` | merge to `main` |
|
||||
|
||||
## Docker Compose 模板
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
# Nginx — 负载均衡 + 静态资源 + SSL
|
||||
nginx:
|
||||
image: nginx:1.25-alpine
|
||||
container_name: app_nginx
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf
|
||||
- ./docker/nginx/conf.d:/etc/nginx/conf.d
|
||||
- ./Case-Database-Frontend-user/dist:/usr/share/nginx/html/user
|
||||
- ./Case-Database-Frontend-admin/dist:/usr/share/nginx/html/admin
|
||||
- ./docker/nginx/ssl:/etc/nginx/ssl
|
||||
depends_on:
|
||||
- hyperf
|
||||
networks:
|
||||
- app_network
|
||||
restart: unless-stopped
|
||||
|
||||
# Hyperf — PHP 8.1 + Swoole (HTTP + WebSocket)
|
||||
hyperf:
|
||||
build:
|
||||
context: ./Case-Database-Backend
|
||||
dockerfile: Dockerfile
|
||||
container_name: app_backend
|
||||
ports:
|
||||
- "9501:9501" # HTTP API
|
||||
- "9502:9502" # WebSocket
|
||||
volumes:
|
||||
- ./Case-Database-Backend:/opt/www
|
||||
environment:
|
||||
- APP_ENV=${APP_ENV:-production}
|
||||
- DB_HOST=mysql
|
||||
- DB_PORT=3306
|
||||
- DB_DATABASE=${DB_DATABASE}
|
||||
- DB_USERNAME=${DB_USERNAME}
|
||||
- DB_PASSWORD=${DB_PASSWORD}
|
||||
- REDIS_HOST=redis
|
||||
- REDIS_PORT=6379
|
||||
- REDIS_AUTH=${REDIS_AUTH}
|
||||
depends_on:
|
||||
mysql:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- app_network
|
||||
restart: unless-stopped
|
||||
|
||||
# MySQL 8.1 — 主数据库
|
||||
mysql:
|
||||
image: mysql:8.1
|
||||
container_name: app_mysql
|
||||
ports:
|
||||
- "${DB_PORT:-3307}:3306"
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
|
||||
MYSQL_DATABASE: ${DB_DATABASE}
|
||||
MYSQL_USER: ${DB_USERNAME}
|
||||
MYSQL_PASSWORD: ${DB_PASSWORD}
|
||||
volumes:
|
||||
- mysql_data:/var/lib/mysql
|
||||
- ./docker/mysql/conf.d:/etc/mysql/conf.d
|
||||
- ./docker/mysql/init:/docker-entrypoint-initdb.d
|
||||
command: >
|
||||
--default-authentication-plugin=caching_sha2_password
|
||||
--character-set-server=utf8mb4
|
||||
--collation-server=utf8mb4_unicode_ci
|
||||
--max-connections=500
|
||||
--innodb-buffer-pool-size=1G
|
||||
--slow-query-log=ON
|
||||
--long-query-time=1
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
networks:
|
||||
- app_network
|
||||
restart: unless-stopped
|
||||
|
||||
# Redis 7 — 缓存 + 队列 + Session
|
||||
redis:
|
||||
image: redis:7.2-alpine
|
||||
container_name: app_redis
|
||||
ports:
|
||||
- "${REDIS_PORT:-6379}:6379"
|
||||
command: redis-server --requirepass ${REDIS_AUTH} --maxmemory 512mb --maxmemory-policy allkeys-lru
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "-a", "${REDIS_AUTH}", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
networks:
|
||||
- app_network
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
mysql_data:
|
||||
driver: local
|
||||
redis_data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
app_network:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
## Backend Dockerfile
|
||||
|
||||
```dockerfile
|
||||
FROM hyperf/hyperf:8.1-alpine-v3.18-swoole
|
||||
|
||||
LABEL maintainer="Enterprise Digital Platform"
|
||||
|
||||
ENV TIMEZONE=Asia/Shanghai
|
||||
ENV APP_ENV=production
|
||||
|
||||
WORKDIR /opt/www
|
||||
|
||||
COPY composer.json composer.lock ./
|
||||
RUN composer install --no-dev --optimize-autoloader --no-scripts
|
||||
|
||||
COPY . .
|
||||
RUN composer dump-autoload -o
|
||||
|
||||
EXPOSE 9501 9502
|
||||
|
||||
ENTRYPOINT ["php", "/opt/www/bin/hyperf.php", "start"]
|
||||
```
|
||||
|
||||
## 部署检查清单
|
||||
|
||||
### 部署前
|
||||
- [ ] 所有后端测试通过 (`composer test`)
|
||||
- [ ] 所有前端测试通过 (`npm test`)
|
||||
- [ ] 代码审查已批准
|
||||
- [ ] 数据库迁移已准备 (`php bin/hyperf.php migrate:status`)
|
||||
- [ ] 环境变量已配置 (`.env`)
|
||||
- [ ] Redis 连接正常
|
||||
- [ ] 静态分析通过 (`composer analyse`)
|
||||
|
||||
### 部署步骤
|
||||
```bash
|
||||
# 1. 拉取最新代码
|
||||
git pull origin main
|
||||
|
||||
# 2. 后端依赖更新
|
||||
cd Case-Database-Backend && composer install --no-dev -o
|
||||
|
||||
# 3. 数据库迁移
|
||||
php bin/hyperf.php migrate
|
||||
|
||||
# 4. 前端构建
|
||||
cd Case-Database-Frontend-user && npm ci && npm run build
|
||||
cd ../Case-Database-Frontend-admin && npm ci && npm run build
|
||||
|
||||
# 5. 重启服务
|
||||
docker-compose restart hyperf
|
||||
docker-compose restart nginx
|
||||
|
||||
# 6. 验证
|
||||
curl -s https://your-domain.com/admin/health | jq
|
||||
```
|
||||
|
||||
### 部署后
|
||||
- [ ] 健康检查通过
|
||||
- [ ] 监控无异常 (CPU/内存/连接数)
|
||||
- [ ] 数据库迁移成功
|
||||
- [ ] WebSocket 连接正常
|
||||
- [ ] 队列消费进程运行中
|
||||
|
||||
## 回滚
|
||||
|
||||
```bash
|
||||
# 代码回滚
|
||||
git revert HEAD
|
||||
git push origin main
|
||||
|
||||
# 数据库回滚
|
||||
php bin/hyperf.php migrate:rollback --step=1
|
||||
|
||||
# Docker 容器回滚到上一个镜像
|
||||
docker-compose pull hyperf
|
||||
docker-compose up -d hyperf
|
||||
```
|
||||
|
||||
## 扩展到多实例
|
||||
|
||||
```bash
|
||||
# 水平扩展 Hyperf 实例
|
||||
docker-compose up -d --scale hyperf=3
|
||||
|
||||
# Nginx upstream 配置多后端
|
||||
upstream hyperf_cluster {
|
||||
server hyperf_1:9501;
|
||||
server hyperf_2:9501;
|
||||
server hyperf_3:9501;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
*最后更新: YYYY-MM-DD*
|
||||
54
docs/runbooks/incident-response.md
Normal file
54
docs/runbooks/incident-response.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# 🚨 Incident Response
|
||||
|
||||
> 事故响应流程 (PHP Hyperf + Vue 3)
|
||||
|
||||
---
|
||||
|
||||
## 严重等级
|
||||
|
||||
| 等级 | 定义 | 响应时间 |
|
||||
|------|------|----------|
|
||||
| P0 | 服务完全不可用 | 15 分钟内 |
|
||||
| P1 | 核心功能受损 | 1 小时内 |
|
||||
| P2 | 非核心功能受损 | 4 小时内 |
|
||||
| P3 | 轻微问题 | 1 工作日 |
|
||||
|
||||
## 响应流程
|
||||
|
||||
1. **确认**: 确认问题、评估影响范围和严重等级
|
||||
2. **通知**: 通知相关人员 (企业微信 / Slack #incidents)
|
||||
3. **修复**: 定位问题、实施修复或回滚
|
||||
4. **验证**: 确认修复有效
|
||||
5. **复盘**: 编写事后分析报告
|
||||
|
||||
## 常用命令
|
||||
|
||||
```bash
|
||||
# 查看后端日志
|
||||
tail -f runtime/logs/hyperf.log
|
||||
|
||||
# Docker 查看日志
|
||||
docker compose logs -f hyperf
|
||||
|
||||
# 检查数据库连接
|
||||
php bin/hyperf.php tinker --execute="Db::select('SELECT 1')"
|
||||
|
||||
# 检查 Swoole 状态
|
||||
curl http://localhost:9501/admin/health
|
||||
|
||||
# 快速回滚代码
|
||||
git revert HEAD && git push origin main
|
||||
|
||||
# 回滚数据库迁移
|
||||
php bin/hyperf.php migrate:rollback --step=1
|
||||
|
||||
# Docker 回滚到上一版本
|
||||
docker compose pull && docker compose up -d
|
||||
|
||||
# 重启服务
|
||||
docker compose restart hyperf
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
*最后更新: 2026-02-24*
|
||||
483
docs/specs/F1-认证与账户.md
Normal file
483
docs/specs/F1-认证与账户.md
Normal file
@@ -0,0 +1,483 @@
|
||||
# F1 统一认证与账户中心
|
||||
|
||||
> **涉及端**:用户端(`Case-Database-Frontend-user`)+ 后端(`Case-Database-Backend`)
|
||||
>
|
||||
> **关联文档**:
|
||||
> - API 契约:[api-contracts.md §2.1 用户端认证](../architecture/api-contracts.md)
|
||||
> - 数据模型:[data-model.md §4.1 用户与权限域](../architecture/data-model.md)
|
||||
> - UI 规范:[ui-specs-user.md](../guides/ui-specs-user.md)
|
||||
> - 参考原型:`docs/reference/登录页.html`
|
||||
|
||||
---
|
||||
|
||||
## 目标与边界
|
||||
|
||||
- 在保持本系统独立账号体系前提下,实现与企业数字化平台便捷互通登录
|
||||
- 覆盖账号登录、短信登录、扫码登录、OAuth 登录、企业 SSO、注册、找回密码与个人中心
|
||||
- 完善验证码、风控、审计、会话安全与协议合规,不在前端和日志中存储敏感明文
|
||||
|
||||
---
|
||||
|
||||
## 开发状态说明
|
||||
|
||||
> - 🟢 已完成 — 前后端均已联调可用
|
||||
> - 🟡 前端已完成 — 前端 UI 和交互已实现,待后端对接
|
||||
> - 🟠 前端部分完成 — 前端 UI 存在但逻辑为占位/模拟,需补全
|
||||
> - ⚪ 待开发 — 前后端均未开发
|
||||
|
||||
## 功能清单
|
||||
|
||||
| 编号 | 功能 | 优先级 | 状态 |
|
||||
|------|------|--------|------|
|
||||
| F1.1 | 多模式登录(账号 / 短信 / 扫码) | P0 | 🟠 部分完成 |
|
||||
| F1.2 | 第三方授权登录(微信 / QQ) | P1 | 🟠 仅入口 UI |
|
||||
| F1.3 | 账户辅助功能(自动登录 / 忘记密码) | P0 | 🟠 部分完成 |
|
||||
| F1.4 | 全局主题切换(深色 / 浅色) | P1 | 🟢 已完成 |
|
||||
| F1.5 | 简易个人中心 | P1 | 🟠 仅基础展示 |
|
||||
| F1.6 | 用户注册 | P0 | 🟠 仅 UI 框架 |
|
||||
| F1.7 | 安全管理后台 | P1 | ⚪ 待开发 |
|
||||
| F1.8 | 企业 SSO 集成 | P1 | ⚪ 待开发 |
|
||||
| F1.9 | 多端会话管理 | P2 | ⚪ 待开发 |
|
||||
|
||||
---
|
||||
|
||||
## F1.1 多模式登录(P0) — 🟠 部分完成
|
||||
|
||||
### 开发现状
|
||||
|
||||
| 子功能 | 前端 | 后端 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| 左右分屏布局 | ✅ | — | `LoginView.vue` + `LoginBanner.vue` |
|
||||
| 账号密码登录 | ✅ | ✅ | `LoginTabPanel.vue` → `useLoginForms.handleLogin` → `authApi.login` 已联调 |
|
||||
| 短信登录表单 | ✅ | ❌ | UI 已实现(Headless UI TabPanel),但逻辑仅 Toast 提示"短信登录未实现" |
|
||||
| 密码明文切换 | ✅ | — | `AppInput.vue` 已支持 |
|
||||
| 账号/短信标签页切换 | ✅ | — | Headless UI `TabGroup` 实现 |
|
||||
| 扫码登录 | ❌ | ❌ | 未实现(无二维码图标入口、无二维码区域) |
|
||||
| 图形验证码 | ✅ | ✅ | 拼图滑块验证码已实现,登录/注册/发短信前触发 |
|
||||
| 登录成功跳转 redirect | ✅ | — | 路由守卫已携带 `redirect` 参数,登录后跳转已实现 |
|
||||
| Loading 态 | ✅ | — | 提交时按钮 Loading 态已实现 |
|
||||
| 错误提示统一 | ❌ | ❌ | 当前直接暴露后端原始错误,未做统一化处理 |
|
||||
|
||||
### 用户故事
|
||||
|
||||
作为用户,我希望通过账号、短信和扫码三种方式快速登录,并在异常场景下得到明确、可恢复的提示。
|
||||
|
||||
### 功能描述
|
||||
|
||||
- 登录页采用左右分屏:左侧品牌展示,右侧认证功能区
|
||||
- 账号登录与短信登录通过表单内顶部标签页切换(仅两个标签:账号登录 / 短信登录)
|
||||
- 账号登录:`username` 或手机号 + 密码,支持明文切换
|
||||
- 短信登录:手机号 + 短信验证码
|
||||
- 扫码登录:点击输入区右上角二维码图标切换到二维码区域(独立于标签页)
|
||||
|
||||
### 交互细节
|
||||
|
||||
- 账号/短信切换:两个标签页原地切换,共享底部区域(第三方登录入口、协议勾选)
|
||||
- 扫码切换:点击二维码图标后,整个表单区(含标签页)执行 `fade + slide` 过渡替换为二维码区;二维码区右上角提供"返回账号登录"图标,点击后恢复表单
|
||||
- 二维码区包含:二维码、刷新按钮、剩余有效时间(180 秒)和状态文本
|
||||
- 扫码状态流转:等待扫描 → 待用户确认 → 确认中 → 登录成功
|
||||
- 二维码过期自动刷新并提示"二维码已更新,请重新扫码"
|
||||
- "登录"与"发送短信"前,均需通过图形验证码挑战
|
||||
|
||||
### 表单与校验规则
|
||||
|
||||
- `username`:4-20 位,字母数字下划线
|
||||
- `phone`:符合中国大陆手机号格式
|
||||
- `password`:8-20 位,必须同时包含字母和数字,拒绝常见弱口令(后端维护弱口令黑名单,如 `12345678`、`password`、`qwerty123`)
|
||||
- `sms_code`:6 位数字,5 分钟有效
|
||||
- 密码强度指示(注册和修改密码场景显示):弱 = 仅满足最低长度和字符要求;中 = 含大小写混合或特殊字符;强 = 12 位以上且含大小写 + 数字 + 特殊字符
|
||||
- 登录错误提示统一为"账号或密码错误"或"账号或校验信息不匹配"
|
||||
|
||||
### 错误与加载态
|
||||
|
||||
- 提交按钮进入 Loading 态,防重复点击
|
||||
- 网络超时:提示"网络异常,请稍后重试"
|
||||
- 验证码过期:提示并自动刷新验证码挑战
|
||||
- 风控限流:返回剩余重试时间,并提示稍后再试
|
||||
- 账号锁定:提示锁定时长和解锁路径(短信解锁或等待)
|
||||
|
||||
### 登录成功跳转
|
||||
|
||||
- 如果用户登录前访问了需认证的页面(被拦截跳转到登录页),登录成功后自动跳回该页面
|
||||
- 前端通过 URL query 参数 `redirect` 携带原始路径,登录成功后读取并跳转
|
||||
- `redirect` 值必须为站内相对路径,禁止跳转到外部 URL(防开放重定向攻击)
|
||||
- 无 `redirect` 参数时默认跳转首页
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [x] 账号密码登录可认证并跳转首页
|
||||
- [x] 账号/短信标签页可正常切换,共享底部区域
|
||||
- [x] 登录成功后跳回 `redirect` 指定的站内页面
|
||||
- [x] 密码输入支持明文/密文切换
|
||||
- [x] 提交按钮有 Loading 态
|
||||
- [ ] 短信登录对接后端 API(当前为占位)
|
||||
- [ ] 扫码登录功能完整实现
|
||||
- [x] 登录/发送短信均经过图形验证码验证
|
||||
- [ ] 二维码支持倒计时与自动刷新
|
||||
- [ ] 错误提示统一化处理(不暴露后端原始错误)
|
||||
|
||||
---
|
||||
|
||||
## F1.2 第三方授权登录(P1) — 🟠 仅入口 UI
|
||||
|
||||
### 开发现状
|
||||
|
||||
| 子功能 | 前端 | 后端 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| 微信/QQ 登录入口展示 | ✅ | — | `ThirdPartyLogin.vue` 已渲染图标 |
|
||||
| OAuth 跳转 | ❌ | ❌ | 按钮无点击事件 |
|
||||
| 回调处理 | ❌ | ❌ | 无回调页面和逻辑 |
|
||||
| 手机号绑定引导 | ❌ | ❌ | |
|
||||
|
||||
### 用户故事
|
||||
|
||||
作为用户,我希望使用微信或 QQ 一键登录,避免重复注册。
|
||||
|
||||
### 功能描述
|
||||
|
||||
- 登录区底部展示微信、QQ 登录入口
|
||||
- 首次授权自动创建账号并建立绑定,后续直接登录
|
||||
|
||||
### 交互细节
|
||||
|
||||
- OAuth 流程:跳转授权页 → 授权 → 回调 → 绑定或登录 → 跳转原页面
|
||||
- 未绑定用户引导补充手机号(若第三方未提供可靠手机号)
|
||||
- 已绑定用户直接签发本系统会话 Token
|
||||
|
||||
### 数据约定
|
||||
|
||||
- 首次 OAuth 创建账号时,`users.source` 设为对应 provider(`wechat` / `qq`)
|
||||
- 手机号冲突处理:若 OAuth 返回的手机号已被其他本地账号绑定,提示用户"该手机号已注册,请用该手机号登录后在个人中心绑定",不自动合并
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [x] 微信/QQ 登录入口 UI 已展示
|
||||
- [ ] 微信 OAuth 跳转和回调流程完整可用
|
||||
- [ ] QQ OAuth 跳转和回调流程完整可用
|
||||
- [ ] 已绑定用户直接登录,未绑定用户进入绑定流程
|
||||
|
||||
---
|
||||
|
||||
## F1.3 账户辅助功能(P0) — 🟠 部分完成
|
||||
|
||||
### 开发现状
|
||||
|
||||
| 子功能 | 前端 | 后端 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| 自动登录勾选 UI | ✅ | ❌ | `LoginTabPanel.vue` 勾选框已实现,但未真正影响会话有效期 |
|
||||
| 忘记密码表单 UI | ✅ | ❌ | `ForgotPanel.vue` 表单已实现,含用户名/手机号/验证码/新密码字段 |
|
||||
| 忘记密码提交逻辑 | ❌ | ❌ | `useLoginForms.handleForgot` 为 `setTimeout` 模拟,无 API 调用 |
|
||||
| 验证码发送 | ❌ | ❌ | `sendCode` 仅 Toast 提示,无真实发送 |
|
||||
|
||||
### 用户故事
|
||||
|
||||
作为用户,我希望系统记住登录状态并在忘记密码时快速恢复访问。
|
||||
|
||||
### 功能描述
|
||||
|
||||
- 自动登录:勾选后延长会话有效期(30 天)
|
||||
- 忘记密码:账号/手机号 + 短信验证码 + 新密码重置
|
||||
|
||||
### 找回密码流程
|
||||
|
||||
1. 输入账号或手机号(至少填一项;OAuth 用户可能无 username,此时仅填手机号即可)
|
||||
2. 验证关联手机号并发送短信验证码
|
||||
3. 校验验证码后设置新密码并确认
|
||||
4. 重置成功后跳转登录页
|
||||
|
||||
### 安全规则
|
||||
|
||||
- 错误提示统一为"账号或校验信息不匹配",避免账号枚举
|
||||
- 新密码不可与最近一次密码相同
|
||||
- 重置成功后主动使历史会话失效
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [x] 自动登录勾选 UI 可用
|
||||
- [x] 忘记密码表单 UI 完整(含用户名、手机号、验证码、新密码字段)
|
||||
- [ ] 自动登录勾选后真正延长会话有效期
|
||||
- [ ] 忘记密码对接后端 API
|
||||
- [ ] 短信验证码发送对接后端 API
|
||||
- [ ] 重置密码后旧会话失效
|
||||
|
||||
---
|
||||
|
||||
## F1.4 全局主题切换(P1) — 🟢 已完成
|
||||
|
||||
### 开发现状
|
||||
|
||||
| 子功能 | 前端 | 后端 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| 主题切换图标 | ✅ | — | 登录页已实现切换按钮 |
|
||||
| 深色/浅色双主题 | ✅ | — | 使用 `@vueuse/core` 的 `useDark` + `useToggle` |
|
||||
| 偏好持久化 | ✅ | — | `useDark` 自动持久化到 `localStorage` |
|
||||
| 系统偏好跟随 | ✅ | — | `useDark` 默认跟随 `prefers-color-scheme` |
|
||||
|
||||
### 用户故事
|
||||
|
||||
作为用户,我希望在深色模式和浅色模式间切换,以适配不同使用环境。
|
||||
|
||||
### 功能描述
|
||||
|
||||
- 顶部导航栏提供主题切换图标
|
||||
- 支持浅色/深色两套主题,并在本地持久化
|
||||
- 支持 `prefers-color-scheme` 初次自动跟随
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [x] 切换后全局 UI 立即生效
|
||||
- [x] 刷新页面后主题偏好保持
|
||||
- [ ] 核心页面在深色模式下可读性正常(需全页面回归验证)
|
||||
|
||||
---
|
||||
|
||||
## F1.5 简易个人中心(P1) — 🟠 仅基础展示
|
||||
|
||||
### 开发现状
|
||||
|
||||
| 子功能 | 前端 | 后端 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| 导航栏用户信息展示 | ✅ | ✅ | `AppNavbar.vue` 展示昵称或"用户",已登录/未登录切换正常 |
|
||||
| 下拉菜单 | ❌ | — | 无下拉菜单组件,无个人信息/修改密码/绑定管理入口 |
|
||||
| 退出登录 | ❌ | ❌ | 导航栏无退出入口,`userStore.logout` 方法已存在但未绑定到 UI |
|
||||
| 账号注销 | ❌ | ❌ | |
|
||||
|
||||
### 用户故事
|
||||
|
||||
作为已登录用户,我希望查看自身信息并管理账户安全相关操作。
|
||||
|
||||
### 功能描述
|
||||
|
||||
- 顶部导航右侧展示头像、昵称、角色标签
|
||||
- 下拉菜单:个人信息、修改密码、绑定管理、退出登录
|
||||
- 支持账号注销入口(7 天冷静期,可撤销)
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [x] 登录态展示用户昵称,未登录态展示"登录"链接
|
||||
- [ ] 导航栏增加下拉菜单(个人信息、修改密码、绑定管理、退出登录)
|
||||
- [ ] 退出登录功能可用
|
||||
- [ ] 账号注销流程含冷静期提示与撤销能力
|
||||
|
||||
---
|
||||
|
||||
## F1.6 用户注册(P0) — 🟠 仅 UI 框架
|
||||
|
||||
### 开发现状
|
||||
|
||||
| 子功能 | 前端 | 后端 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| 注册表单 UI | ✅ | — | `RegisterPanel.vue` 已实现(用户名、手机号、验证码、密码、确认密码) |
|
||||
| 昵称字段 | ❌ | — | 当前注册表单缺少昵称输入项 |
|
||||
| 密码强度指示 | ❌ | — | 未实现 |
|
||||
| 协议勾选 | ❌ | — | 未实现 |
|
||||
| 注册提交逻辑 | ❌ | ❌ | `useLoginForms.handleRegister` 为 `setTimeout` 模拟,无 API 调用 |
|
||||
| 验证码发送 | ❌ | ❌ | 仅 Toast,无真实发送 |
|
||||
| `auth.ts` 注册 API | ❌ | ❌ | 未定义 `register` 方法 |
|
||||
|
||||
### 用户故事
|
||||
|
||||
作为新用户,我希望通过账号注册快速完成开户并进入系统。
|
||||
|
||||
### 功能描述
|
||||
|
||||
- 注册字段:账号(username)、昵称(nickname)、手机号、短信验证码、密码、确认密码
|
||||
- 昵称为选填,留空时系统自动生成默认昵称(如"用户\_" + 随机 6 位字符)
|
||||
- 页面实时显示密码强度(弱/中/强)
|
||||
- 注册前必须确认协议(默认未勾选)
|
||||
|
||||
### 校验规则
|
||||
|
||||
- 账号唯一,手机号唯一
|
||||
- 账号不允许使用系统保留词(`admin`、`system`、`root`、`test`、`api`、`null`、`undefined` 等),后端维护保留词列表
|
||||
- 账号须通过敏感词过滤,拒绝包含违规内容的用户名
|
||||
- 昵称长度限制 2-30 字符,同样需通过敏感词过滤
|
||||
- 密码复杂度:8-20 位,必须同时包含字母和数字,拒绝常见弱口令(如 `12345678`、`password`、`qwerty123`),后端维护弱口令黑名单
|
||||
- 短信验证码 5 分钟有效,错误次数达到阈值后触发风控
|
||||
|
||||
### 数据约定
|
||||
|
||||
- 注册创建账号时,`users.source` 设为 `local`
|
||||
- `users.user_type` 注册时固定为 `user`,管理员仅由后台创建
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [x] 注册表单基础 UI 已实现(用户名、手机号、验证码、密码、确认密码)
|
||||
- [ ] 注册表单补充昵称字段
|
||||
- [ ] 密码强度实时指示
|
||||
- [ ] 协议勾选组件及拦截逻辑
|
||||
- [ ] 注册对接后端 API(`authApi.register`)
|
||||
- [ ] 短信验证码对接后端 API
|
||||
- [ ] 系统保留词和敏感词被拒绝并给出明确提示
|
||||
- [ ] 协议未同意时不可提交注册
|
||||
|
||||
---
|
||||
|
||||
## F1.7 安全管理后台(P1) — ⚪ 待开发
|
||||
|
||||
### 功能描述
|
||||
|
||||
- 黑名单管理:IP、设备指纹、账号维度封禁/解封
|
||||
- 登录日志:时间、IP、设备、登录类型、成功/失败、风控命中原因
|
||||
- 账号锁定记录:支持检索与手动解锁
|
||||
- 风控策略配置:阈值、封禁时长、白名单
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [ ] 可查看和检索登录审计日志
|
||||
- [ ] 可配置限流和锁定策略
|
||||
- [ ] 支持手动解封和白名单管理
|
||||
|
||||
---
|
||||
|
||||
## F1.8 企业 SSO 集成(P1) — ⚪ 待开发
|
||||
|
||||
### 用户故事
|
||||
|
||||
作为企业内部用户,我希望从企业数字化平台无感知进入本系统。
|
||||
|
||||
### 设计原则
|
||||
|
||||
- 本系统保持独立账号池和会话体系
|
||||
- 企业平台作为外部 IdP,通过桥接流程完成认证
|
||||
- 协议优先级:OIDC/OAuth2(首选)> 自定义签名票据(兜底)
|
||||
|
||||
### 账号映射策略
|
||||
|
||||
1. 优先按 `enterprise_user_id` 绑定本地账号
|
||||
2. 未绑定时按手机号/邮箱进行二次确认绑定
|
||||
3. 仍无匹配账号则创建外部来源账号并标记来源
|
||||
|
||||
### 直达登录要求
|
||||
|
||||
- 支持企业平台深链:`state` + `nonce` + 回调白名单
|
||||
- 凭据短时效、一次性使用,防重放
|
||||
- SSO 登录失败可回退本地登录
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [ ] 企业用户可从外部平台直达登录
|
||||
- [ ] 首次登录自动完成绑定或创建
|
||||
- [ ] 企业平台不可用时,本地登录路径不受影响
|
||||
|
||||
---
|
||||
|
||||
## F1.9 多端会话管理(P2) — ⚪ 待开发
|
||||
|
||||
### 功能描述
|
||||
|
||||
- 个人中心展示当前账号在线会话列表(设备、地区、最近活跃时间)
|
||||
- 支持手动踢出指定会话
|
||||
- 系统可配置是否允许多端同时在线(单点挤占)
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [ ] 可查看在线会话并识别当前设备
|
||||
- [ ] 支持踢出其他设备并即时生效
|
||||
- [ ] 单点挤占模式下,新登录会使旧会话失效
|
||||
|
||||
---
|
||||
|
||||
## 图形验证码与协议合规 — ⚪ 待开发
|
||||
|
||||
### 图形验证码规范
|
||||
|
||||
- 挑战类型:拼图滑块(slider puzzle)
|
||||
- 触发点:登录提交、发送短信、注册提交、找回密码关键步骤
|
||||
- 交互流程:
|
||||
1. 前端调用 `POST /api/auth/captcha/challenge`,后端生成随机 `target_x` 位置(60 ~ width-60),连同 `captcha_token`、`width`、`target_x` 一起返回
|
||||
2. 前端展示拼图区域:上方为带有缺口(target gap)的背景图案,缺口位于 `target_x` 处;滑块控制一个拼图块在背景上水平移动
|
||||
3. 用户拖动滑块将拼图块对齐缺口位置,松手后前端提交 `answer_x` 到 `POST /api/auth/captcha/verify`
|
||||
4. 后端校验 `abs(answer_x - target_x) <= tolerance`(tolerance = 10px),通过后标记 `captcha_verified:{token}`
|
||||
5. 验证通过后前端获得一次性 `captcha_token`(5 分钟有效),提交业务请求时携带,后端校验后立即销毁
|
||||
- 视觉反馈:拼图块接近缺口时(误差 ≤ 10px),缺口和拼图块同步变为绿色,提示用户已对齐
|
||||
- 校验数据存储于 Redis(非 MySQL),防止数据库压力
|
||||
|
||||
### 协议同意规范
|
||||
|
||||
- 登录和注册页展示"我已阅读并同意《用户协议》《隐私政策》"
|
||||
- 默认不勾选;未勾选提交时弹窗提醒并提供"一键同意并继续"
|
||||
- 服务端记录 `agree_at` 与 `agreement_version`
|
||||
|
||||
---
|
||||
|
||||
## 安全与风控策略 — ⚪ 待开发
|
||||
|
||||
### 限流规则
|
||||
|
||||
- 登录:同 IP 5 次/分钟;同账号 10 次/小时
|
||||
- 短信:同手机号 1 次/分钟,5 次/天
|
||||
- 注册:同 IP 3 次/小时
|
||||
- 密码重置:同账号 3 次/天
|
||||
|
||||
### 分级响应
|
||||
|
||||
- L1 轻度异常:提升验证码难度
|
||||
- L2 中度异常:账号/IP/设备短期限流
|
||||
- L3 重度异常:冻结高风险动作并触发人机复核
|
||||
- L4 确认恶意:自动拉黑并进入观察名单
|
||||
|
||||
### 防攻击要求
|
||||
|
||||
- 防撞库:统一错误提示,不暴露账号存在性
|
||||
- 防暴力破解:连续 5 次密码错误锁定 30 分钟
|
||||
- 防重放:SSO 一次性状态值 + 回调校验
|
||||
- 会话安全:Access Token 2h,Refresh Token 7d,支持轮换与吊销
|
||||
|
||||
### Token 存储方案
|
||||
|
||||
- Access Token 通过 `httpOnly`、`Secure`、`SameSite=Strict` Cookie 下发,前端不可通过 JS 读取,防止 XSS 窃取
|
||||
- Refresh Token 同样存储在 `httpOnly` Cookie 中,路径限制为 `/api/auth/refresh`
|
||||
- 禁止将 Token 存储在 `localStorage` 或 `sessionStorage`
|
||||
|
||||
> **当前实现差异**:`userStore` 当前将 Token 存储在 `localStorage` 中,需在后端 Cookie 方案就绪后迁移。
|
||||
|
||||
### 退出登录范围
|
||||
|
||||
- 常规退出(F1.5 下拉菜单"退出登录"):仅使当前设备的 Access Token 和 Refresh Token 失效
|
||||
- 全部退出(F1.9 会话管理"退出所有设备"):使账号下所有会话 Token 失效
|
||||
- 密码重置(F1.3)和账号锁定触发时:自动使所有会话 Token 失效
|
||||
|
||||
---
|
||||
|
||||
## 已开发代码索引
|
||||
|
||||
> 供研发快速定位已有实现,避免重复开发。
|
||||
|
||||
| 文件路径 | 职责 |
|
||||
|----------|------|
|
||||
| `src/views/login/LoginView.vue` | 登录主页面:左右分屏、视图切换(login/register/forgot)、主题切换 |
|
||||
| `src/views/login/components/LoginTabPanel.vue` | 账号登录 + 短信登录标签页、自动登录勾选 |
|
||||
| `src/views/login/components/RegisterPanel.vue` | 注册表单 UI |
|
||||
| `src/views/login/components/ForgotPanel.vue` | 忘记密码表单 UI |
|
||||
| `src/views/login/components/ThirdPartyLogin.vue` | 微信/QQ 第三方登录入口 UI |
|
||||
| `src/views/login/components/LoginBanner.vue` | 左侧品牌展示区 |
|
||||
| `src/views/login/composables/useLoginForms.ts` | 表单状态和提交逻辑(账号登录已联调,其余为占位) |
|
||||
| `src/components/ui/AppInput.vue` | 通用输入框(含密码明文切换) |
|
||||
| `src/components/auth/useCaptchaSlider.ts` | 拼图滑块验证码核心逻辑(拖拽、对齐检测、验证提交) |
|
||||
| `src/api/auth.ts` | 认证 API(login / logout / refresh / getProfile / updateProfile / captcha) |
|
||||
| `src/stores/user.ts` | 用户状态管理(token / userInfo / login / logout) |
|
||||
| `src/router/index.ts` | 路由守卫(未登录 → /login?redirect=xxx) |
|
||||
| `src/components/layout/AppNavbar.vue` | 导航栏(登录态展示昵称,未登录展示登录链接) |
|
||||
|
||||
---
|
||||
|
||||
## 分阶段落地建议
|
||||
|
||||
- Phase A(P0):短信登录对接、注册对接、忘记密码对接、图形验证码、协议勾选、注册补昵称/密码强度
|
||||
- Phase B(P0):企业 SSO 桥接、账号映射与直达登录
|
||||
- Phase C(P0/P1):风控引擎、自动拉黑、安全后台、Token 存储迁移至 httpOnly Cookie
|
||||
- Phase D(P1):个人中心下拉菜单、退出登录、OAuth 对接、多端会话管理、监控告警
|
||||
|
||||
---
|
||||
|
||||
## 验收指标
|
||||
|
||||
- 正常用户登录成功率 ≥ 98%
|
||||
- 短信接口恶意触发量按周下降
|
||||
- 企业用户无感登录成功率持续提升且不影响外部用户路径
|
||||
- 协议同意和风控决策具备可审计追溯能力
|
||||
|
||||
---
|
||||
|
||||
*最后更新: 2026-03-04*
|
||||
303
docs/specs/F2-首页.md
Normal file
303
docs/specs/F2-首页.md
Normal file
@@ -0,0 +1,303 @@
|
||||
# F2 首页
|
||||
|
||||
> **涉及端**:用户端(`Case-Database-Frontend-user`)+ 后端(`Case-Database-Backend`)
|
||||
>
|
||||
> **关联文档**:
|
||||
> - API 契约:[api-contracts.md §2.2 用户端案例](../architecture/api-contracts.md) / [§2.4 用户端内容](../architecture/api-contracts.md)
|
||||
> - 数据模型:[data-model.md §4.2 案例核心域](../architecture/data-model.md) / [§4.4 运营内容域](../architecture/data-model.md)
|
||||
> - UI 规范:[ui-specs-user.md](../guides/ui-specs-user.md)
|
||||
> - 参考原型:`docs/reference/首页.html`
|
||||
|
||||
---
|
||||
|
||||
## 功能清单
|
||||
|
||||
| 编号 | 功能 | 优先级 | 状态 |
|
||||
|------|------|--------|------|
|
||||
| F2.1 | 顶部导航与分类频道 | P0 | 🟢 已实现 |
|
||||
| F2.2 | 全局模糊搜索 | P0 | 🟡 部分实现 |
|
||||
| F2.3 | Hero 焦点推荐位 | P0 | 🟢 已实现 |
|
||||
| F2.4 | 多维条件过滤与收藏夹 | P0 | 🟡 部分实现 |
|
||||
| F2.5 | 富数据项目卡片 | P0 | 🟢 已实现 |
|
||||
| F2.6 | 底部全局模块 | P2 | ⚪ 待开发 |
|
||||
|
||||
> **状态说明**:🟢 已实现 = 前端 UI 与核心交互已完成;🟡 部分实现 = UI 框架已有,部分子功能待开发;⚪ 待开发 = 尚未启动。
|
||||
|
||||
---
|
||||
|
||||
## F2.1 顶部导航与分类频道(P0 · 🟢 已实现)
|
||||
|
||||
### 用户故事
|
||||
|
||||
作为用户,我希望通过分类频道快速定位感兴趣的案例类型,并在右上角管理个人账户和主题偏好。
|
||||
|
||||
### 功能描述
|
||||
|
||||
- 顶部固定导航栏:Logo + 分类频道 + 搜索 + 用户区
|
||||
- 分类频道标签:全部 / 别墅 / 室内 / 民宿 / 景观 / 专题 / 设计师
|
||||
- 切换频道后内容区实时过滤更新
|
||||
- **用户区(右上角)**:
|
||||
- 未登录:显示「登录」按钮
|
||||
- 已登录:显示用户头像,点击展开下拉菜单(个人信息 / 我的收藏 / 退出登录)
|
||||
- 主题切换按钮:暗色 ↔ 亮色模式切换,偏好持久化至 `localStorage`
|
||||
- 登录成功后默认跳转至首页
|
||||
|
||||
### 交互细节
|
||||
|
||||
- **导航栏滚动行为**:初始透明背景,页面滚动超过 80px 后过渡为实色背景(带阴影)
|
||||
- **频道切换过渡动效**:当前激活频道下方显示指示线,切换时指示线平滑滑动
|
||||
- **主题切换**:图标在 `SunIcon`(亮色)与 `MoonIcon`(暗色)之间切换,带旋转过渡动效
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [x] 频道切换时内容区无刷新更新(SPA 路由)
|
||||
- [x] 当前激活频道高亮显示,带下方指示线
|
||||
- [x] 导航栏滚动时保持固定(sticky),透明 → 实色背景过渡
|
||||
- [x] 频道标签顺序:全部 / 别墅 / 室内 / 民宿 / 景观 / 专题 / 设计师
|
||||
- [x] 右上角未登录显示登录按钮,已登录显示头像及下拉菜单
|
||||
- [x] 暗色 / 亮色主题可切换,偏好持久化
|
||||
|
||||
---
|
||||
|
||||
## F2.2 全局模糊搜索(P0 · 🟡 部分实现)
|
||||
|
||||
### 用户故事
|
||||
|
||||
作为用户,我希望通过关键词快速找到目标案例,以便提高检索效率。
|
||||
|
||||
### 功能描述
|
||||
|
||||
- 全局搜索框,支持搜索:项目名称、项目编号、建筑师姓名
|
||||
- 搜索框位置:导航栏右侧(桌面端)
|
||||
- 搜索结果实时展示联想下拉,或回车跳转搜索结果页
|
||||
|
||||
### 交互细节
|
||||
|
||||
- **实时联想下拉**:输入关键词后 300ms 防抖触发搜索请求,下拉面板最多展示 8 条匹配结果,匹配关键词高亮
|
||||
- **搜索历史记录**:持久化至 `localStorage`,保留最近 10 条搜索词,支持一键清除全部历史
|
||||
- **搜索结果页**:回车后跳转至搜索结果页,结果按相关度排序,支持分页
|
||||
- **空结果**:展示友好的空状态插图 + 推荐搜索词
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [x] 搜索框在导航栏中可见
|
||||
- [ ] 输入关键词后 300ms 防抖触发联想下拉
|
||||
- [ ] 联想下拉最多展示 8 条,匹配关键词高亮
|
||||
- [ ] 搜索历史持久化,支持清除
|
||||
- [ ] 空结果展示空状态插图与推荐词
|
||||
|
||||
---
|
||||
|
||||
## F2.3 Hero 焦点推荐位(P0 · 🟢 已实现)
|
||||
|
||||
### 用户故事
|
||||
|
||||
作为运营,我希望在管理端自定义首页大图的内容(图片、标题、描述等),以便灵活引导用户注意力。
|
||||
|
||||
### 功能描述
|
||||
|
||||
首页顶部全宽大图轮播区域,支持两种内容源(管理端创建轮播条目时选择):
|
||||
|
||||
- **`image`(单图模式)**:上传背景图 + 自定义标题 / 描述 / 标签文字 / 跳转链接
|
||||
- **`topic`(专题模式)**:选择已有专题,自动继承专题封面、标题、描述,点击跳转专题详情页
|
||||
|
||||
#### 自定义字段(均由管理端配置,前端不硬编码)
|
||||
|
||||
| 字段 | 说明 | 示例 |
|
||||
|------|------|------|
|
||||
| `label` | 左上角标签文字 | "精选项目" / "本周专题" |
|
||||
| `title` | 大标题 | "云端墅 — 现代都市别墅的极致诠释" |
|
||||
| `description` | 描述摘要 | "三层框架结构,340㎡ 全功能空间" |
|
||||
| `cta_text` | 行动按钮文字 | "阅读全文" / "查看专题" |
|
||||
| `link_url` | 点击跳转地址 | "/cases/88" / "/topics/3" |
|
||||
| `image` | 背景图片 URL | — |
|
||||
|
||||
#### 轮播行为
|
||||
|
||||
- 自动播放,间隔 5s,鼠标 hover 时暂停自动播放
|
||||
- 手动切换:左右箭头按钮 + 底部圆点指示器
|
||||
- 过渡动效:淡入淡出 + 轻微水平位移
|
||||
- 背景图片带灰度滤镜处理
|
||||
|
||||
### 交互细节
|
||||
|
||||
- **轮播指示器**:底部圆点,当前项高亮,点击可跳转到对应条目
|
||||
- **左右箭头**:默认隐藏,鼠标 hover 轮播区域时显示,点击切换上/下一条
|
||||
- **骨架屏**:轮播数据加载前显示骨架屏占位,避免布局抖动
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [x] 轮播支持自动播放(5s 间隔)与手动切换
|
||||
- [x] 管理端配置的标题 / 描述 / 标签在前端实时呈现
|
||||
- [x] `image` 类型条目支持自定义跳转任意内链
|
||||
- [x] `topic` 类型条目点击后跳转专题详情页
|
||||
- [x] 热门标签点击后跳转至对应筛选结果
|
||||
|
||||
---
|
||||
|
||||
## F2.4 多维条件过滤与收藏夹(P0 · 🟡 部分实现)
|
||||
|
||||
### 用户故事
|
||||
|
||||
作为设计师,我希望通过多个维度交叉筛选案例,或快速查看我收藏的项目,以便精准定位参考案例。
|
||||
|
||||
### 功能描述
|
||||
|
||||
- **快捷风格 Tab**(🟢 已实现):横向风格标签切换(全部风格 / 现代 / 中式 / 新中式 / 欧式 / 田园 / 其它)
|
||||
- **高级筛选器**(🟢 已实现):下拉面板,支持多维度交叉筛选(面积范围、造价范围、层数、结构类型等)
|
||||
- **视图切换**(🟢 已实现):网格视图(Grid)与列表视图(List)双模式切换
|
||||
- **收藏夹入口**(⚪ 待开发):快捷筛选"我收藏的"案例
|
||||
|
||||
### 收藏夹交互流程
|
||||
|
||||
1. 点击筛选栏中的「收藏夹」按钮 → 卡片列表切换为仅展示当前用户已收藏的案例
|
||||
2. 再次点击「收藏夹」按钮或刷新页面 → 退出收藏夹模式,恢复全量列表
|
||||
3. 收藏夹模式激活时,按钮高亮显示以区分状态
|
||||
4. 未登录用户点击「收藏夹」 → 弹出登录引导弹窗
|
||||
5. 收藏夹模式下无收藏内容 → 显示空状态引导("去发现喜欢的案例")
|
||||
|
||||
### 交互细节
|
||||
|
||||
- **筛选条件 URL 同步**:所有筛选参数(`category`、`style`、`keyword`、`favorites` 等)写入 URL query string,支持浏览器前进/后退和分享链接
|
||||
- **已选条件展示**:以「标签胶囊」形式显示在筛选栏下方,支持单项点击清除或一键全部重置
|
||||
- **筛选面板动效**:展开/折叠使用从顶部向下滑入的过渡
|
||||
- **筛选变更后的刷新策略**:清空现有卡片,重新加载首屏数据(非追加)
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [x] 风格 Tab 切换实时过滤卡片内容
|
||||
- [x] 高级筛选器支持多条件叠加且可一键重置
|
||||
- [x] 视图切换(网格 / 列表)保持筛选状态不丢失
|
||||
- [ ] 收藏夹按钮点击后切换到已收藏内容,再次点击或刷新退出
|
||||
- [ ] 收藏夹按钮激活时高亮区分
|
||||
- [ ] 未登录用户点击收藏夹弹出登录引导
|
||||
- [ ] 筛选参数同步至 URL query string
|
||||
|
||||
---
|
||||
|
||||
## F2.5 富数据项目卡片(P0 · 🟢 已实现)
|
||||
|
||||
### 用户故事
|
||||
|
||||
作为用户,我希望在卡片上一眼获取案例的核心参数,并通过悬浮操作快速收藏或点赞。
|
||||
|
||||
### F2.5a 卡片结构与字段自定义
|
||||
|
||||
- 卡片封面图(支持 Hover 缩放动效)
|
||||
- 基础信息:项目名称(`title`)、项目编号(`code`)
|
||||
- 业务标签:建筑类型角标(`category`,如别墅/民宿等)、特色标签(`tags`,如落地窗、工业风等)
|
||||
- 状态标识:精选徽章(金色角标,由 `is_featured` 字段驱动)
|
||||
- **核心参数网格(6 项外显)**:在管理端上传案例时,运营人员可自定义选择展示哪 6 项参数
|
||||
- 字段选项池来自案例的 `dimensions` 数据(约 15+ 个维度字段:开间、进深、占地面积、建筑总面积、户型布局、预估造价、结构类型、设计师、层数等)
|
||||
- 标题、标签、角标均读取案例对应字段,前端不硬编码
|
||||
|
||||
### F2.5b 卡片加载策略(动态加载)
|
||||
|
||||
- **首屏加载**:6 行 × 当前视图列数
|
||||
- 网格模式(3 列)= 18 条
|
||||
- 列表模式 = 6 条
|
||||
- **触底追加加载**:用户向下滚动触底时,每次追加 2 行
|
||||
- 网格模式 = 追加 6 条
|
||||
- 列表模式 = 追加 2 条
|
||||
- **加载中状态**:显示骨架屏(Skeleton UI)占位
|
||||
- **加载完毕**:全部数据加载完成后显示「已加载全部内容」底部提示
|
||||
- 不使用传统分页器,采用无限滚动 + 触底加载模式
|
||||
|
||||
### F2.5c Hover 悬浮操作层
|
||||
|
||||
- 鼠标移入卡片封面图区域 → 图片上方叠加半透明操作层,显示:
|
||||
- **收藏按钮**(心形图标):未收藏时空心,已收藏时实心红色
|
||||
- **点赞按钮**(拇指图标):显示当前点赞数
|
||||
- 鼠标移出 → 操作层淡出消失
|
||||
- **已收藏卡片的常驻标识**:封面右上角始终显示实心心形徽标(不依赖 hover 状态),方便用户一眼识别已收藏内容
|
||||
|
||||
### F2.5d 登录拦截与跳转
|
||||
|
||||
- 未登录用户点击收藏 / 点赞按钮 → 弹出登录引导弹窗
|
||||
- 登录成功后自动重定向回首页(通过 `redirect` 参数)
|
||||
- 点击卡片本体 → 跳转至户型详情页(无需登录)
|
||||
|
||||
### 交互细节
|
||||
|
||||
- **卡片 Hover**:封面图放大至 1.05 倍,卡片阴影加深,过渡时长 300ms
|
||||
- **骨架屏**:卡片加载时显示与真实卡片等尺寸的骨架占位,避免布局抖动
|
||||
- **图片懒加载**:封面图使用 `loading="lazy"` 属性,优先使用 WebP 格式
|
||||
- **视图一致性**:网格视图与列表视图展示相同的字段和操作按钮
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [x] 卡片 Hover 时封面图平滑缩放
|
||||
- [x] 精选徽章仅对 `is_featured=true` 的案例显示
|
||||
- [x] 点击卡片跳转至户型详情页
|
||||
- [x] 支持网格视图(3 列)与列表视图
|
||||
- [x] 卡片底部 6 个参数字段由管理端自定义配置
|
||||
- [x] Hover 时显示收藏/点赞悬浮按钮,移出时消失
|
||||
- [x] 已收藏卡片封面右上角常驻心形徽标
|
||||
- [x] 首屏加载 6 行,触底追加 2 行,非一次全部加载
|
||||
- [ ] 未登录用户点击收藏/点赞弹出登录引导
|
||||
|
||||
---
|
||||
|
||||
## F2.6 底部全局模块(P2)
|
||||
|
||||
### 用户故事
|
||||
|
||||
作为用户,我希望在页面底部获取平台信息和快捷入口。
|
||||
|
||||
### 功能描述
|
||||
|
||||
- 订阅资讯模块:邮箱输入 + 订阅按钮
|
||||
- 分类快速链接:按建筑类型分组的快捷导航
|
||||
- 版权与协议说明
|
||||
|
||||
### 交互细节
|
||||
|
||||
<!-- TODO: 补充以下内容 -->
|
||||
<!-- - 订阅成功/失败的反馈提示 -->
|
||||
<!-- - 邮箱重复订阅的处理 -->
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [ ] 邮箱格式校验通过后可提交订阅
|
||||
- [ ] 分类链接跳转至对应频道页
|
||||
|
||||
---
|
||||
|
||||
## 补充说明
|
||||
|
||||
### 暗色模式持久化
|
||||
|
||||
- 主题偏好存储至 `localStorage` key `theme`,值为 `light` 或 `dark`
|
||||
- 页面初始化时读取 `localStorage`,无记录则跟随系统偏好(`prefers-color-scheme`)
|
||||
- 切换后立即生效,无需刷新页面
|
||||
|
||||
### 骨架屏(Skeleton UI)
|
||||
|
||||
- **Hero 轮播区**:数据加载前显示与轮播等高的灰色骨架占位
|
||||
- **卡片列表区**:加载时显示与真实卡片等尺寸的骨架卡片(含图片区 + 文字行占位)
|
||||
- 骨架屏使用 `animate-pulse` 动画,视觉上提示加载中状态
|
||||
- 避免因数据加载导致的布局累积偏移(CLS)
|
||||
|
||||
### 图片懒加载
|
||||
|
||||
- 卡片封面图统一使用 `loading="lazy"` 原生懒加载
|
||||
- 图片优先使用 WebP 格式,对不支持的浏览器回退到 JPEG
|
||||
- Hero 轮播首屏图片不懒加载(`loading="eager"`),确保首屏加载速度
|
||||
|
||||
### 筛选条件 URL 同步
|
||||
|
||||
- 所有筛选参数(`category`、`style`、`keyword`、`favorites`、`view` 等)写入 URL query string
|
||||
- 用户可通过浏览器前进/后退还原筛选状态
|
||||
- 分享 URL 后,其他用户打开可直接看到相同的筛选结果
|
||||
|
||||
### 空状态
|
||||
|
||||
| 场景 | 展示内容 |
|
||||
|------|----------|
|
||||
| 搜索无结果 | 空状态插图 + "未找到相关案例,试试其他关键词" |
|
||||
| 收藏夹为空 | 空状态插图 + "还没有收藏,去发现喜欢的案例" + 跳转首页按钮 |
|
||||
| 筛选无结果 | 空状态插图 + "当前条件无匹配结果,试试调整筛选" + 重置筛选按钮 |
|
||||
|
||||
---
|
||||
|
||||
*最后更新: 2026-03-02*
|
||||
255
docs/specs/F3-案例详情.md
Normal file
255
docs/specs/F3-案例详情.md
Normal file
@@ -0,0 +1,255 @@
|
||||
# F3 标准化案例资产详情引擎
|
||||
|
||||
> **涉及端**:用户端(`Case-Database-Frontend-user`)+ 后端(`Case-Database-Backend`)
|
||||
>
|
||||
> **关联文档**:
|
||||
> - API 契约:[api-contracts.md §2.2 用户端案例](../architecture/api-contracts.md)(案例详情、评论、文件、相关推荐)
|
||||
> - 数据模型:[data-model.md §4.2 案例核心域](../architecture/data-model.md) / [§4.3 设计师域](../architecture/data-model.md) / [§4.5 用户互动域](../architecture/data-model.md)
|
||||
> - UI 规范:[ui-specs-user.md](../guides/ui-specs-user.md)
|
||||
> - 参考原型:`docs/reference/户型详情页.html`
|
||||
|
||||
---
|
||||
|
||||
## 功能清单
|
||||
|
||||
| 编号 | 功能 | 优先级 | 状态 |
|
||||
|------|------|--------|------|
|
||||
| F3.1 | 面包屑导航 | P0 | ⚪ 待开发 |
|
||||
| F3.2 | 富媒体多维图库 | P0 | ⚪ 待开发 |
|
||||
| F3.3 | 专业级参数看板 | P0 | ⚪ 待开发 |
|
||||
| F3.4 | 侧边栏核心信息聚合 | P0 | ⚪ 待开发 |
|
||||
| F3.5 | 设计理念与主创团队 | P1 | ⚪ 待开发 |
|
||||
| F3.6 | 数字资产分发中心 | P0 | ⚪ 待开发 |
|
||||
| F3.7 | 互动与裂变闭环 | P1 | ⚪ 待开发 |
|
||||
| F3.8 | 智能推荐 | P2 | ⚪ 待开发 |
|
||||
|
||||
---
|
||||
|
||||
## F3.1 面包屑导航(P0)
|
||||
|
||||
### 用户故事
|
||||
|
||||
作为用户,我希望通过面包屑快速回到上一层级。
|
||||
|
||||
### 功能描述
|
||||
|
||||
- 页面顶部路径导航:首页 > 分类 > 当前项目名称
|
||||
- 支持点击任一层级跳转
|
||||
|
||||
### 交互细节
|
||||
|
||||
<!-- TODO: 补充以下内容 -->
|
||||
<!-- - 面包屑在不同来源页面的路径生成逻辑(从首页 vs 从搜索结果) -->
|
||||
<!-- - 长标题的截断处理 -->
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [ ] 面包屑路径正确反映当前导航层级
|
||||
- [ ] 各层级链接可正常跳转
|
||||
|
||||
---
|
||||
|
||||
## F3.2 富媒体多维图库(P0)
|
||||
|
||||
### 用户故事
|
||||
|
||||
作为用户,我希望从多个视角浏览案例的视觉资料,以便全面了解设计方案。
|
||||
|
||||
### 功能描述
|
||||
|
||||
- 画廊式主图展示区,支持左右切换和页码指示
|
||||
- 底部缩略图列表轮播(可横向滚动选取)
|
||||
- 快捷视图分类切换按钮:主效果图 / 平面图 / 立面图
|
||||
- 主图支持点击放大全屏浏览
|
||||
|
||||
### 交互细节
|
||||
|
||||
<!-- TODO: 补充以下内容 -->
|
||||
<!-- - 图片预加载策略(当前 + 前后各 1 张) -->
|
||||
<!-- - 全屏模式的手势操作(滑动切换、捏合缩放) -->
|
||||
<!-- - 缩略图列表的滚动对齐逻辑 -->
|
||||
<!-- - 图片加载失败的降级显示 -->
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [ ] 图片切换流畅无闪烁
|
||||
- [ ] 缩略图点击后主图同步更新
|
||||
- [ ] 视图分类切换后图库内容对应过滤
|
||||
- [ ] 大图模式支持键盘左右箭头切换
|
||||
|
||||
---
|
||||
|
||||
## F3.3 专业级参数看板(P0)
|
||||
|
||||
### 用户故事
|
||||
|
||||
作为设计师,我希望快速获取案例的详细技术参数,以便评估设计方案的可行性。
|
||||
|
||||
### 功能描述
|
||||
|
||||
5 大维度强结构化数据展示(4 列网格布局):
|
||||
|
||||
| 维度 | 参数项 |
|
||||
|------|--------|
|
||||
| 用地条件 | 面宽、进深、占地面积、采光限制、用地形状 |
|
||||
| 规模造价 | 建筑层数、造价预估、建筑总面积、卧室数量 |
|
||||
| 平面功能 | 楼梯类型、特色空间、卧室配置、休闲空间、厨卫配置 |
|
||||
| 外观风格 | 建筑风格、屋顶形式、外立面材料 |
|
||||
| 结构与性能 | 结构类型、基础类型、户型逻辑、墙体厚度、抗震设防、保温形式、屋面构造 |
|
||||
|
||||
### 交互细节
|
||||
|
||||
<!-- TODO: 补充以下内容 -->
|
||||
<!-- - 各维度的折叠/展开交互(默认全部展开 vs 逐个展开) -->
|
||||
<!-- - 参数值的格式化规则(面积带单位、造价带范围) -->
|
||||
<!-- - 响应式布局(4列 → 2列 → 1列) -->
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [ ] 5 个维度分组清晰,每组参数完整展示
|
||||
- [ ] 参数值缺失时显示"-"占位而非空白
|
||||
- [ ] 4 列网格在不同分辨率下自适应调整
|
||||
|
||||
---
|
||||
|
||||
## F3.4 侧边栏核心信息聚合(P0)
|
||||
|
||||
### 用户故事
|
||||
|
||||
作为用户,我希望在页面右侧始终看到项目的核心摘要信息。
|
||||
|
||||
### 功能描述
|
||||
|
||||
- 固定宽度侧边栏(约 440px),滚动时保持可见
|
||||
- 项目信息卡片:项目名称、项目 ID(支持一键复制)、收藏按钮
|
||||
- 核心数据速览:户型布局、建筑面积、面宽进深、结构类型、层高、采光限制
|
||||
- 预估造价醒目展示(大字号突出)
|
||||
- 操作按钮:分享、下载
|
||||
|
||||
### 交互细节
|
||||
|
||||
<!-- TODO: 补充以下内容 -->
|
||||
<!-- - Sticky 定位的起止位置(跟随区域的上下边界) -->
|
||||
<!-- - 项目 ID 复制成功的 Toast 提示 -->
|
||||
<!-- - 分享弹窗的分享渠道和链接生成逻辑 -->
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [ ] 侧边栏随页面滚动保持固定(sticky 定位)
|
||||
- [ ] 项目 ID 一键复制到剪贴板并提示成功
|
||||
- [ ] 造价数字使用醒目样式突出显示
|
||||
|
||||
---
|
||||
|
||||
## F3.5 设计理念与主创团队(P1)
|
||||
|
||||
### 用户故事
|
||||
|
||||
作为用户,我希望了解案例背后的设计思路和创作团队。
|
||||
|
||||
### 功能描述
|
||||
|
||||
- 设计理念区:富文本描述 + 核心提炼标签(风格、材质、受众)
|
||||
- 主创团队区:按专业分列(方案设计、结构设计、水电设计等)的设计师名单,支持点击跳转设计师主页
|
||||
|
||||
### 交互细节
|
||||
|
||||
<!-- TODO: 补充以下内容 -->
|
||||
<!-- - 富文本内容的最大高度和"展开/收起"逻辑 -->
|
||||
<!-- - 团队成员卡片的 Hover 效果和跳转行为 -->
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [ ] 设计理念支持富文本渲染(段落、加粗、列表)
|
||||
- [ ] 设计师姓名可点击跳转至 F4 设计师主页
|
||||
|
||||
---
|
||||
|
||||
## F3.6 数字资产分发中心(P0)
|
||||
|
||||
### 用户故事
|
||||
|
||||
作为设计师,我希望按类别下载案例的专业源文件,以便用于实际项目参考。
|
||||
|
||||
### 功能描述
|
||||
|
||||
- 文件按类别归纳展示:
|
||||
- 平面图 / CAD / PDF
|
||||
- 外观图集 / JPG
|
||||
- 施工图
|
||||
- 其它
|
||||
- 每个文件显示:文件名、文件大小、下载按钮
|
||||
- 文件下载需登录认证
|
||||
|
||||
### 交互细节
|
||||
|
||||
<!-- TODO: 补充以下内容 -->
|
||||
<!-- - 文件分类的折叠面板交互 -->
|
||||
<!-- - 下载进度的反馈方式 -->
|
||||
<!-- - 未登录用户点击下载的弹窗引导逻辑 -->
|
||||
<!-- - 大文件下载的断点续传体验 -->
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [ ] 文件列表按类别分组,每组可展开/折叠
|
||||
- [ ] 文件大小格式化显示(KB / MB)
|
||||
- [ ] 未登录用户点击下载引导登录
|
||||
- [ ] 下载操作记录日志(审计需要)
|
||||
|
||||
---
|
||||
|
||||
## F3.7 互动与裂变闭环(P1)
|
||||
|
||||
### 用户故事
|
||||
|
||||
作为用户,我希望对感兴趣的案例进行点赞、收藏和分享,并与其他用户交流。
|
||||
|
||||
### 功能描述
|
||||
|
||||
- 悬浮操作栏(右下角固定):点赞、收藏、返回顶部
|
||||
- 分享功能:生成分享链接 / 复制到剪贴板
|
||||
- 用户评论区:发表评论、查看评论列表、回复评论
|
||||
|
||||
### 交互细节
|
||||
|
||||
<!-- TODO: 补充以下内容 -->
|
||||
<!-- - 悬浮操作栏的出现/隐藏时机(滚动方向判断) -->
|
||||
<!-- - 点赞/收藏的微动效(心跳、弹跳) -->
|
||||
<!-- - 评论的实时追加 vs 刷新策略 -->
|
||||
<!-- - 评论嵌套层级限制(最多 2 层) -->
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [ ] 点赞 / 收藏状态实时切换并持久化
|
||||
- [ ] 评论支持分页加载
|
||||
- [ ] 评论发布后实时出现在列表顶部
|
||||
- [ ] 未登录用户操作时引导登录
|
||||
|
||||
---
|
||||
|
||||
## F3.8 智能推荐(P2)
|
||||
|
||||
### 用户故事
|
||||
|
||||
作为用户,我希望在浏览完一个案例后发现更多相似案例。
|
||||
|
||||
### 功能描述
|
||||
|
||||
- 详情页底部"相似推荐"卡片流(3 列网格)
|
||||
- 基于建筑类型、风格、面积等维度匹配推荐
|
||||
|
||||
### 交互细节
|
||||
|
||||
<!-- TODO: 补充以下内容 -->
|
||||
<!-- - 推荐算法的匹配维度和权重 -->
|
||||
<!-- - 推荐卡片的懒加载时机(滚动到底部触发) -->
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [ ] 推荐卡片至少展示 3 个相关案例
|
||||
- [ ] 点击推荐卡片跳转至对应详情页
|
||||
- [ ] 当前案例不出现在推荐列表中
|
||||
|
||||
---
|
||||
|
||||
*最后更新: 2026-03-02*
|
||||
131
docs/specs/F4-设计师档案.md
Normal file
131
docs/specs/F4-设计师档案.md
Normal file
@@ -0,0 +1,131 @@
|
||||
# F4 设计师数字档案
|
||||
|
||||
> **涉及端**:用户端(`Case-Database-Frontend-user`)+ 后端(`Case-Database-Backend`)
|
||||
>
|
||||
> **关联文档**:
|
||||
> - API 契约:[api-contracts.md §2.3 用户端设计师](../architecture/api-contracts.md)
|
||||
> - 数据模型:[data-model.md §4.3 设计师域](../architecture/data-model.md) / [§4.5 用户互动域(follows)](../architecture/data-model.md)
|
||||
> - UI 规范:[ui-specs-user.md](../guides/ui-specs-user.md)
|
||||
> - 参考原型:`docs/reference/个人主页.html`
|
||||
|
||||
---
|
||||
|
||||
## 功能清单
|
||||
|
||||
| 编号 | 功能 | 优先级 | 状态 |
|
||||
|------|------|--------|------|
|
||||
| F4.1 | 设计师名片档案 | P0 | ⚪ 待开发 |
|
||||
| F4.2 | 背景与履历 | P1 | ⚪ 待开发 |
|
||||
| F4.3 | 商业互动通路 | P2 | ⚪ 待开发 |
|
||||
| F4.4 | 作品集矩阵 | P0 | ⚪ 待开发 |
|
||||
|
||||
---
|
||||
|
||||
## F4.1 设计师名片档案(P0)
|
||||
|
||||
### 用户故事
|
||||
|
||||
作为用户,我希望了解设计师的专业背景,以便评估其设计能力。
|
||||
|
||||
### 功能描述
|
||||
|
||||
- 个人信息区:
|
||||
- 左侧:职位标签、中英文姓名、职位 / 所属机构 / 所在城市
|
||||
- 右侧:设计师个人写真(Hover 去灰动效)
|
||||
- 资历统计:从业经验年限、完成项目数量
|
||||
- 专长标签库:如商业空间、参数化设计、现代简约、工业风等
|
||||
|
||||
### 交互细节
|
||||
|
||||
<!-- TODO: 补充以下内容 -->
|
||||
<!-- - 写真图片的灰度 → 彩色过渡效果参数 -->
|
||||
<!-- - 资历数字的计数动画(数字滚动效果) -->
|
||||
<!-- - 标签过多时的展开/折叠逻辑 -->
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [ ] 中英文姓名完整显示
|
||||
- [ ] 资历数据使用醒目的数字展示(大字号 + 单位标注)
|
||||
- [ ] 标签支持多个平铺展示
|
||||
|
||||
---
|
||||
|
||||
## F4.2 背景与履历(P1)
|
||||
|
||||
### 用户故事
|
||||
|
||||
作为用户,我希望深入了解设计师的设计理念和荣誉资历。
|
||||
|
||||
### 功能描述
|
||||
|
||||
- 设计理念深度阐述区(富文本段落)
|
||||
- 荣誉奖项时间轴列表(年份 + 奖项名称,按时间倒序)
|
||||
|
||||
### 交互细节
|
||||
|
||||
<!-- TODO: 补充以下内容 -->
|
||||
<!-- - 时间轴的视觉样式(左侧年份 + 右侧内容卡片) -->
|
||||
<!-- - 奖项内容的展开/折叠逻辑 -->
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [ ] 设计理念支持多段落富文本
|
||||
- [ ] 荣誉奖项按年份分组排列
|
||||
- [ ] 内容为空时展示优雅的空状态
|
||||
|
||||
---
|
||||
|
||||
## F4.3 商业互动通路(P2)
|
||||
|
||||
### 用户故事
|
||||
|
||||
作为业主,我希望关注心仪的设计师并发起商业咨询。
|
||||
|
||||
### 功能描述
|
||||
|
||||
- "关注"按钮:关注 / 取消关注状态切换
|
||||
- "联系设计师"按钮:展示联系方式或跳转咨询表单
|
||||
|
||||
### 交互细节
|
||||
|
||||
<!-- TODO: 补充以下内容 -->
|
||||
<!-- - 关注按钮的状态切换动效 -->
|
||||
<!-- - 联系方式的展示形式(弹窗 vs 侧面板) -->
|
||||
<!-- - 未登录用户的引导逻辑 -->
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [ ] 关注状态持久化,再次访问保持
|
||||
- [ ] 联系入口需登录后可用
|
||||
- [ ] 关注数量在设计师档案中可见
|
||||
|
||||
---
|
||||
|
||||
## F4.4 作品集矩阵(P0)
|
||||
|
||||
### 用户故事
|
||||
|
||||
作为用户,我希望浏览设计师的所有精选作品。
|
||||
|
||||
### 功能描述
|
||||
|
||||
- 3 列网格展示设计师名下的项目卡片
|
||||
- 卡片信息:封面缩略图、项目标题、建筑类型角标、面积、年份
|
||||
- 底部"加载更多"按钮(分页)
|
||||
|
||||
### 交互细节
|
||||
|
||||
<!-- TODO: 补充以下内容 -->
|
||||
<!-- - 作品卡片与首页卡片的差异(简化版 vs 完整版) -->
|
||||
<!-- - 空作品集的展示逻辑 -->
|
||||
<!-- - 分页加载的骨架屏过渡 -->
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [ ] 作品按发布时间倒序排列
|
||||
- [ ] 点击卡片跳转至 F3 详情页
|
||||
- [ ] "加载更多"追加卡片而非全页刷新
|
||||
|
||||
---
|
||||
|
||||
*最后更新: 2026-03-02*
|
||||
180
docs/specs/F5-内容运营.md
Normal file
180
docs/specs/F5-内容运营.md
Normal file
@@ -0,0 +1,180 @@
|
||||
# F5 内容运营管理(F5.1 ~ F5.4)
|
||||
|
||||
> **涉及端**:管理端(`Case-Database-Frontend-admin`)+ 后端(`Case-Database-Backend`)
|
||||
>
|
||||
> **关联文档**:
|
||||
> - API 契约:[api-contracts.md §2.6 案例管理](../architecture/api-contracts.md) / [§2.7 轮播管理](../architecture/api-contracts.md) / [§2.8 专题管理](../architecture/api-contracts.md) / [§2.9 分类标签](../architecture/api-contracts.md)
|
||||
> - 数据模型:[data-model.md §4.2 案例核心域](../architecture/data-model.md) / [§4.4 运营内容域](../architecture/data-model.md)
|
||||
> - UI 规范:[ui-specs-admin.md](../guides/ui-specs-admin.md)
|
||||
>
|
||||
> 管理端基于 Element Plus 标准后台布局,所有页面遵循**搜索栏 → 数据表格 → 分页 → 弹窗表单**的标准结构。
|
||||
|
||||
---
|
||||
|
||||
## 功能清单
|
||||
|
||||
| 编号 | 功能 | 优先级 | 状态 |
|
||||
|------|------|--------|------|
|
||||
| F5.1 | 案例全生命周期管理 | P0 | ⚪ 待开发 |
|
||||
| F5.2 | 首页轮播管理 | P0 | ⚪ 待开发 |
|
||||
| F5.3 | 专题与精选管理 | P0 | ⚪ 待开发 |
|
||||
| F5.4 | 分类与标签字典 | P0 | ⚪ 待开发 |
|
||||
|
||||
---
|
||||
|
||||
## F5.1 案例全生命周期管理(P0)
|
||||
|
||||
### 用户故事
|
||||
|
||||
作为运营人员,我希望创建、编辑、发布和管理设计案例,以便持续丰富平台内容库。
|
||||
|
||||
### 功能描述
|
||||
|
||||
**案例 CRUD**:
|
||||
- 案例列表页:搜索(名称 / 编号 / 设计师)、按分类 / 风格 / 状态筛选、分页表格
|
||||
- 创建 / 编辑案例:多步表单或分区表单,包含基础信息、参数录入、文件上传、团队关联
|
||||
- 案例状态流转:草稿 → 待审核 → 已发布 → 已下架
|
||||
- 批量操作:批量发布、批量下架、批量删除(二次确认)
|
||||
|
||||
**分阶段文件上传体系**:
|
||||
- 将案例的数字资产按设计阶段组织上传,阶段划分:
|
||||
|
||||
| 阶段 | 典型文件 |
|
||||
|------|----------|
|
||||
| 平面阶段 | 平面图 CAD (.dwg)、平面布局 PDF、户型分析图 |
|
||||
| 外观阶段 | 效果图 (JPG/PNG)、外立面 CAD、鸟瞰图 |
|
||||
| 施工图阶段 | 施工图 CAD (.dwg)、施工说明 PDF |
|
||||
| 结构阶段 | 结构图 CAD、结构计算书 PDF、Revit 模型 (.rvt) |
|
||||
| 室内阶段 | 室内效果图、室内施工图、软装清单 |
|
||||
| 庭院阶段 | 庭院景观图、绿化方案、庭院施工图 |
|
||||
|
||||
- 每个阶段支持上传多种文件类型:PDF、CAD (.dwg)、Revit (.rvt)、图片 (JPG/PNG)、压缩包 (ZIP/RAR)
|
||||
- 上传方式:批量上传 + 拖拽上传
|
||||
- 文件元数据自动提取与手动补充:文件名、大小、上传时间、上传者、阶段归属、文件类型标签
|
||||
- 单文件大小限制:图片 ≤ 20MB、文档 ≤ 100MB、模型 ≤ 500MB
|
||||
- 上传进度条 + 断点续传(大文件场景)
|
||||
|
||||
**案例结构化参数录入**:
|
||||
- 与 F3.3 参数看板对应的 5 大维度表单(用地条件 / 规模造价 / 平面功能 / 外观风格 / 结构与性能)
|
||||
- 表单字段类型:数值输入(面宽 / 进深)、下拉选择(结构类型 / 风格)、多选标签(特色空间)、富文本(设计理念)
|
||||
- 封面图设置:从已上传图片中选取或单独上传
|
||||
|
||||
### 交互细节
|
||||
|
||||
<!-- TODO: 补充以下内容 -->
|
||||
<!-- - 案例状态流转状态机图(draft ↔ pending → published ↔ archived) -->
|
||||
<!-- - 多步表单的步骤导航和数据暂存逻辑 -->
|
||||
<!-- - 文件上传的并发数限制和队列管理 -->
|
||||
<!-- - 大文件上传的分片策略 -->
|
||||
<!-- - 批量操作的全选/部分选中逻辑 -->
|
||||
<!-- - 表单校验规则(必填项、数值范围、字符长度) -->
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [ ] 案例创建表单包含所有 5 大维度参数字段
|
||||
- [ ] 分阶段上传区域按 Tab 或折叠面板组织,各阶段独立管理
|
||||
- [ ] 拖拽上传支持多文件同时拖入
|
||||
- [ ] 文件超出大小限制时前端即时提示
|
||||
- [ ] 案例状态流转有明确的操作按钮(发布 / 下架 / 删除)和状态标签
|
||||
- [ ] 草稿状态的案例不在用户端展示
|
||||
- [ ] 删除操作需二次确认,已发布案例需先下架才能删除
|
||||
|
||||
---
|
||||
|
||||
## F5.2 首页轮播管理(P0)
|
||||
|
||||
### 用户故事
|
||||
|
||||
作为运营人员,我希望管理首页 Hero 大图轮播内容,以便控制用户端的首屏焦点展示。
|
||||
|
||||
### 功能描述
|
||||
|
||||
- 轮播项 CRUD:上传背景图、设置标题、描述摘要、跳转链接(案例详情 / 专题页 / 外部链接)
|
||||
- 排序:拖拽排序调整轮播顺序
|
||||
- 启停控制:每个轮播项支持启用 / 停用开关
|
||||
- 预览:保存前可预览轮播效果(模拟用户端展示)
|
||||
- 轮播数量限制:建议最多 5 条,超出提示
|
||||
|
||||
### 交互细节
|
||||
|
||||
<!-- TODO: 补充以下内容 -->
|
||||
<!-- - 拖拽排序的交互实现(Sortable.js / Vue Draggable) -->
|
||||
<!-- - 背景图裁剪组件的交互(比例锁定、预览区域) -->
|
||||
<!-- - 链接类型切换时表单字段的联动变化 -->
|
||||
<!-- - 预览弹窗的模拟展示效果 -->
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [ ] 拖拽排序后自动保存新顺序
|
||||
- [ ] 停用的轮播项不在用户端首页展示
|
||||
- [ ] 背景图上传支持裁剪(建议比例 16:9)
|
||||
- [ ] 跳转链接支持站内路由和外部 URL
|
||||
- [ ] 至少保留 1 条启用状态的轮播项
|
||||
|
||||
---
|
||||
|
||||
## F5.3 专题与精选管理(P0)
|
||||
|
||||
### 用户故事
|
||||
|
||||
作为运营人员,我希望创建专题合集并标记精选案例,以便策划内容运营活动。
|
||||
|
||||
### 功能描述
|
||||
|
||||
**专题管理**:
|
||||
- 专题 CRUD:标题、封面图、富文本描述、关联案例列表
|
||||
- 关联案例:从案例库中搜索并添加,支持拖拽排序
|
||||
- 专题状态:草稿 / 已发布
|
||||
|
||||
**精选标记**:
|
||||
- 在案例列表中一键标记 / 取消精选徽章
|
||||
- 精选案例排序:拖拽调整精选展示顺序
|
||||
- 精选案例在用户端首页"精选"频道和卡片金色徽章中体现
|
||||
|
||||
### 交互细节
|
||||
|
||||
<!-- TODO: 补充以下内容 -->
|
||||
<!-- - 关联案例的搜索选择器交互(弹窗搜索 + 已选列表) -->
|
||||
<!-- - 精选排序的可视化拖拽面板 -->
|
||||
<!-- - 专题封面图的推荐尺寸和裁剪逻辑 -->
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [ ] 专题可关联多个案例,案例可被多个专题引用
|
||||
- [ ] 精选标记后用户端卡片立即显示金色徽章
|
||||
- [ ] 精选排序支持拖拽且保存后即时生效
|
||||
|
||||
---
|
||||
|
||||
## F5.4 分类与标签字典(P0)
|
||||
|
||||
### 用户故事
|
||||
|
||||
作为运营人员,我希望统一管理分类和标签体系,以便保持平台内容的结构化一致性。
|
||||
|
||||
### 功能描述
|
||||
|
||||
- **建筑类型分类**: 别墅 / 民宿 / 室内 / 景观 / 农村自建房 / 庭院等,支持 CRUD + 排序
|
||||
- **风格标签**: 现代 / 中式 / 新中式 / 欧式 / 田园 / 工业风 / 极简等,支持 CRUD + 排序
|
||||
- **特色标签**: 自由标签(落地窗 / 大露台 / 双车库等),支持 CRUD
|
||||
- 标签去重校验:创建时检查是否已存在同名标签
|
||||
- 标签引用统计:显示每个标签被多少案例引用
|
||||
|
||||
### 交互细节
|
||||
|
||||
<!-- TODO: 补充以下内容 -->
|
||||
<!-- - 分类列表的拖拽排序交互 -->
|
||||
<!-- - 标签类型(style / feature / specialty)的分 Tab 管理 -->
|
||||
<!-- - 删除已引用标签的警告弹窗(显示关联案例数量) -->
|
||||
<!-- - 批量导入标签的功能(可选) -->
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [ ] 分类和标签的增删改查操作正常
|
||||
- [ ] 被案例引用的标签删除时提示关联数量并要求确认
|
||||
- [ ] 排序支持拖拽且保存后用户端同步更新
|
||||
- [ ] 同名标签创建时提示重复
|
||||
|
||||
---
|
||||
|
||||
*最后更新: 2026-03-02*
|
||||
120
docs/specs/F5-用户权限.md
Normal file
120
docs/specs/F5-用户权限.md
Normal file
@@ -0,0 +1,120 @@
|
||||
# F5 用户与权限管理(F5.5 ~ F5.7)
|
||||
|
||||
> **涉及端**:管理端(`Case-Database-Frontend-admin`)+ 后端(`Case-Database-Backend`)
|
||||
>
|
||||
> **关联文档**:
|
||||
> - API 契约:[api-contracts.md §2.10 设计师管理](../architecture/api-contracts.md) / [§2.11 评论管理](../architecture/api-contracts.md) / [§2.12 用户与权限](../architecture/api-contracts.md)
|
||||
> - 数据模型:[data-model.md §4.1 用户与权限域](../architecture/data-model.md) / [§4.3 设计师域](../architecture/data-model.md) / [§4.5 用户互动域](../architecture/data-model.md)
|
||||
> - UI 规范:[ui-specs-admin.md](../guides/ui-specs-admin.md)
|
||||
>
|
||||
> 管理端基于 Element Plus 标准后台布局,所有页面遵循**搜索栏 → 数据表格 → 分页 → 弹窗表单**的标准结构。
|
||||
|
||||
---
|
||||
|
||||
## 功能清单
|
||||
|
||||
| 编号 | 功能 | 优先级 | 状态 |
|
||||
|------|------|--------|------|
|
||||
| F5.5 | 设计师档案管理 | P1 | ⚪ 待开发 |
|
||||
| F5.6 | 评论审核 | P1 | ⚪ 待开发 |
|
||||
| F5.7 | 用户管理与权限分配 | P1 | ⚪ 待开发 |
|
||||
|
||||
---
|
||||
|
||||
## F5.5 设计师档案管理(P1)
|
||||
|
||||
### 用户故事
|
||||
|
||||
作为运营人员,我希望管理设计师的数字档案,以便维护平台设计师资源池。
|
||||
|
||||
### 功能描述
|
||||
|
||||
- 设计师档案 CRUD:
|
||||
- 基础信息:中英文姓名、职位、机构、城市、个人写真
|
||||
- 专业信息:从业年限、专长标签、设计理念(富文本)
|
||||
- 荣誉奖项:年份 + 奖项名称,支持多条录入
|
||||
- 案例关联:将设计师绑定到案例的主创团队(方案 / 结构 / 水电等专业角色)
|
||||
- 公开展示控制:启用 / 停用设计师主页的前台可见性
|
||||
|
||||
### 交互细节
|
||||
|
||||
<!-- TODO: 补充以下内容 -->
|
||||
<!-- - 设计师表单的分步或分区布局 -->
|
||||
<!-- - 荣誉奖项的动态表单行(新增/删除行) -->
|
||||
<!-- - 专长标签的选择器交互(从标签字典中选取 vs 自由输入) -->
|
||||
<!-- - 设计师写真的上传和裁剪规格 -->
|
||||
<!-- - 案例关联的搜索选择器 -->
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [ ] 设计师信息编辑后在用户端 F4 主页实时更新
|
||||
- [ ] 同一设计师可关联多个案例,同一案例可关联多个设计师
|
||||
- [ ] 停用后用户端无法访问该设计师主页,但案例中仍显示姓名
|
||||
|
||||
---
|
||||
|
||||
## F5.6 评论审核(P1)
|
||||
|
||||
### 用户故事
|
||||
|
||||
作为运营人员,我希望审核用户评论,以便维护平台内容质量和社区氛围。
|
||||
|
||||
### 功能描述
|
||||
|
||||
- 评论列表:支持按案例 / 用户 / 时间范围 / 审核状态筛选
|
||||
- 审核操作:通过(上线展示)/ 拒绝(不展示并通知用户)/ 删除
|
||||
- 举报处理:查看被举报评论,处理举报(标记违规 / 驳回举报)
|
||||
- 审核模式配置:先审后发 / 先发后审(系统配置项)
|
||||
|
||||
### 交互细节
|
||||
|
||||
<!-- TODO: 补充以下内容 -->
|
||||
<!-- - 评论列表的批量审核操作 -->
|
||||
<!-- - 审核通过/拒绝的快捷键操作 -->
|
||||
<!-- - 评论原文的上下文预览(关联案例信息) -->
|
||||
<!-- - 审核模式切换的影响说明弹窗 -->
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [ ] 评论列表支持多维筛选和分页
|
||||
- [ ] 审核通过的评论在用户端 F3.7 评论区可见
|
||||
- [ ] 拒绝或删除评论后用户端实时移除
|
||||
- [ ] 先审后发模式下新评论默认不展示,待审核通过后上线
|
||||
|
||||
---
|
||||
|
||||
## F5.7 用户管理与权限分配(P1)
|
||||
|
||||
### 用户故事
|
||||
|
||||
作为管理员,我希望管理平台用户和管理员权限,以便保障平台安全运营。
|
||||
|
||||
### 功能描述
|
||||
|
||||
**前台用户管理**:
|
||||
- 用户列表:搜索(姓名 / 手机号)、按注册时间 / 状态筛选
|
||||
- 用户详情:注册信息、登录记录、收藏列表、下载记录、评论记录
|
||||
- 状态操作:启用 / 禁用用户账号
|
||||
|
||||
**管理员权限管理**:
|
||||
- 管理员 CRUD:创建管理员账号、分配角色
|
||||
- RBAC 角色管理:预设角色(超级管理员 / 内容运营 / 审核员)
|
||||
- 权限粒度:按模块(案例 / 设计师 / 评论 / 用户 / 系统)分配读写权限
|
||||
|
||||
### 交互细节
|
||||
|
||||
<!-- TODO: 补充以下内容 -->
|
||||
<!-- - 用户详情页的 Tab 布局(基础信息 / 登录记录 / 收藏 / 下载 / 评论) -->
|
||||
<!-- - 禁用用户的二次确认和影响说明(Token 立即失效) -->
|
||||
<!-- - 角色权限分配的树形菜单勾选交互 -->
|
||||
<!-- - 角色变更时的即时生效机制说明 -->
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [ ] 禁用用户后该用户无法登录,已登录 Token 立即失效
|
||||
- [ ] 非超级管理员无法访问用户管理和系统配置模块
|
||||
- [ ] 角色权限变更后立即生效,无需重新登录
|
||||
|
||||
---
|
||||
|
||||
*最后更新: 2026-03-02*
|
||||
116
docs/specs/F5-系统运维.md
Normal file
116
docs/specs/F5-系统运维.md
Normal file
@@ -0,0 +1,116 @@
|
||||
# F5 系统配置与监控(F5.8 ~ F5.10)
|
||||
|
||||
> **涉及端**:管理端(`Case-Database-Frontend-admin`)+ 后端(`Case-Database-Backend`)
|
||||
>
|
||||
> **关联文档**:
|
||||
> - API 契约:[api-contracts.md §2.13 系统配置](../architecture/api-contracts.md) / [§2.14 数据仪表盘](../architecture/api-contracts.md) / [§2.15 日志](../architecture/api-contracts.md)
|
||||
> - 数据模型:[data-model.md §4.6 日志与系统域](../architecture/data-model.md)
|
||||
> - UI 规范:[ui-specs-admin.md](../guides/ui-specs-admin.md)
|
||||
>
|
||||
> 管理端基于 Element Plus 标准后台布局,所有页面遵循**搜索栏 → 数据表格 → 分页 → 弹窗表单**的标准结构。
|
||||
|
||||
---
|
||||
|
||||
## 功能清单
|
||||
|
||||
| 编号 | 功能 | 优先级 | 状态 |
|
||||
|------|------|--------|------|
|
||||
| F5.8 | 系统配置 | P1 | ⚪ 待开发 |
|
||||
| F5.9 | 数据仪表盘 | P2 | ⚪ 待开发 |
|
||||
| F5.10 | 操作日志与审计 | P2 | ⚪ 待开发 |
|
||||
|
||||
---
|
||||
|
||||
## F5.8 系统配置(P1)
|
||||
|
||||
### 用户故事
|
||||
|
||||
作为管理员,我希望配置平台的基础信息和运营参数。
|
||||
|
||||
### 功能描述
|
||||
|
||||
- 站点信息:平台名称、Logo、版权信息、备案号
|
||||
- SEO 配置:首页标题、描述、关键词
|
||||
- 文件上传配置:允许的文件类型、单文件大小限制
|
||||
- 评论配置:审核模式切换(先审后发 / 先发后审)
|
||||
- 水印配置:图片下载是否添加水印、水印文字 / 位置
|
||||
|
||||
### 交互细节
|
||||
|
||||
<!-- TODO: 补充以下内容 -->
|
||||
<!-- - 配置项的分组 Tab 布局(站点 / SEO / 上传 / 评论 / 水印) -->
|
||||
<!-- - 配置修改后的即时预览(Logo / 水印) -->
|
||||
<!-- - 配置保存的确认和生效机制 -->
|
||||
<!-- - 配置变更的操作日志自动记录 -->
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [ ] 站点信息修改后用户端全局生效
|
||||
- [ ] 文件上传限制修改后在案例管理的上传组件中即时生效
|
||||
- [ ] 配置变更记录操作日志
|
||||
|
||||
---
|
||||
|
||||
## F5.9 数据仪表盘(P2)
|
||||
|
||||
### 用户故事
|
||||
|
||||
作为运营人员,我希望通过数据看板了解平台运营状况,以便制定运营策略。
|
||||
|
||||
### 功能描述
|
||||
|
||||
- 概览卡片:案例总数、设计师总数、注册用户总数、今日浏览量、今日下载量
|
||||
- 热门案例排行 Top 10(按浏览 / 收藏 / 下载量排序,支持切换维度)
|
||||
- 热门设计师排行 Top 10(按关注 / 主页浏览量排序)
|
||||
- 下载统计:按文件类型分布饼图、按设计阶段分布柱状图
|
||||
- 趋势图:近 7 天 / 30 天的浏览量、注册量、下载量折线图
|
||||
|
||||
### 交互细节
|
||||
|
||||
<!-- TODO: 补充以下内容 -->
|
||||
<!-- - 概览卡片的数据刷新策略(实时 vs 缓存) -->
|
||||
<!-- - 图表组件选型(ECharts / Chart.js) -->
|
||||
<!-- - 排行榜的时间范围选择器交互 -->
|
||||
<!-- - 趋势图的日期范围切换(7天/30天/自定义) -->
|
||||
<!-- - 仪表盘的响应式布局(2列 vs 1列) -->
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [ ] 概览数据实时刷新(或 5 分钟缓存)
|
||||
- [ ] 排行榜支持时间范围切换(今日 / 本周 / 本月 / 全部)
|
||||
- [ ] 图表支持鼠标悬停查看具体数值
|
||||
- [ ] 大数据量下仪表盘加载时间 < 3s
|
||||
|
||||
---
|
||||
|
||||
## F5.10 操作日志与审计(P2)
|
||||
|
||||
### 用户故事
|
||||
|
||||
作为管理员,我希望查看所有管理员的操作记录,以便追溯问题和保障安全。
|
||||
|
||||
### 功能描述
|
||||
|
||||
- 自动记录所有管理端的写操作(创建 / 编辑 / 删除 / 状态变更)
|
||||
- 日志内容:操作时间、操作人、操作类型、操作对象、变更前后值
|
||||
- 日志列表支持按操作人 / 时间范围 / 操作类型筛选
|
||||
- 日志不可编辑、不可删除(只读)
|
||||
|
||||
### 交互细节
|
||||
|
||||
<!-- TODO: 补充以下内容 -->
|
||||
<!-- - 日志详情的变更对比展示(diff 视图) -->
|
||||
<!-- - 日志导出的格式和字段选择 -->
|
||||
<!-- - 日志分页的性能优化(游标分页 vs offset 分页) -->
|
||||
<!-- - 日志保留策略的配置入口 -->
|
||||
|
||||
### 验收标准
|
||||
|
||||
- [ ] 所有 CRUD 操作自动记录日志
|
||||
- [ ] 日志详情可展开查看变更前后对比
|
||||
- [ ] 日志数据保留至少 180 天
|
||||
- [ ] 支持按条件导出日志(CSV)
|
||||
|
||||
---
|
||||
|
||||
*最后更新: 2026-03-02*
|
||||
228
docs/vision/PRD.md
Normal file
228
docs/vision/PRD.md
Normal file
@@ -0,0 +1,228 @@
|
||||
# Product Requirements Document (PRD)
|
||||
|
||||
> **设计库** — 建筑与室内设计案例资产管理平台
|
||||
>
|
||||
> 本文档是 AI Agent 理解项目需求的核心入口。功能总览在此,各模块详规见 `docs/specs/`。
|
||||
|
||||
---
|
||||
|
||||
## 1. 项目概述
|
||||
|
||||
### 1.1 项目名称
|
||||
|
||||
**设计库** — 面向别墅、民宿、农村自建房、庭院等建筑类型的标准化设计案例数字资产平台
|
||||
|
||||
### 1.2 项目愿景
|
||||
|
||||
建筑与室内设计行业的案例资产高度碎片化:设计师的作品散落在各类社交平台、本地硬盘和企业内网中,缺乏统一的结构化沉淀;业主在选型时缺少专业、可信赖的案例参考源。
|
||||
|
||||
**设计库**致力于构建一个标准化、强结构化的设计案例数字资产平台,让每一个设计案例都成为可检索、可对比、可复用的数字资产,同时为设计师提供专业的作品展示与商机转化通路。
|
||||
|
||||
### 1.3 目标用户
|
||||
|
||||
| 用户类型 | 描述 | 核心需求 |
|
||||
|----------|------|----------|
|
||||
| 设计师(建筑/室内) | 专业设计从业者,需要检索参考案例、沉淀个人作品集 | 高效检索、专业源文件下载、个人品牌展示 |
|
||||
| 业主 / 建房者 | 计划建房或装修的个人用户,需要灵感参考与设计师对接 | 浏览灵感、筛选户型、了解造价、联系设计师 |
|
||||
| 平台运营 | 负责案例审核、内容运营、用户管理的后台管理人员 | 案例 CRUD、内容审核、数据统计、用户管理 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 终端与平台规划
|
||||
|
||||
基于业务场景的多样性,采取**分阶段多端覆盖**策略:
|
||||
|
||||
| 版本 | 终端 | 定位 | 状态 |
|
||||
|------|------|------|------|
|
||||
| V1.0 | PC Web 端 | **生产力中心** — 沉浸式大屏浏览、高阶多维筛选、大体积源文件下载 | 🔵 当前版本 |
|
||||
| V2.0 | 微信小程序 | **传播与裂变中心** — 碎片化浏览、扫码协同、一键转发、轻量社区互动 | ⚪ 远期规划 |
|
||||
| V3.0 | Revit / CAD 插件 | **专业工具集成** — 打破信息孤岛、设计资产复用、降低重复设计成本 | ⚪ 远期规划 |
|
||||
|
||||
> V1.0 聚焦 PC Web 端,对应脚手架:`Case-Database-Backend`(后端)+ `Case-Database-Frontend-user`(用户端)+ `Case-Database-Frontend-admin`(管理端)+ `Case-Database-Frontend-shared`(共享层)。
|
||||
|
||||
---
|
||||
|
||||
## 3. 核心功能
|
||||
|
||||
> **终端归属说明**:F1 ~ F4 为用户端功能(`Case-Database-Frontend-user`),F5 为管理端功能(`Case-Database-Frontend-admin`)。后端 API(`Case-Database-Backend`)同时服务两端,共享层(`Case-Database-Frontend-shared`)提供类型定义与公共逻辑。
|
||||
>
|
||||
> **详规入口**:每个模块的用户故事、功能描述、交互细节、验收标准见对应详规文件。
|
||||
|
||||
| 优先级 | 模块 | 功能 | 状态 | 详规 |
|
||||
|--------|------|------|------|------|
|
||||
| P0 | F1 认证 | 账号密码登录 | ⚪ 待开发 | [F1-认证与账户](../specs/F1-认证与账户.md) |
|
||||
| P0 | F1 认证 | 短信验证码登录 | ⚪ 待开发 | [F1-认证与账户](../specs/F1-认证与账户.md) |
|
||||
| P0 | F1 认证 | 扫码登录 | ⚪ 待开发 | [F1-认证与账户](../specs/F1-认证与账户.md) |
|
||||
| P1 | F1 认证 | 微信 / QQ 第三方授权 | ⚪ 待开发 | [F1-认证与账户](../specs/F1-认证与账户.md) |
|
||||
| P1 | F1 认证 | 自动登录保持 / 忘记密码 | ⚪ 待开发 | [F1-认证与账户](../specs/F1-认证与账户.md) |
|
||||
| P1 | F1 认证 | 深色 / 浅色主题切换 | ⚪ 待开发 | [F1-认证与账户](../specs/F1-认证与账户.md) |
|
||||
| P0 | F2 首页 | 分类频道导航 | ⚪ 待开发 | [F2-首页](../specs/F2-首页.md) |
|
||||
| P0 | F2 首页 | 全局模糊搜索 | ⚪ 待开发 | [F2-首页](../specs/F2-首页.md) |
|
||||
| P0 | F2 首页 | Hero 焦点推荐位 | ⚪ 待开发 | [F2-首页](../specs/F2-首页.md) |
|
||||
| P0 | F2 首页 | 富数据项目卡片网格 | ⚪ 待开发 | [F2-首页](../specs/F2-首页.md) |
|
||||
| P0 | F2 首页 | 风格 Tab 快捷筛选 | ⚪ 待开发 | [F2-首页](../specs/F2-首页.md) |
|
||||
| P1 | F2 首页 | 高级多维筛选器 | ⚪ 待开发 | [F2-首页](../specs/F2-首页.md) |
|
||||
| P1 | F2 首页 | 网格 / 列表视图切换 | ⚪ 待开发 | [F2-首页](../specs/F2-首页.md) |
|
||||
| P1 | F2 首页 | 收藏夹快捷入口 | ⚪ 待开发 | [F2-首页](../specs/F2-首页.md) |
|
||||
| P2 | F2 首页 | 热门标签 / 搜索预设热词 | ⚪ 待开发 | [F2-首页](../specs/F2-首页.md) |
|
||||
| P2 | F2 首页 | 底部订阅资讯(邮箱收集) | ⚪ 待开发 | [F2-首页](../specs/F2-首页.md) |
|
||||
| P0 | F3 详情 | 富媒体多维图库 | ⚪ 待开发 | [F3-案例详情](../specs/F3-案例详情.md) |
|
||||
| P0 | F3 详情 | 5 维专业参数看板 | ⚪ 待开发 | [F3-案例详情](../specs/F3-案例详情.md) |
|
||||
| P0 | F3 详情 | 侧边栏核心信息聚合 | ⚪ 待开发 | [F3-案例详情](../specs/F3-案例详情.md) |
|
||||
| P0 | F3 详情 | 数字资产分发中心(文件下载) | ⚪ 待开发 | [F3-案例详情](../specs/F3-案例详情.md) |
|
||||
| P1 | F3 详情 | 用户评论区 | ⚪ 待开发 | [F3-案例详情](../specs/F3-案例详情.md) |
|
||||
| P1 | F3 详情 | 点赞 / 收藏 / 分享 | ⚪ 待开发 | [F3-案例详情](../specs/F3-案例详情.md) |
|
||||
| P1 | F3 详情 | 设计理念 & 主创团队展示 | ⚪ 待开发 | [F3-案例详情](../specs/F3-案例详情.md) |
|
||||
| P2 | F3 详情 | 智能相似推荐 | ⚪ 待开发 | [F3-案例详情](../specs/F3-案例详情.md) |
|
||||
| P0 | F4 设计师 | 设计师名片档案 | ⚪ 待开发 | [F4-设计师档案](../specs/F4-设计师档案.md) |
|
||||
| P0 | F4 设计师 | 作品集矩阵展示 | ⚪ 待开发 | [F4-设计师档案](../specs/F4-设计师档案.md) |
|
||||
| P1 | F4 设计师 | 资历标签 / 设计理念 / 荣誉奖项 | ⚪ 待开发 | [F4-设计师档案](../specs/F4-设计师档案.md) |
|
||||
| P2 | F4 设计师 | 关注按钮 / 联系设计师入口 | ⚪ 待开发 | [F4-设计师档案](../specs/F4-设计师档案.md) |
|
||||
| P0 | F5 管理端 | 案例 CRUD(创建 / 编辑 / 发布 / 下架) | ⚪ 待开发 | [F5-内容运营](../specs/F5-内容运营.md) |
|
||||
| P0 | F5 管理端 | 分阶段文件上传体系 | ⚪ 待开发 | [F5-内容运营](../specs/F5-内容运营.md) |
|
||||
| P0 | F5 管理端 | 案例结构化参数录入 | ⚪ 待开发 | [F5-内容运营](../specs/F5-内容运营.md) |
|
||||
| P0 | F5 管理端 | 首页轮播管理 | ⚪ 待开发 | [F5-内容运营](../specs/F5-内容运营.md) |
|
||||
| P0 | F5 管理端 | 专题与精选管理 | ⚪ 待开发 | [F5-内容运营](../specs/F5-内容运营.md) |
|
||||
| P0 | F5 管理端 | 分类与标签字典 | ⚪ 待开发 | [F5-内容运营](../specs/F5-内容运营.md) |
|
||||
| P1 | F5 管理端 | 设计师档案管理 | ⚪ 待开发 | [F5-用户权限](../specs/F5-用户权限.md) |
|
||||
| P1 | F5 管理端 | 评论审核 | ⚪ 待开发 | [F5-用户权限](../specs/F5-用户权限.md) |
|
||||
| P1 | F5 管理端 | 用户管理与权限分配 | ⚪ 待开发 | [F5-用户权限](../specs/F5-用户权限.md) |
|
||||
| P1 | F5 管理端 | 系统配置(站点信息 / SEO / 水印) | ⚪ 待开发 | [F5-系统运维](../specs/F5-系统运维.md) |
|
||||
| P2 | F5 管理端 | 数据仪表盘 | ⚪ 待开发 | [F5-系统运维](../specs/F5-系统运维.md) |
|
||||
| P2 | F5 管理端 | 操作日志与审计 | ⚪ 待开发 | [F5-系统运维](../specs/F5-系统运维.md) |
|
||||
|
||||
---
|
||||
|
||||
## 4. 非功能需求
|
||||
|
||||
### 4.1 性能要求
|
||||
|
||||
| 指标 | 目标 |
|
||||
|------|------|
|
||||
| 首屏加载(FCP) | < 2s |
|
||||
| API 响应(P95) | < 200ms |
|
||||
| 图片加载策略 | 懒加载 + WebP 格式优先 |
|
||||
| 列表渲染 | 虚拟滚动(长列表场景) |
|
||||
| 并发用户 | 1000+ |
|
||||
|
||||
### 4.2 安全要求
|
||||
|
||||
- [ ] JWT + Refresh Token 双令牌认证机制
|
||||
- [ ] RBAC 角色权限控制(管理端)
|
||||
- [ ] HTTPS 全站强制
|
||||
- [ ] 敏感操作审计日志(登录、下载、删除)
|
||||
- [ ] 文件下载防盗链
|
||||
- [ ] API 接口限流(令牌桶 / 滑动窗口)
|
||||
|
||||
### 4.3 兼容性
|
||||
|
||||
- 浏览器:Chrome 90+、Firefox 88+、Safari 14+、Edge 90+
|
||||
- 分辨率:最小支持 1280px 宽度(PC 端优先)
|
||||
|
||||
### 4.4 设计系统
|
||||
|
||||
| 项目 | 规范 |
|
||||
|------|------|
|
||||
| 主色 | `#C41E3A`(红色系) |
|
||||
| 金色辅助 | `#C5A059`(精选标识) |
|
||||
| 标题字体 | Noto Serif SC |
|
||||
| 正文字体 | Inter / Noto Sans SC |
|
||||
| 数据字体 | IBM Plex Mono |
|
||||
| 主题 | 支持深色模式(Dark Mode) |
|
||||
|
||||
---
|
||||
|
||||
## 5. 技术约束
|
||||
|
||||
### 5.1 技术栈
|
||||
|
||||
- **前端**: Vue 3 + Vite + TypeScript + Tailwind CSS + Pinia
|
||||
- 管理端:Element Plus(标准后台)
|
||||
- 用户端:Headless UI + 自定义组件(品牌化设计)
|
||||
- **后端**: PHP 8.1+ / Hyperf 3.1 / Swoole 5.0+
|
||||
- **数据库**: MySQL 8.1 + Redis 7.x
|
||||
- **部署**: Docker Compose / Nginx
|
||||
|
||||
> 详见 [系统架构](../architecture/system-design.md)
|
||||
|
||||
### 5.2 第三方服务
|
||||
|
||||
| 服务 | 用途 | 状态 |
|
||||
|------|------|------|
|
||||
| 微信开放平台 | OAuth 登录授权 | ⚪ 待集成 |
|
||||
| QQ 互联 | OAuth 登录授权 | ⚪ 待集成 |
|
||||
| 阿里云 SMS | 短信验证码 | ⚪ 待集成 |
|
||||
| 阿里云 OSS / MinIO | 文件存储(CAD / PDF / 图片) | ⚪ 待集成 |
|
||||
| CDN | 静态资源与图片加速 | ⚪ 待集成 |
|
||||
|
||||
---
|
||||
|
||||
## 6. 里程碑
|
||||
|
||||
| 里程碑 | 用户端交付物 | 管理端交付物 |
|
||||
|--------|-------------|-------------|
|
||||
| Alpha | 登录 + 首页(频道 / 搜索 / 卡片 / 筛选)+ 详情页(图库 / 参数 / 下载) | 案例 CRUD + 分阶段文件上传 + 轮播管理 + 分类标签字典 |
|
||||
| Beta | 设计师主页 + 收藏体系 + 评论系统 + 高级筛选 + 主题切换 | 专题精选管理 + 设计师管理 + 评论审核 + 用户管理 + 系统配置 |
|
||||
| GA | 性能优化 + 安全加固 + 第三方登录 + 智能推荐 | 数据仪表盘 + 操作日志审计 + 全链路安全加固 |
|
||||
|
||||
---
|
||||
|
||||
## 7. 术语表
|
||||
|
||||
| 术语 | 定义 |
|
||||
|------|------|
|
||||
| 面宽(开间) | 建筑物主要朝向的外墙面宽度,通常为房屋正面的宽度 |
|
||||
| 进深 | 建筑物垂直于面宽方向的深度,即从前墙到后墙的距离 |
|
||||
| 占地面积 | 建筑物底层(首层)的外墙外围水平投影面积 |
|
||||
| 建筑总面积 | 各楼层建筑面积之和 |
|
||||
| 户型布局 | 房屋的功能房间配置,通常以"X 室 X 厅 X 卫"表示 |
|
||||
| 户型逻辑 | 房间功能分区与动线组织的设计合理性 |
|
||||
| 结构类型 | 建筑的主体承重结构形式(如框架结构、砖混结构、钢结构等) |
|
||||
| 基础类型 | 建筑地基的构造形式(如条形基础、筏板基础、独立基础等) |
|
||||
| 抗震设防 | 建筑设计中针对地震灾害所采取的结构措施等级 |
|
||||
| 外立面材料 | 建筑外墙的饰面材料(如真石漆、文化石、面砖等) |
|
||||
| 屋面构造 | 屋顶的结构组成和防水保温做法 |
|
||||
| 造价预估 | 建筑施工的预计总费用(不含土地成本) |
|
||||
| 数字资产 | 案例相关的可下载专业文件(CAD 图纸、PDF 方案、高清效果图等) |
|
||||
| 设计阶段 | 案例数字资产的生产环节分类,包括平面、外观、施工图、结构、室内、庭院等阶段 |
|
||||
| 数字资产包 | 一个案例按设计阶段归集的全部可下载文件的集合 |
|
||||
| CAD (.dwg) | AutoCAD 原生图纸格式,建筑设计行业的标准工程图文件 |
|
||||
| Revit (.rvt) | Autodesk Revit 建筑信息模型文件,包含三维参数化建筑数据 |
|
||||
| 精选标记 | 运营人员在管理端为优质案例添加的推荐标识,在用户端显示为金色徽章 |
|
||||
| 专题 | 运营策划的主题内容合集,关联多个案例并附带编辑性描述 |
|
||||
| RBAC | 基于角色的访问控制(Role-Based Access Control),通过角色分配管理端操作权限 |
|
||||
|
||||
---
|
||||
|
||||
## 8. 参考文档
|
||||
|
||||
### 架构与技术
|
||||
|
||||
- [系统架构](../architecture/system-design.md)
|
||||
- [数据模型](../architecture/data-model.md)
|
||||
- [API 契约](../architecture/api-contracts.md)
|
||||
- [双前端架构策略](../architecture/frontend-strategy.md)
|
||||
|
||||
### 设计规范
|
||||
|
||||
- [管理端 UI 规范](../guides/ui-specs-admin.md)
|
||||
- [用户端 UI 规范](../guides/ui-specs-user.md)
|
||||
|
||||
### 功能模块详规
|
||||
|
||||
- [F1 — 认证与账户中心](../specs/F1-认证与账户.md)
|
||||
- [F2 — 首页](../specs/F2-首页.md)
|
||||
- [F3 — 案例详情引擎](../specs/F3-案例详情.md)
|
||||
- [F4 — 设计师数字档案](../specs/F4-设计师档案.md)
|
||||
- [F5 — 内容运营管理](../specs/F5-内容运营.md)
|
||||
- [F5 — 用户与权限管理](../specs/F5-用户权限.md)
|
||||
- [F5 — 系统配置与监控](../specs/F5-系统运维.md)
|
||||
|
||||
### 参考原型
|
||||
|
||||
- `docs/reference/` 目录下 HTML 文件
|
||||
|
||||
---
|
||||
|
||||
*最后更新: 2026-03-02*
|
||||
*文档负责人: 产品团队*
|
||||
20
docs/vision/roadmap.md
Normal file
20
docs/vision/roadmap.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# 🗺️ Product Roadmap
|
||||
|
||||
> 产品路线图,帮助 AI 理解项目长期方向
|
||||
|
||||
---
|
||||
|
||||
## 当前阶段: [Phase Name]
|
||||
|
||||
### 近期 (本月)
|
||||
- [ ] ...
|
||||
|
||||
### 中期 (本季度)
|
||||
- [ ] ...
|
||||
|
||||
### 远期 (半年+)
|
||||
- [ ] ...
|
||||
|
||||
---
|
||||
|
||||
*最后更新: YYYY-MM-DD*
|
||||
Reference in New Issue
Block a user