更新数据库结构,向章节表添加 hot_score 字段以修复前端保存章节时的 1054 错误。同时,实施 Toast 通知系统,替换全系统的 alert 提示,提升用户体验。更新相关文档以反映变更流程与最佳实践。

This commit is contained in:
Alex-larget
2026-03-10 18:11:06 +08:00
parent aebb533507
commit 3b942fd7a4
16 changed files with 1028 additions and 785 deletions

View File

@@ -34,3 +34,34 @@
> 详见会议纪要:`.cursor/meeting/2026-03-10_小程序新旧版对比与dashboard接口新增.md`
---
## chapters 表新增 hot_score 字段
### 问题
前端 `ContentPage.tsx` 保存章节时传递 `hotScore` 字段,但后端 model 和数据库均缺少该列,导致:
```
Error 1054 (42S22): Unknown column 'hot_score' in 'field list'
```
### 修复步骤
1. 执行迁移 SQL`soul-api/scripts/add-hot-score.sql`
```sql
ALTER TABLE chapters ADD COLUMN hot_score INT NOT NULL DEFAULT 0;
```
2. 同步 model`internal/model/chapter.go`
```go
HotScore int `gorm:"column:hot_score;default:0" json:"hotScore"`
```
3. 重启后端服务生效
### 规则沉淀
- **model 与 DB 必须同步**:前端传入新字段时,必须先确认 DB 列存在,再确认 model struct 中有对应字段,缺一不可
- **变更流程**:前端加字段 → ALTER TABLE → 更新 model struct → 重启服务
- 迁移 SQL 统一放 `soul-api/scripts/` 目录,文件名格式 `add-{描述}.sql`
> 详见会议纪要:`.cursor/meeting/2026-03-10_Toast通知系统全局落地.md`

View File

@@ -116,3 +116,29 @@
> 同时影响:小程序开发工程师、后端工程师
> 详见会议纪要:`.cursor/meeting/2026-03-10_小程序新旧版对比与dashboard接口新增.md`
---
## Toast 通知系统 & DB 变更 SOP团队共享
### Toast 批量替换方法论
使用 PowerShell 正则脚本批量替换 alert → toast**替换后必须人工复查 `toast.info()`**
- 验证提示类("请输入/请填写/密码至少/ID已存在")被脚本误判为 info应改为 error
- 核查方式:`grep -r "toast.info(" src/` 逐条确认语义
### DB 变更 SOP前后端联动
当前端新增字段时,完整变更流程:
| 步骤 | 执行方 | 操作 |
|------|--------|------|
| 1 | 后端 | 执行 `ALTER TABLE` 或用 `db-exec` 脚本 |
| 2 | 后端 | 更新 `internal/model/*.go` struct |
| 3 | 后端 | 重启服务验证 |
| 4 | 管理端 | 确认保存请求不再报 1054 |
若跳过任一步骤GORM 写入时必报 `Unknown column`
> 同时影响:管理端开发工程师、后端工程师
> 详见会议纪要:`.cursor/meeting/2026-03-10_Toast通知系统全局落地.md`

View File

@@ -29,6 +29,9 @@
| 2026-03-10 | 小程序 | 最佳实践 | miniprogram-dev SKILL §my | my.js 阅读统计改为后端接口loadDashboardStats禁止用随机数时间/标题占位 |
| 2026-03-10 | 后端 | bug 修复 | api-dev SKILL | 聚合接口三处修复recentChapters 去重、totalReadMinutes 最小1分钟、DB 错误返回 500 |
| 2026-03-10 | 团队 | 方法论 | - | 新旧版代码对比:以功能完整性为基准,批量 diff + 分类取舍,不以日期判优劣 |
| 2026-03-10 | 管理端 | 最佳实践 | admin-dev SKILL §toast | Toast 通知系统落地utils/toast.ts 纯原生实现,全系统 18 文件 alert → toast 批量替换 |
| 2026-03-10 | 后端 | bug 修复 | api-dev SKILL | chapters 表新增 hot_score 列,修复 1054 Unknown column 错误DB 变更 SOPALTER→model→重启 |
| 2026-03-10 | 团队 | 方法论 | - | DB 变更 SOP + Toast 批量替换方法论(脚本替换后必须人工复查 toast.info 语义) |
---
@@ -39,4 +42,4 @@
---
**最后更新**2026-03-10
**最后更新**2026-03-10Toast + hot_score 经验入库)

View File

@@ -22,9 +22,10 @@ soul-apiGo + Gin + GORM + MySQL提供三组路由`/api/miniprogram/*`
| 2026-03-05 | 文章详情@某人加好友方案讨论content 内嵌 @ 标记、miniprogram 添加好友接口 | 待续 |
| 2026-03-10 | 会议:管理端迁移 Mycontent-temp后端接口边界不变overview 聚合接口可选但需降级 | 待续 |
| 2026-03-10 | 新增 GET /api/miniprogram/user/dashboard-stats聚合阅读统计接口含去重、min1分钟、500错误码修复 | 已完成 |
| 2026-03-10 | chapters 表新增 hot_score 列ALTER TABLE + model 同步),修复前端保存章节报 1054 错误 | 已完成 |
> **格式说明**:每次开发后在此追加一行,日期格式 YYYY-MM-DD状态用已完成 / 进行中 / 待续 / 搁置
---
**最后更新**2026-03-10dashboard-stats 接口新增完成)
**最后更新**2026-03-10hot_score 迁移完成)

View File

@@ -21,9 +21,10 @@
| 2026-03-05 | 分支冲突后功能完整性分析会议:全功能自测,记录 404/异常接口 | 待续 |
| 2026-03-05 | 文章详情@某人加好友方案讨论:编辑页插入 @用户、保存约定 content 格式 | 待续 |
| 2026-03-10 | 会议:管理端迁移 Mycontent-temp 新菜单/布局主导航收敛、author/admin 并入 Settings Tab | 待续 |
| 2026-03-10 | Toast 通知系统落地:创建 utils/toast.ts纯原生全系统 18 文件约 90 处 alert 全部替换为 toast.success/error/info | 已完成 |
> **格式说明**:每次开发后在此追加一行,日期格式 YYYY-MM-DD状态用已完成 / 进行中 / 待续 / 搁置
---
**最后更新**2026-03-10
**最后更新**2026-03-10Toast 系统全局落地)

View File

@@ -16,3 +16,41 @@
> 详见会议纪要:`.cursor/meeting/2026-03-10_管理端迁移Mycontent-temp菜单布局讨论.md`
---
## Toast 通知系统全局落地
### 背景
管理端全部操作反馈使用原生 `alert()`,体验差、阻断操作流程、需点 OK 才能继续。
### 解决方案
创建 `soul-admin/src/utils/toast.ts`**纯原生 DOM 实现**,无第三方依赖):
```typescript
// 用法
import toast from '@/utils/toast'
toast.success('已保存:标题') // 绿色3s 消失
toast.error('保存失败: ...') // 红色3s 消失
toast.info('暂无数据') // 蓝色3s 消失
```
### 全系统替换
使用 PowerShell 批量脚本处理 **18 个文件、约 90 处 alert**,替换规则:
- 含"失败/错误/请填/不一致/必填" → `toast.error()`
- 含"成功/已保存/已删除/已创建" → `toast.success()`
- 其余 → `toast.info()`
替换后人工复查 `toast.info()` 调用,修正 5 处语义误判(验证提示类应为 error
### 规则沉淀
1. **管理端禁用 `alert()`**,统一使用 `@/utils/toast`
2. 新增页面/组件时,操作反馈一律用 toast
3. 批量脚本替换后,**必须**人工复查 `toast.info()` 是否有应为 `toast.error()` 的验证提示
4. toast 自动消失3s不阻断流程若需用户确认仍使用 `confirm()`
> 详见会议纪要:`.cursor/meeting/2026-03-10_Toast通知系统全局落地.md`

View File

@@ -0,0 +1,103 @@
# 会议纪要 - 2026-03-10 | Toast 通知系统全局落地 & hot_score 数据库迁移
> 本文件由**助理橙子**在会议结束后自动生成。
---
## 基本信息
- **时间**2026-03-10
- **议题**1) 文章保存后添加成功提示2) 数据库缺失 hot_score 字段报错修复3) 全系统 alert 替换为 toast 组件
- **触发方式**:用户反馈 → 逐步扩展到全系统改造
- **参与角色**:管理端开发工程师、后端开发、助理橙子
---
## 各角色发言
### 【管理端开发工程师】
当前管理端所有操作反馈都使用原生 `alert()`,体验差,阻断操作流程,用户必须手动点 OK 才能继续。需要一个统一的 toast 通知系统:非阻塞、自动消失、视觉语义化(绿色=成功、红色=错误、蓝色=信息)。
考虑到项目没有现成 toast 依赖sonner 安装失败),选择纯原生 DOM 实现 `src/utils/toast.ts`,无需第三方库,全量兼容现有项目。
### 【后端开发】
保存文章时报 `Error 1054 (42S22): Unknown column 'hot_score' in 'field list'`,原因是前端 `ContentPage.tsx` 已在 `handleSaveSection` 中传递 `hotScore` 字段,但后端 `Chapter` model 缺少该字段,且数据库 `chapters` 表也未建列。
需要两步修复:① ALTER TABLE 新增列;② 同步 model struct。
### 【助理橙子】
全系统 18 个文件约 90 处 alert 经 PowerShell 脚本批量替换。替换规则:
- 含"失败/错误/请填/不一致/必填"→ `toast.error()`
- 含"成功/已保存/已删除/已创建"→ `toast.success()`
- 其余→ `toast.info()`
事后人工复查,修正 5 处语义误判info 改 error
---
## 讨论过程
1. 用户提出"文章保存了要提示保存成功"
2. 管理端工程师创建 `src/utils/toast.ts`(纯原生,无依赖),替换 `ContentPage.tsx` 的 alert
3. 用户截图报错 `Unknown column 'hot_score'`
4. 后端工程师执行 `ALTER TABLE chapters ADD COLUMN hot_score INT NOT NULL DEFAULT 0`,更新 `chapter.go` model
5. 用户提出"整个系统的 alert 都可以改为 toast"
6. 助理橙子编写 PowerShell 批量替换脚本,处理 18 个文件
7. 人工复查 `toast.info()` 调用,将 5 处验证提示修正为 `toast.error()`
---
## 会议决议
1. **Toast 系统统一规范**:管理端所有用户反馈统一使用 `@/utils/toast`,禁止使用 `alert()`
2. **toast 类型语义**
- `toast.success()` → 操作成功、保存成功、删除成功
- `toast.error()` → 操作失败、表单验证不通过、接口报错
- `toast.info()` → 中性提示(无数据、当前状态说明)
3. **hot_score 字段**`chapters` 表已新增,`Chapter` model 已同步,热度分功能可正常保存
4. **数据库变更流程**model 字段与 DB 列必须同步维护ALTER TABLE 后立即更新 model struct
---
## 待办事项
| 责任角色 | 任务 | 优先级 | 截止建议 |
|---------|------|--------|---------|
| 管理端开发工程师 | 新增页面/组件时使用 toast 而非 alert已有规范 | 高 | 持续 |
| 后端开发 | hot_score 排名算法接口(若有)按此字段排序 | 低 | 待需求 |
---
## 问题与作答区
| # | 问题 | 责任角色 | 作答 |
|---|------|---------|------|
| 1 | hot_score 热度分的计算逻辑和更新时机是什么? | 产品经理/后端开发 | (待补充) |
| 2 | toast 是否需要支持持久化(不自动消失)的场景? | 管理端开发工程师 | (待补充) |
---
## 各角色经验与业务理解更新
### 后端开发
- `chapters` 表新增 `hot_score INT NOT NULL DEFAULT 0`,用于热度排名算法
- model struct 字段须与 DB 列同步,否则 GORM 写入报 1054 错误
### 管理端开发工程师
- 创建 `src/utils/toast.ts`:纯原生 DOM toast无第三方依赖支持 success/error/info
- 全系统 18 个文件约 90 处 `alert()` 已替换替换按语义分类info 类需人工复查
- 新规范:管理端禁用 `alert()`,统一使用 `toast.*`
### 团队共享
- **Toast 替换脚本方法论**:用 PowerShell 正则 + 语义关键词批量替换,替换后人工复查 `toast.info()` 是否应为 `toast.error()`(验证提示类常被误判)
- **DB 变更 SOP**:前端传新字段 → 后端先执行 ALTER TABLE → 再更新 model → 重启服务
---
*会议纪要由助理橙子生成 | 各角色经验已同步至 `agent/{角色}/evolution/2026-03-10.md`*

View File

@@ -71,3 +71,4 @@ YYYY-MM-DD_会议主题.md
| 2026-03-10 | 管理端迁移 Mycontent-temp 菜单/布局讨论 | 产品、后端、管理端、小程序、测试 | [2026-03-10_管理端迁移Mycontent-temp菜单布局讨论.md](2026-03-10_管理端迁移Mycontent-temp菜单布局讨论.md) |
| 2026-03-10 | 小程序新旧版对比分析与 dashboard-stats 接口新增 | 小程序、后端、团队 | [2026-03-10_小程序新旧版对比与dashboard接口新增.md](2026-03-10_小程序新旧版对比与dashboard接口新增.md) |
| 2026-03-10 | 文章详情三端功能对齐与开发(@mention/#linkTag/图片 | 产品、后端、管理端、小程序 | [2026-03-10_文章详情三端功能对齐与开发.md](2026-03-10_文章详情三端功能对齐与开发.md) |
| 2026-03-10 | Toast 通知系统全局落地 & hot_score 数据库迁移 | 管理端、后端、团队 | [2026-03-10_Toast通知系统全局落地.md](2026-03-10_Toast通知系统全局落地.md) |

View File

@@ -57,7 +57,7 @@ description: Soul 创业派对管理端开发规范。在 soul-admin/ 下编辑
**可选**:导出 CSV、列头排序、批量操作。
**禁止**:不得用原生 `alert`加载失败提示;不得调用 `/api/miniprogram/*`
**禁止**:不得用原生 `alert`任何提示(包括成功、失败、验证);不得调用 `/api/miniprogram/*`
**检查清单**分页、搜索防抖、刷新、loading、空状态、错误条、仅 admin/db 路径。详见 `开发文档/列表标准与角色分工.md`
@@ -65,7 +65,41 @@ description: Soul 创业派对管理端开发规范。在 soul-admin/ 下编辑
**口诀**:外边包 div/view内部 input width 100%。设置 input 的 padding、背景、边框时用 div 包裹 inputpadding 写在容器上input 仅做文字样式(`width: 100%`)。禁止在 input 自身上设 padding可避免光标截断、布局异常。React`<div className="form-input"><input className="form-input-inner" ... /></div>`
### 4.2 表单弹窗与「可选择+可手动填写」(吸收 SetVipModal 经验
### 4.2 用户操作反馈:统一使用 Toast禁止 alert
**规则**:管理端所有操作反馈(保存成功、操作失败、表单验证提示等)**必须使用 `@/utils/toast`**,严禁使用原生 `window.alert()`
```typescript
import toast from '@/utils/toast'
// ✅ 正确
toast.success('已保存')
toast.success(`章节「${title}」创建成功`)
toast.error('保存失败: ' + (res?.error || '未知错误'))
toast.error('请填写章节ID和标题') // 表单验证也用 error
toast.info('暂无数据可导出') // 中性说明用 info
// ❌ 错误
alert('已保存')
alert('保存失败')
```
**类型语义**
| 方法 | 使用场景 | 颜色 |
|------|---------|------|
| `toast.success()` | 操作成功、保存成功、创建/删除成功 | 绿色 |
| `toast.error()` | 接口报错、表单验证不通过、操作失败 | 红色 |
| `toast.info()` | 中性提示(无数据、当前状态说明) | 蓝色 |
**注意**
- `confirm()` 仍可用于删除等破坏性操作的二次确认
- toast 自动 3 秒消失,不阻断流程;若需用户强制确认才能继续,使用 `confirm()`
- 新增页面/组件时,**不得引入新的 `alert()`**
> 来源2026-03-10 全系统 alert → toast 改造18 文件约 90 处)
### 4.4 表单弹窗与「可选择+可手动填写」(吸收 SetVipModal 经验)
当表单需支持「从预设选项选择」或「手动填写自定义值」时:

View File

@@ -9,8 +9,8 @@ App({
globalData: {
// API基础地址 - 连接真实后端
// baseUrl: 'https://soulapi.quwanzhi.com',
// baseUrl: 'https://souldev.quwanzhi.com',
baseUrl: 'http://localhost:8080',
baseUrl: 'https://souldev.quwanzhi.com',
// baseUrl: 'http://localhost:8080',
// 小程序配置 - 真实AppID

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

779
soul-admin/dist/assets/index-GNzyAsgf.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -4,8 +4,8 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>管理后台 - Soul创业派对</title>
<script type="module" crossorigin src="/assets/index-DsLRWYbk.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-CXOwdtCt.css">
<script type="module" crossorigin src="/assets/index-GNzyAsgf.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-hM2iAGkr.css">
</head>
<body>
<div id="root"></div>

View File

@@ -1 +1 @@
{"root":["./src/app.tsx","./src/main.tsx","./src/vite-env.d.ts","./src/api/auth.ts","./src/api/client.ts","./src/components/richeditor.tsx","./src/components/modules/user/setvipmodal.tsx","./src/components/modules/user/userdetailmodal.tsx","./src/components/ui/pagination.tsx","./src/components/ui/badge.tsx","./src/components/ui/button.tsx","./src/components/ui/card.tsx","./src/components/ui/dialog.tsx","./src/components/ui/input.tsx","./src/components/ui/label.tsx","./src/components/ui/select.tsx","./src/components/ui/slider.tsx","./src/components/ui/switch.tsx","./src/components/ui/table.tsx","./src/components/ui/tabs.tsx","./src/components/ui/textarea.tsx","./src/hooks/usedebounce.ts","./src/layouts/adminlayout.tsx","./src/lib/utils.ts","./src/pages/admin-users/adminuserspage.tsx","./src/pages/api-doc/apidocpage.tsx","./src/pages/author-settings/authorsettingspage.tsx","./src/pages/chapters/chapterspage.tsx","./src/pages/content/chaptertree.tsx","./src/pages/content/contentpage.tsx","./src/pages/dashboard/dashboardpage.tsx","./src/pages/distribution/distributionpage.tsx","./src/pages/find-partner/findpartnerpage.tsx","./src/pages/find-partner/tabs/ckbconfigpanel.tsx","./src/pages/find-partner/tabs/ckbstatstab.tsx","./src/pages/find-partner/tabs/findpartnertab.tsx","./src/pages/find-partner/tabs/matchpooltab.tsx","./src/pages/find-partner/tabs/matchrecordstab.tsx","./src/pages/find-partner/tabs/mentorbookingtab.tsx","./src/pages/find-partner/tabs/mentortab.tsx","./src/pages/find-partner/tabs/resourcedockingtab.tsx","./src/pages/find-partner/tabs/teamrecruittab.tsx","./src/pages/login/loginpage.tsx","./src/pages/match/matchpage.tsx","./src/pages/match-records/matchrecordspage.tsx","./src/pages/mentor-consultations/mentorconsultationspage.tsx","./src/pages/mentors/mentorspage.tsx","./src/pages/not-found/notfoundpage.tsx","./src/pages/orders/orderspage.tsx","./src/pages/payment/paymentpage.tsx","./src/pages/qrcodes/qrcodespage.tsx","./src/pages/referral-settings/referralsettingspage.tsx","./src/pages/settings/settingspage.tsx","./src/pages/site/sitepage.tsx","./src/pages/users/userspage.tsx","./src/pages/vip-roles/viprolespage.tsx","./src/pages/withdrawals/withdrawalspage.tsx"],"version":"5.6.3"}
{"root":["./src/app.tsx","./src/main.tsx","./src/vite-env.d.ts","./src/api/auth.ts","./src/api/client.ts","./src/components/richeditor.tsx","./src/components/modules/user/setvipmodal.tsx","./src/components/modules/user/userdetailmodal.tsx","./src/components/ui/pagination.tsx","./src/components/ui/badge.tsx","./src/components/ui/button.tsx","./src/components/ui/card.tsx","./src/components/ui/dialog.tsx","./src/components/ui/input.tsx","./src/components/ui/label.tsx","./src/components/ui/select.tsx","./src/components/ui/slider.tsx","./src/components/ui/switch.tsx","./src/components/ui/table.tsx","./src/components/ui/tabs.tsx","./src/components/ui/textarea.tsx","./src/hooks/usedebounce.ts","./src/layouts/adminlayout.tsx","./src/lib/utils.ts","./src/pages/admin-users/adminuserspage.tsx","./src/pages/api-doc/apidocpage.tsx","./src/pages/author-settings/authorsettingspage.tsx","./src/pages/chapters/chapterspage.tsx","./src/pages/content/chaptertree.tsx","./src/pages/content/contentpage.tsx","./src/pages/dashboard/dashboardpage.tsx","./src/pages/distribution/distributionpage.tsx","./src/pages/find-partner/findpartnerpage.tsx","./src/pages/find-partner/tabs/ckbconfigpanel.tsx","./src/pages/find-partner/tabs/ckbstatstab.tsx","./src/pages/find-partner/tabs/findpartnertab.tsx","./src/pages/find-partner/tabs/matchpooltab.tsx","./src/pages/find-partner/tabs/matchrecordstab.tsx","./src/pages/find-partner/tabs/mentorbookingtab.tsx","./src/pages/find-partner/tabs/mentortab.tsx","./src/pages/find-partner/tabs/resourcedockingtab.tsx","./src/pages/find-partner/tabs/teamrecruittab.tsx","./src/pages/login/loginpage.tsx","./src/pages/match/matchpage.tsx","./src/pages/match-records/matchrecordspage.tsx","./src/pages/mentor-consultations/mentorconsultationspage.tsx","./src/pages/mentors/mentorspage.tsx","./src/pages/not-found/notfoundpage.tsx","./src/pages/orders/orderspage.tsx","./src/pages/payment/paymentpage.tsx","./src/pages/qrcodes/qrcodespage.tsx","./src/pages/referral-settings/referralsettingspage.tsx","./src/pages/settings/settingspage.tsx","./src/pages/site/sitepage.tsx","./src/pages/users/userspage.tsx","./src/pages/vip-roles/viprolespage.tsx","./src/pages/withdrawals/withdrawalspage.tsx","./src/utils/toast.ts"],"version":"5.6.3"}