docs: 论坛+环保建材+导航改版设计文档
新增 2026-07-07 spec:landing 导航改 4 项、环保建材拉真实材料库、 健康装修大家谈进阶版论坛(板块/楼层回帖/点赞,公开看登录发)。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D7EkGJYZMdQtMeDEt3z4vL
This commit is contained in:
commit
89369fd45e
|
|
@ -0,0 +1,222 @@
|
|||
# 设计文档:导航改版 + 环保建材 + 健康装修大家谈论坛
|
||||
|
||||
- 日期:2026-07-07
|
||||
- 目标项目:`C:\code\空气质量预测\源码`(用户端 iapip-web / 服务端 iapip-svr)
|
||||
- 工作目录:前端 `源码/用户端/iapip-web`,后端 `源码/服务端/iapip-svr`
|
||||
- 状态:已通过需求评审,待写实现计划
|
||||
|
||||
---
|
||||
|
||||
## 1. 背景与目标
|
||||
|
||||
用户端首页(landing,`用户端/iapip-web/src/pages/landing/index.tsx`)当前顶部导航为 5 项(资讯科普 / 治理案例 / 如何使用 / 污染源识别 / 专业看板),前三项为页面内锚点滚动、内容全为写死的静态数据。
|
||||
|
||||
本次改动:
|
||||
|
||||
1. 顶部导航改为 4 项:**健康装修科普、预测案例、环保建材、健康装修大家谈**。
|
||||
2. 「环保建材」为新区块,从后端真实公共材料库拉取 E0 低释放材料展示。
|
||||
3. 「健康装修大家谈」为新的**真功能论坛**(进阶版:板块、发帖、楼层回帖、点赞、分页;公开浏览、手机登录后发帖)。
|
||||
|
||||
前两项(健康装修科普、预测案例)仅为现有区块的**标签改名**,内容不变。
|
||||
|
||||
---
|
||||
|
||||
## 2. 范围
|
||||
|
||||
### 2.1 纳入范围
|
||||
- 导航 4 项改版与两处区块标签改名(纯前端)。
|
||||
- 环保建材:新增 1 个免认证后端接口 + landing 新区块(真实数据)。
|
||||
- 论坛:新增 3 张 Prisma 表 + 1 个后端 controller + 2 个前端页面 + 1 个前端 API 封装。
|
||||
|
||||
### 2.2 不纳入范围(YAGNI)
|
||||
- 论坛板块的后台增删(板块用代码常量固定)。
|
||||
- 帖子/回帖的富文本、@提及、通知、搜索。
|
||||
- 管理端对论坛的审核后台(作者可自删自己的帖/回帖已满足基本治理;管理端审核为后续可选项)。
|
||||
- 环保建材的收藏、跳转到材料详情等交互(仅展示)。
|
||||
|
||||
---
|
||||
|
||||
## 3. A. 导航栏与 landing 文案(前端)
|
||||
|
||||
文件:`用户端/iapip-web/src/pages/landing/index.tsx`
|
||||
|
||||
| 新导航项 | 行为 | 实现 |
|
||||
|---|---|---|
|
||||
| 健康装修科普 | 滚动到 `#news` | 现「资讯科普」区块改名;`nav-links` 文案改,`#news` 区块 `sec-tag` 由「资讯 · 科普」改为「健康装修科普」 |
|
||||
| 预测案例 | 滚动到 `#cases` | 现「治理案例」区块改名;`sec-tag` 由「治理案例」改为「预测案例」,内容(before/after 卡片)不变 |
|
||||
| 环保建材 | 滚动到新 `#eco` | 见第 4 节 |
|
||||
| 健康装修大家谈 | `history.push('/forum')` | 见第 5–7 节 |
|
||||
|
||||
其他:
|
||||
- 「免费试算」主按钮(`openPredict`)保留不变。
|
||||
- 原「如何使用」`#how` 区块**保留在页面**,仅从导航移除。
|
||||
- 原「专业看板」入口从导航移除;CTA 区块的「查看专业看板」按钮(`goPro`)与登录入口仍可到达工作台。
|
||||
|
||||
---
|
||||
|
||||
## 4. B. 环保建材(后端免认证接口 + 前端区块)
|
||||
|
||||
### 4.1 后端接口
|
||||
- 路由:`GET /api/mtrl/eco`,**免认证**(不挂 `authn`),加在 `material.ts` 中。
|
||||
- 逻辑:查询 `PublicMaterial` 中 `deleted=0 且 display=1`、`eco_level='E0'` 的材料;若不足 8 条,补 `E1`。按 `created_at` 倒序,最多返回 8 条。
|
||||
- 返回字段(精简,不返回释放参数三件套等敏感/无关字段):
|
||||
`material_id, name, category, brand, factory, eco_level, methanal`(甲醛标称值,若有)。
|
||||
- 空结果返回 `[]`,前端优雅处理。
|
||||
|
||||
### 4.2 前端区块
|
||||
- landing 新增 `#eco` 区块,位置置于 `#cases` 与 `#how` 之间(顺序:news → cases → eco → how)。
|
||||
- 组件挂载时通过 `api.material.getEcoMaterials()` 拉取,`useState` 保存。
|
||||
- 展示:卡片网格(复用现有 `.cases-grid` / `.case` 或新增等价样式),每张卡显示材料名、品牌、类别、环保等级标签(E0/E1)。
|
||||
- 加载中不阻塞页面其他区块;返回空数组时该区块整体隐藏(`data.length === 0` 则不渲染 `<section>`)。
|
||||
- 前端 API:`src/services/api/material.ts` 新增 `getEcoMaterials`,走 `/api/mtrl/eco`。
|
||||
|
||||
---
|
||||
|
||||
## 5. C. 论坛数据模型(Prisma)
|
||||
|
||||
文件:`服务端/iapip-svr/prisma/schema.prisma`。新增 3 张表。板块(board)**不建表**,用后端常量固定。
|
||||
|
||||
### 5.1 板块常量
|
||||
在 `服务端/iapip-svr/src/common/constants.ts` 定义:
|
||||
```
|
||||
FORUM_BOARDS = ['甲醛治理', '异味TVOC', '环保材料', '装修避坑', '求助问答']
|
||||
```
|
||||
帖子的 `board` 字段值必须属于该列表(后端校验)。
|
||||
|
||||
### 5.2 表结构
|
||||
```prisma
|
||||
model ForumThread {
|
||||
id Int @id @default(autoincrement())
|
||||
board String
|
||||
title String
|
||||
content String @db.Text
|
||||
author_id String
|
||||
author_name String
|
||||
like_count Int @default(0)
|
||||
reply_count Int @default(0)
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
deleted Int @default(0)
|
||||
replies ForumReply[]
|
||||
likes ForumThreadLike[]
|
||||
@@map("forum_thread")
|
||||
}
|
||||
|
||||
model ForumReply {
|
||||
id Int @id @default(autoincrement())
|
||||
thread_id Int
|
||||
thread ForumThread @relation(fields: [thread_id], references: [id], onDelete: Cascade)
|
||||
floor Int
|
||||
content String @db.Text
|
||||
author_id String
|
||||
author_name String
|
||||
created_at DateTime @default(now())
|
||||
deleted Int @default(0)
|
||||
@@map("forum_reply")
|
||||
}
|
||||
|
||||
model ForumThreadLike {
|
||||
thread_id Int
|
||||
thread ForumThread @relation(fields: [thread_id], references: [id], onDelete: Cascade)
|
||||
user_id String
|
||||
created_at DateTime @default(now())
|
||||
@@id([thread_id, user_id])
|
||||
@@map("forum_thread_like")
|
||||
}
|
||||
```
|
||||
- `author_name` 冗余存 username,列表/详情展示不连表。
|
||||
- 软删 `deleted` 沿用项目惯例;`ForumThreadLike` 无软删(toggle 直接删行)。
|
||||
- 迁移:`npm run dbpush:dev`(prisma db push)。
|
||||
|
||||
---
|
||||
|
||||
## 6. D. 论坛后端 API
|
||||
|
||||
新建 controller `服务端/iapip-svr/src/controllers/forum.ts`,`prefix('/api/forum')`,在 `src/index.ts` 中 `app.use(forumRoutes)` 注册。登录鉴权复用 `authn(CERT_TYPE.ACCOUNT)`,作者身份取 `ctx.state.acct_cert`(`id`、`username`)。
|
||||
|
||||
| 方法 路径 | 鉴权 | 功能 | 说明 |
|
||||
|---|---|---|---|
|
||||
| `GET /api/forum/boards` | 公开 | 板块列表 + 各板块帖数 | 返回 `[{board, count}]`,count 统计 `deleted=0` |
|
||||
| `GET /api/forum/threads` | 公开 | 分页帖子列表 | query:`board?`(缺省全部)、`page`(默认1)、`size`(默认20)。按 `created_at desc`。返回列表项 + 总数 |
|
||||
| `GET /api/forum/threads/:id` | 公开 | 帖子详情 + 分页回帖 | 回帖按 `floor asc`,跳过 `deleted=1` 的回帖。best-effort:若请求带有效 token 则解析出用户并附 `liked` 布尔,否则省略该字段 |
|
||||
| `POST /api/forum/threads` | 登录 | 发帖 | body:`{board,title,content}`。board 必须在 `FORUM_BOARDS`,title/content 非空且限长 |
|
||||
| `POST /api/forum/threads/:id/replies` | 登录 | 回帖 | body:`{content}`。事务内 `floor = 当前 reply_count + 1`,同时 `reply_count++` |
|
||||
| `POST /api/forum/threads/:id/like` | 登录 | 点赞/取消 toggle | 有 like 行则删并 `like_count--`;无则插并 `like_count++`。返回最新 `{liked, like_count}` |
|
||||
| `DELETE /api/forum/threads/:id` | 登录 | 软删自己的帖 | 仅 `author_id === cert.id`,否则 403 |
|
||||
| `DELETE /api/forum/replies/:id` | 登录 | 软删自己的回帖 | 同上;不回退 floor(其余楼层号保持不变)。详情接口跳过 `deleted=1` 的回帖,前端不展示已删楼层 |
|
||||
|
||||
- 校验:沿用项目 AJV `validate` 中间件风格(参照 `material.ts`)。
|
||||
- 错误码:非法 board / 空标题用 `1000 INVALID_REQ_DATA`;越权删除用 `3000 FORBIDDEN`;帖子不存在用 `4000`(沿用现有粗粒度约定)。
|
||||
- 并发:回帖 floor 与 reply_count、点赞计数均在 `db.$transaction` 内完成,避免竞态。
|
||||
|
||||
---
|
||||
|
||||
## 7. E. 论坛前端
|
||||
|
||||
前端 API 封装:新建 `用户端/iapip-web/src/services/api/forum.ts`,聚合进 `src/services/api/index.ts`(`api.forum.*`)。
|
||||
|
||||
新增两个**公开路由**(无需登录即可访问,路由风格参照 landing 在 `.umirc.ts` 中的注册方式):
|
||||
|
||||
### 7.1 `/forum` — 论坛首页
|
||||
- 板块 Tab(含「全部」):点击切换 `board` 过滤。
|
||||
- 帖子列表:标题、作者名、时间、回帖数、点赞数;点击行 → `/forum/thread/:id`。
|
||||
- 分页控件(Antd `Pagination`)。
|
||||
- 右上「发帖」按钮:未登录 → 弹 `PhoneAuthModal`;已登录 → 打开发帖表单(Modal:板块选择 + 标题 + 正文)。发帖成功后刷新列表。
|
||||
|
||||
### 7.2 `/forum/thread/:id` — 帖子详情
|
||||
- 帖子正文(作者、时间、板块)。
|
||||
- 点赞按钮:显示 `like_count` 与当前用户 `liked` 状态;未登录点则弹登录框,登录后 toggle。
|
||||
- 楼层回帖列表(floor + 作者 + 时间 + 内容),分页。
|
||||
- 底部回帖框:未登录点则弹登录框;已登录提交后刷新回帖列表并楼层递增。
|
||||
- 若为作者本人,帖子/自己的回帖显示「删除」入口(软删)。
|
||||
|
||||
### 7.3 登录复用
|
||||
- 统一复用现有 `PhoneAuthModal`(`src/components/phone-auth-modal`)。登录态判断沿用 `localStorage[LOC_STOR_KEY.AUTH_TOKEN]`。
|
||||
- 已登录请求自动带 `Authorization`(沿用 `services/api` 现有请求拦截)。
|
||||
|
||||
---
|
||||
|
||||
## 8. 测试
|
||||
|
||||
### 8.1 后端
|
||||
- 发帖 → 该板块帖数 +1;非法 board 被拒(1000)。
|
||||
- 连续回帖 → floor 依次 1、2、3,`reply_count` 同步;未登录回帖被拒(401/2000)。
|
||||
- 点赞 toggle:首次 +1 且 `liked=true`,再次 -1 且 `liked=false`;同一用户不重复计数。
|
||||
- 越权删除他人帖 → 403;删除自己的 → `deleted=1`,列表不再出现。
|
||||
- 分页:`page/size` 边界正确,返回总数一致。
|
||||
|
||||
### 8.2 环保建材
|
||||
- 有 E0 材料时返回 ≤8 条且字段精简;无任何公共材料时返回 `[]`,前端 `#eco` 区块隐藏、不报错。
|
||||
|
||||
### 8.3 前端
|
||||
- 未登录浏览 `/forum` 与详情正常;触发发帖/回帖/点赞时弹登录框,登录后动作继续完成。
|
||||
- 导航 4 项滚动/跳转正确;`#news`/`#cases` 改名后内容不变。
|
||||
|
||||
---
|
||||
|
||||
## 9. 涉及文件清单
|
||||
|
||||
### 后端 `服务端/iapip-svr`
|
||||
- `prisma/schema.prisma`(新增 3 表)
|
||||
- `src/common/constants.ts`(新增 `FORUM_BOARDS`)
|
||||
- `src/controllers/forum.ts`(新建)
|
||||
- `src/controllers/material.ts`(新增 `GET /eco`)
|
||||
- `src/index.ts`(注册 `forumRoutes`)
|
||||
|
||||
### 前端 `用户端/iapip-web`
|
||||
- `src/pages/landing/index.tsx`(导航 4 项、区块改名、新增 `#eco` 区块及取数)
|
||||
- `src/pages/forum/index.tsx`(新建,论坛首页)
|
||||
- `src/pages/forum/thread.tsx`(新建,帖子详情)
|
||||
- `src/services/api/forum.ts`(新建)
|
||||
- `src/services/api/material.ts`(新增 `getEcoMaterials`)
|
||||
- `src/services/api/index.ts`(聚合 `api.forum`)
|
||||
- `.umirc.ts`(新增 `/forum`、`/forum/thread/:id` 公开路由)
|
||||
|
||||
---
|
||||
|
||||
## 10. 风险与注意
|
||||
|
||||
- **数据库迁移**:改 schema 需 `npm run dbpush:dev`;生产库需谨慎(本地开发用 Docker MySQL)。
|
||||
- **landing 首个真实接口**:环保建材使 landing 依赖后端,需保证后端未起/空数据时页面不崩。
|
||||
- **楼层稳定性**:回帖软删后不回退 floor,避免楼层错位。
|
||||
- **登录态一致性**:论坛与现有测算入口共用手机登录 token,行为需一致。
|
||||
Loading…
Reference in New Issue