# 系统架构设计 ## 1. 整体架构 ``` ┌─────────────────────────────────────────────────────────────┐ │ 用户访问层 │ │ ┌─────────────┐ ┌──────────────┐ ┌────────────────────┐ │ │ │ 公众端(H5) │ │ 管理后台(Web) │ │ 微信内置浏览器(H5) │ │ │ │ /p/... │ │ /:tenant/... │ │ /p/... │ │ │ └──────┬──────┘ └──────┬───────┘ └─────────┬──────────┘ │ └─────────┼────────────────┼────────────────────┼─────────────┘ │ │ │ ┌─────────▼────────────────▼────────────────────▼─────────────┐ │ Vue3 前端应用 │ │ ┌─────────────────┐ ┌──────────────────────────────────┐ │ │ │ 公众端模块 │ │ 管理端模块 │ │ │ │ - 活动大厅 │ │ - 机构管理端(图书馆/学校/...) │ │ │ │ - 活动详情 │ │ - 评审端 │ │ │ │ - 报名/提交作品 │ │ - 平台管理端(超管) │ │ │ │ - 个人中心 │ │ - 现有功能保持不变 │ │ │ │ - 子女管理 │ │ │ │ │ └─────────────────┘ └──────────────────────────────────┘ │ └────────────────────────────┬─────────────────────────────────┘ │ HTTP API ┌────────────────────────────▼─────────────────────────────────┐ │ NestJS 后端 │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────────────┐ │ │ │ Auth模块 │ │ 用户模块 │ │ 活动模块 │ │ 公众API模块 │ │ │ │(多种登录) │ │(子女管理) │ │(现有改造) │ │ (公众端专用) │ │ │ └──────────┘ └──────────┘ └──────────┘ └────────────────┘ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────────────┐ │ │ │ 租户模块 │ │ 评审模块 │ │ 作品模块 │ │ 其他现有模块 │ │ │ │(类型扩展) │ │(现有) │ │(现有改造) │ │ (保持不变) │ │ │ └──────────┘ └──────────┘ └──────────┘ └────────────────┘ │ └────────────────────────────┬─────────────────────────────────┘ │ Prisma ORM ┌────────────────────────────▼─────────────────────────────────┐ │ MySQL 数据库 │ │ users / children / tenants / contests / registrations / ... │ └──────────────────────────────────────────────────────────────┘ ``` --- ## 2. 租户模型设计 ### 2.1 租户类型 | 类型标识 | 名称 | 说明 | 举例 | |---------|------|------|------| | `platform` | 平台租户 | 系统运营方,全局唯一 | 乐绘世界 | | `library` | 图书馆 | 公共图书馆机构 | 广东省立中山图书馆 | | `kindergarten` | 幼儿园 | 幼儿教育机构 | XX幼儿园 | | `school` | 学校 | 中小学校 | XX小学 | | `institution` | 社会机构 | 美术培训、文化机构等 | XX美术中心 | | `other` | 其他 | 未分类的机构 | - | ### 2.2 租户与用户的关系 ``` 租户(机构) ├── 拥有机构用户:管理员、工作人员、评委 │ └── 通过 tenant_id 关联 │ 公众用户 ├── 不隶属任何租户 ├── 通过自主注册创建 ├── 可以查看所有"公开"活动并报名 │ 身份重叠场景(二期实现) ├── 一个手机号 = 一个账号 ├── 同一账号可以同时拥有:公众用户身份 + 机构用户身份 └── 通过"身份切换"在不同工作台之间切换 ``` ### 2.3 活动可见范围 ``` 活动创建时设置 visibility 字段: ├── public — 公开(所有注册用户可见,广东省图本次使用) ├── designated — 指定机构(选择哪些租户可见,现有逻辑) └── internal — 仅内部(仅本机构内部可见) ``` --- ## 3. 用户体系设计 ### 3.1 核心原则:一号多身份 **一个手机号/账号 = 一个用户**,用户可以拥有多个身份角色。 一期先实现账号密码登录,二期补充手机号和微信登录。一期阶段公众用户通过"用户名+密码"自主注册。 ### 3.2 用户来源 | 来源 | 标识 | 说明 | |------|------|------| | 管理员创建 | `admin_created` | 现有方式,管理员在后台创建用户 | | 自主注册 | `self_registered` | 新增,用户通过公众端注册页面自行注册 | ### 3.3 用户参与模型 ``` 注册用户(User) ├── 可以以"自己"的身份报名活动(所有用户默认能力) ├── 可以添加子女,以"子女"的身份代为报名(可选能力) │ ├── 我自己报名的活动(participant_type = 'self') │ └── 适用场景:有手机号的青少年自己注册参与 │ └── 我为子女报名的活动(participant_type = 'child') ├── child_id 指向具体哪个子女 └── 适用场景:家长为年幼子女代报名 ``` ### 3.4 报名流程 ``` 用户点击"报名活动" │ ├── 检查是否已登录 → 未登录则跳转登录/注册页 │ ├── 已登录 → 检查是否有关联子女 │ ├── 无子女 → 直接以自己身份报名 │ → 填写报名补充信息 → 提交 │ └── 有子女 → 弹出"选择参与者" ┌─────────────────────────┐ │ 请选择参与者: │ │ ○ 我自己 │ │ ○ 子女:小明(8岁) │ │ ○ 子女:小红(5岁) │ │ + 添加新的子女 │ └─────────────────────────┘ → 选择后填写报名信息 → 提交 ``` --- ## 4. 前端架构 ### 4.1 路由设计 ``` 前端路由结构: │ ├── /p/ # 公众端(H5 + Web 响应式) │ ├── /p/login # 公众端登录 │ ├── /p/register # 公众端注册 │ ├── /p/activities # 活动大厅(活动列表) │ ├── /p/activities/:id # 活动详情 │ ├── /p/activities/:id/register # 报名页面 │ ├── /p/activities/:id/submit # 提交作品 │ ├── /p/mine # 个人中心 │ ├── /p/mine/children # 子女管理 │ ├── /p/mine/registrations # 我的报名 │ └── /p/mine/works # 我的作品 │ ├── /:tenantCode/ # 管理端(现有,保持不变) │ ├── /:tenantCode/login # 机构登录 │ ├── /:tenantCode/contests # 活动管理 │ ├── /:tenantCode/system # 系统管理 │ └── ... │ └── / # 根路径重定向 ``` ### 4.2 公众端布局 ``` ┌────────────────────────────────────────┐ Web 端 │ 顶部导航栏 │ │ [Logo 乐绘世界] [活动大厅] [个人中心] │ ├────────────────────────────────────────┤ │ │ │ 页面内容区 │ │ │ └────────────────────────────────────────┘ ┌──────────────┐ H5 移动端 │ 顶部标题栏 │ ├──────────────┤ │ │ │ 页面内容区 │ │ │ ├──────────────┤ │ 底部Tab导航 │ │ [首页][我的] │ └──────────────┘ ``` ### 4.3 响应式适配策略 ``` 一套 Vue 代码,通过 CSS 媒体查询和 Tailwind 断点适配: ├── sm (< 640px) → H5 移动端布局(底部 Tab 导航) ├── md (640-1024px) → 平板端布局 └── lg (> 1024px) → Web 端布局(顶部导航栏) ``` --- ## 5. 后端 API 设计 ### 5.1 新增公众端 API 模块 ``` /api/public/ # 公众端 API(无需租户上下文) ├── POST /auth/register # 公众注册 ├── POST /auth/login # 公众登录 ├── GET /activities # 获取公开活动列表 ├── GET /activities/:id # 获取活动详情 ├── POST /activities/:id/register # 报名活动 ├── POST /activities/:id/submit # 提交作品 ├── GET /mine/profile # 获取个人信息 ├── PUT /mine/profile # 更新个人信息 ├── GET /mine/children # 获取子女列表 ├── POST /mine/children # 添加子女 ├── PUT /mine/children/:id # 编辑子女 ├── DELETE /mine/children/:id # 删除子女 ├── GET /mine/registrations # 我的报名列表 └── GET /mine/works # 我的作品列表 ``` ### 5.2 现有 API 改造 ``` 活动相关 API 变更: ├── 创建活动:新增 visibility 字段(public/designated/internal) ├── 获取活动列表:支持按 visibility 过滤 ├── 报名接口:新增 participant_type 和 child_id 字段 └── 报名记录查询:支持按 participant_type 筛选 ``` --- ## 6. 多机构联合举办(二期) ### 6.1 主办-协办模型 ``` 活动表新增: ├── organizer_tenant_id — 主办机构 ID └── co_organizer_ids — 协办机构 ID 列表(JSON 数组) 权限分配: ├── 主办方:完整管理权限(创建、编辑、审核、发布成果) └── 协办方:有限权限(查看报名数据、推荐评委、查看成果) ``` ### 6.2 活动页面展示 ``` 活动详情页展示: ├── 主办单位:广东省立中山图书馆 └── 协办单位:北京国家图书馆、上海图书馆 ``` --- ## 7. 一号多身份(二期) ### 7.1 身份切换机制 ``` 用户登录后: ├── 默认进入公众端(活动大厅) ├── 如果用户同时是某机构的管理员/工作人员 │ └── 显示"切换到管理端"入口 ├── 切换身份 = 切换工作台视角 └── 不需要重新登录,JWT token 中包含所有身份信息 ``` ### 7.2 身份绑定 ``` 用户身份表(user_identities) ├── user_id — 用户 ID ├── identity_type — 身份类型(public / tenant_admin / judge / staff) ├── tenant_id — 关联租户(公众身份为 NULL) ├── role_id — 关联角色 └── status — 状态(active / inactive) ```