feat: add note module and route fixes

This commit is contained in:
nepiedg
2026-04-17 07:48:44 +00:00
parent 866ddb046b
commit 84e1c0daac
25 changed files with 2196 additions and 38 deletions
+549
View File
@@ -0,0 +1,549 @@
# Note 模块接口文档
## 1. 模块说明
`note` 是独立于现有 `app/api` 业务的笔记小程序模块,代码位置如下:
- [app/note/controller](/root/work/tp/app/note/controller)
- [app/note/service](/root/work/tp/app/note/service)
- [app/note/model](/root/work/tp/app/note/model)
当前已实现能力:
1. 微信小程序登录
2. 笔记创建、列表、详情、更新、删除
3. 实时转写文本保存
4. AI 总结生成与查询
路由注册位置:
- [route/app.php](/root/work/tp/route/app.php)
---
## 2. 鉴权说明
除登录接口外,其余 `note` 接口都需要携带 JWT
- Header: `Authorization: Bearer {token}`
`note` 模块复用现有 JWT 机制,但要求 token 载荷中必须包含:
```json
{
"userid": 123,
"guard": "note"
}
```
说明:
- `userid` 对应 `note_user.id`
- `guard=note` 用于和旧 `api` 模块登录态隔离
---
## 3. 环境变量
微信登录依赖以下配置:
- `WECHAT_MINI_APPID`
- `WECHAT_MINI_SECRET`
- `DB_NOTE_HOSTNAME`
- `DB_NOTE_DATABASE`
- `DB_NOTE_USERNAME`
- `DB_NOTE_PASSWORD`
- `DB_NOTE_HOSTPORT`
示例位置:
- [\.example.env](/root/work/tp/.example.env)
---
## 4. 数据表
表结构定义位置:
- [database.sql](/root/work/tp/database.sql#L26)
当前 `note` 模块使用以下 4 张表:
1. `note_user`
用于小程序用户登录和用户资料
2. `note_item`
笔记主表,包含正文、转写累计文本、状态、录音时长等
3. `note_transcript`
实时转写分片记录表
4. `note_ai_summary`
AI 总结结果表
---
## 5. 接口列表
### 5.1 获取模块概览
- 方法:`GET`
- 路径:`/note/v1/meta/interfaces`
- 是否鉴权:否
用途:
- 返回 note 模块接口规划概览
---
### 5.2 微信小程序登录
- 方法:`POST`
- 路径:`/note/v1/auth/wechat-login`
- 是否鉴权:否
请求参数:
| 字段 | 类型 | 必填 | 说明 |
| :--- | :--- | :--- | :--- |
| `code` | string | 是 | `wx.login` 获取的临时 code |
| `nickname` | string | 否 | 用户昵称 |
| `avatar_url` | string | 否 | 用户头像地址 |
请求示例:
```json
{
"code": "021xxx",
"nickname": "张三",
"avatar_url": "https://example.com/avatar.png"
}
```
成功响应示例:
```json
{
"code": 200,
"msg": "登录成功",
"data": {
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.xxx",
"refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.xxx",
"expires_in": 604800,
"user": {
"id": 1,
"member_id": 0,
"openid": "oxxx",
"nickname": "张三",
"avatar_url": "https://example.com/avatar.png",
"mobile": "",
"is_new_user": true
}
},
"time": 1710000000
}
```
说明:
1. 首次登录时自动创建 `note_user`
2. 后续登录时按 `openid` 更新资料与最后登录时间
3. 若用户被禁用,返回 403
---
### 5.3 获取当前用户信息
- 方法:`GET`
- 路径:`/note/v1/auth/me`
- 是否鉴权:是
成功响应示例:
```json
{
"code": 200,
"msg": "success",
"data": {
"id": 1,
"member_id": 0,
"openid": "oxxx",
"nickname": "张三",
"avatar_url": "https://example.com/avatar.png",
"mobile": "",
"status": 1,
"last_login_time": 1710000000,
"created_at": 1710000000
},
"time": 1710000001
}
```
---
### 5.4 创建笔记
- 方法:`POST`
- 路径:`/note/v1/item/create`
- 是否鉴权:是
请求参数:
| 字段 | 类型 | 必填 | 说明 |
| :--- | :--- | :--- | :--- |
| `source_type` | string | 是 | `text` / `audio` / `mix` |
| `title` | string | 否 | 标题 |
| `content` | string | 否 | 正文 |
| `audio_duration_ms` | int | 否 | 录音时长 |
| `status` | string | 否 | 默认 `draft` |
请求示例:
```json
{
"source_type": "text",
"title": "会议纪要",
"content": "今天确认了下周需求排期",
"status": "draft"
}
```
成功响应示例:
```json
{
"code": 200,
"msg": "创建成功",
"data": {
"id": 10,
"note_user_id": 1,
"title": "会议纪要",
"content": "今天确认了下周需求排期",
"transcript_text": "",
"source_type": "text",
"status": "draft",
"audio_duration_ms": 0,
"summary_status": "none",
"last_transcript_time": 0,
"created_at": 1710000000,
"updated_at": 1710000000
},
"time": 1710000000
}
```
说明:
- 如果不传 `title`,后端会根据 `content` 自动生成标题
- 如果 `title``content` 都为空,标题会默认为 `未命名笔记`
---
### 5.5 笔记列表
- 方法:`GET`
- 路径:`/note/v1/item/list`
- 是否鉴权:是
查询参数:
| 字段 | 类型 | 必填 | 说明 |
| :--- | :--- | :--- | :--- |
| `page` | int | 否 | 默认 1 |
| `page_size` | int | 否 | 默认 10,最大 100 |
| `keyword` | string | 否 | 搜索标题、正文、转写文本 |
| `status` | string | 否 | 按状态筛选 |
响应示例:
```json
{
"code": 200,
"msg": "success",
"data": {
"list": [
{
"id": 10,
"note_user_id": 1,
"title": "会议纪要",
"content": "今天确认了下周需求排期",
"transcript_text": "",
"source_type": "text",
"status": "draft",
"audio_duration_ms": 0,
"summary_status": "none",
"last_transcript_time": 0,
"created_at": 1710000000,
"updated_at": 1710000000
}
],
"total": 1,
"page": 1,
"page_size": 10
},
"time": 1710000001
}
```
---
### 5.6 笔记详情
- 方法:`GET`
- 路径:`/note/v1/item/:id`
- 是否鉴权:是
响应示例:
```json
{
"code": 200,
"msg": "success",
"data": {
"id": 10,
"note_user_id": 1,
"title": "会议纪要",
"content": "今天确认了下周需求排期",
"transcript_text": "需要跟进接口联调",
"source_type": "mix",
"status": "draft",
"audio_duration_ms": 120000,
"summary_status": "success",
"last_transcript_time": 1710000100,
"created_at": 1710000000,
"updated_at": 1710000200,
"summary": {
"summary_id": 3,
"summary_type": "brief",
"summary_text": "今天确认了下周需求排期\n需要跟进接口联调",
"todo_list": [
"需要跟进接口联调"
],
"keywords": [
"需求",
"排期",
"接口联调"
],
"status": "success"
}
},
"time": 1710000201
}
```
---
### 5.7 更新笔记
- 方法:`POST`
- 路径:`/note/v1/item/update/:id`
- 是否鉴权:是
请求参数:
| 字段 | 类型 | 必填 | 说明 |
| :--- | :--- | :--- | :--- |
| `title` | string | 否 | 标题 |
| `content` | string | 否 | 正文 |
| `status` | string | 否 | 状态 |
| `audio_duration_ms` | int | 否 | 录音时长 |
说明:
- 只更新传入字段
- 只能更新自己的笔记
---
### 5.8 删除笔记
- 方法:`POST`
- 路径:`/note/v1/item/delete/:id`
- 是否鉴权:是
说明:
- 当前为软删除,写入 `deleted_at`
成功响应示例:
```json
{
"code": 200,
"msg": "删除成功",
"data": {
"deleted": true,
"id": 10
},
"time": 1710000300
}
```
---
### 5.9 保存实时转写内容
- 方法:`POST`
- 路径:`/note/v1/item/transcript/:id`
- 是否鉴权:是
请求参数:
| 字段 | 类型 | 必填 | 说明 |
| :--- | :--- | :--- | :--- |
| `full_text` | string | 是 | 当前累计完整转写文本 |
| `segment_no` | int | 否 | 分片序号,默认 0 |
| `segment_text` | string | 否 | 当前分片文本 |
| `is_final` | int/bool | 否 | 是否最终片段 |
| `audio_duration_ms` | int | 否 | 当前累计录音时长 |
请求示例:
```json
{
"segment_no": 3,
"segment_text": "需要跟进接口联调",
"full_text": "今天确认了下周需求排期,需要跟进接口联调",
"is_final": 1,
"audio_duration_ms": 120000
}
```
成功响应示例:
```json
{
"code": 200,
"msg": "转写保存成功",
"data": {
"note_id": 10,
"segment_no": 3,
"is_final": 1,
"transcript_text": "今天确认了下周需求排期,需要跟进接口联调",
"audio_duration_ms": 120000,
"updated_at": 1710000400
},
"time": 1710000400
}
```
说明:
- 后端会同步更新 `note_item.transcript_text`
- 同一个 `note_id + segment_no` 会覆盖写入
---
### 5.10 生成 AI 总结
- 方法:`POST`
- 路径:`/note/v1/ai/summary/:id`
- 是否鉴权:是
请求参数:
| 字段 | 类型 | 必填 | 说明 |
| :--- | :--- | :--- | :--- |
| `summary_type` | string | 否 | `brief` / `outline` / `todo` |
| `force_refresh` | int/bool | 否 | 是否强制重新生成 |
请求示例:
```json
{
"summary_type": "brief",
"force_refresh": 1
}
```
成功响应示例:
```json
{
"code": 200,
"msg": "总结生成成功",
"data": {
"summary_id": 3,
"note_id": 10,
"summary_type": "brief",
"summary_text": "今天确认了下周需求排期\n需要跟进接口联调",
"todo_list": [
"需要跟进接口联调"
],
"keywords": [
"需求",
"排期",
"接口联调"
],
"status": "success",
"error_message": "",
"created_at": 1710000500,
"updated_at": 1710000500
},
"time": 1710000500
}
```
说明:
- 当前实现为规则版总结,不依赖外部大模型
- 若已存在成功总结且 `force_refresh=0`,会直接返回已有结果
---
### 5.11 查看 AI 总结
- 方法:`GET`
- 路径:`/note/v1/ai/summary/:id`
- 是否鉴权:是
说明:
- 返回指定笔记最新的一条总结记录
---
## 6. 错误码约定
当前模块沿用项目统一返回结构:
```json
{
"code": 400,
"msg": "错误信息",
"data": [],
"time": 1710000000
}
```
常见情况:
- `400`:参数错误
- `401`:未登录或登录态无效
- `403`:用户被禁用
- `404`:资源不存在
- `500`:服务端错误
- `502`:调用微信接口失败
---
## 7. 调用顺序建议
小程序端推荐按以下顺序接入:
1.`wx.login`
2.`code` 发给 `POST /note/v1/auth/wechat-login`
3. 保存返回的 `token`
4. 创建笔记 `POST /note/v1/item/create`
5. 录音转写过程中持续调用 `POST /note/v1/item/transcript/:id`
6. 需要生成总结时调用 `POST /note/v1/ai/summary/:id`
7. 打开详情页时调用 `GET /note/v1/item/:id`
---
## 8. 当前限制
1. AI 总结目前是规则版,不是大模型版
2. 微信登录依赖服务端已正确配置 `WECHAT_MINI_APPID``WECHAT_MINI_SECRET`
3. 当前未实现文件音频上传,只实现了“转写文本写回后端”的数据链路