Compare commits
2 Commits
d317e439d4
...
93bde0a6b6
| Author | SHA1 | Date | |
|---|---|---|---|
| 93bde0a6b6 | |||
| 13db6e89f0 |
@@ -35,6 +35,7 @@
|
||||
- 新增业务 `admin` 模块时,如无明确例外,先提供这 6 个接口,再叠加业务特有接口。
|
||||
- 路由统一放在 `router/<module>`,接口统一放在 `api/v1/<module>`,业务统一放在 `service/<module>`,模型统一放在 `model/<module>`。
|
||||
- 新增业务路由后,必须同步在 `initialize/router_biz.go` 注册。
|
||||
- 新增或修改 `.ai-specs/doc-api/<端>/<resource>.md` 时,必须遵循 `.ai-specs/sys-specs/doc-api-doc-spec.md`。
|
||||
- 单个业务模块包含多个独立资源或多张业务表时,`api/v1/<module>`、`service/<module>`、`router/<module>` 必须按资源拆分文件;禁止把多个资源的 CRUD 长期堆在同一个大文件。
|
||||
- 单个业务模块包含多个独立资源或多张业务表时,`.ai-specs/doc-api/<端>/<resource>.md` 必须按资源拆分文档;禁止把多个资源的接口 contract 长期堆在同一个 doc-api 大文档。
|
||||
- 每个资源文件只承载该资源的 `API`、`Service` 或 `Router` 方法;跨资源复用逻辑只能放在明确命名的 `common.go`、`helper.go` 等公共文件,且公共文件禁止承载具体资源 CRUD 主流程。
|
||||
|
||||
@@ -1,29 +1,243 @@
|
||||
# 书籍信息 admin 接口
|
||||
# 书籍信息 admin 接口
|
||||
|
||||
## 基本信息
|
||||
|
||||
- 模块:book
|
||||
- 资源:书籍
|
||||
- 资源:书籍信息
|
||||
- 端:admin
|
||||
- 鉴权:挂载 `PrivateGroup`,需要 `JWT + Casbin`
|
||||
- 操作审计:创建、更新、单删、批量删除写操作启用 `OperationRecord`
|
||||
- 路由前缀:`/book`
|
||||
- 鉴权:`PrivateGroup`,需要 `JWT + Casbin`
|
||||
- 审计:创建、更新、单删、批量删除启用 `OperationRecord`
|
||||
- 前缀:`/book`
|
||||
- 实体模型:`book.Book`
|
||||
- 搜索入参:`bookReq.BookSearch`
|
||||
- 详情响应:`bookRes.BookResponse`
|
||||
- 列表项:`book.Book`
|
||||
- 返回:写操作 `response.Response{msg}`;详情 `response.Response{data}`;列表 `response.PageResult`
|
||||
- 删除策略:硬删
|
||||
|
||||
## 默认 CRUD
|
||||
## CRUD
|
||||
|
||||
| 动作 | Method | 路径 | API 方法 | Service 方法 |
|
||||
|:---|:---|:---|:---|:---|
|
||||
| 创建 | `POST` | `/book/createBook` | `CreateBook` | `CreateBook` |
|
||||
| 单删 | `DELETE` | `/book/deleteBook` | `DeleteBook` | `DeleteBook` |
|
||||
| 批量删除 | `DELETE` | `/book/deleteBookByIds` | `DeleteBookByIds` | `DeleteBookByIds` |
|
||||
| 更新 | `PUT` | `/book/updateBook` | `UpdateBook` | `UpdateBook` |
|
||||
| 详情 | `GET` | `/book/findBook` | `FindBook` | `GetBook` |
|
||||
| 分页列表 | `GET` | `/book/getBookList` | `GetBookList` | `GetBookInfoList` |
|
||||
### 创建书籍信息
|
||||
|
||||
## 参数与返回
|
||||
- Method:`POST`
|
||||
- Path:`/book/createBook`
|
||||
- Handler:`BookApi.CreateBook`
|
||||
- Service:`BookService.CreateBook`
|
||||
- 审计:是
|
||||
|
||||
- 创建、更新:`body` 使用 `book.Book`。
|
||||
- 单删、详情:`query id`。
|
||||
- 批量删除:`query ids[]`。
|
||||
- 分页列表:`query` 使用 `bookReq.BookSearch`,返回 `response.PageResult`。
|
||||
- 详情返回:`bookRes.BookResponse`。
|
||||
#### Request Body `book.Book`
|
||||
|
||||
| 字段 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| title | string | 是 | 非空,最大 `255` | 书名主标题 |
|
||||
| subtitle | string | 否 | 最大 `255` | 书籍副标题 |
|
||||
| bookType | string | 是 | 非空,值必须存在于系统字典 `book_type` | 书籍类型字典值 |
|
||||
| eraTag | string | 否 | `book_era_tag`:`unknown/ancient/han/tang/song/yuan/ming/qing/modern/contemporary`;默认 `unknown` | 时代标签字典值 |
|
||||
| coverUrl | string | 否 | 最大 `500` | 封面图片 URL |
|
||||
| publisher | string | 否 | 最大 `128` | 出版社名称 |
|
||||
| publishedAt | string | 否 | 日期类型 | 出版日期 |
|
||||
| intro | string | 否 | 文本 | 书籍简介 |
|
||||
| hotScore | int64 | 否 | `>= 0`;默认 `0` | 热度聚合值 |
|
||||
| rating | float64 | 否 | `0 <= rating <= 10`;默认 `0.0` | 书籍评分 |
|
||||
| commentCount | int64 | 否 | `>= 0`;默认 `0` | 点评数聚合值 |
|
||||
| wordCount | int64 | 否 | `>= 0`;默认 `0` | 书籍总字数 |
|
||||
| completionStatus | string | 否 | `book_completion_status`:`completed/serializing`;默认 `serializing` | 书籍完结状态 |
|
||||
| publishStatus | string | 否 | `book_publish_status`:`draft/off_shelf/on_shelf`;默认 `draft` | 书籍上下架状态 |
|
||||
| seriesId | uint | 否 | 可为空;存在时应为有效系列 ID | 所属系列 ID |
|
||||
| seriesSort | int | 否 | `>= 0`;默认 `0` | 同系列内展示排序 |
|
||||
| rawTxtUrl | string | 否 | 最大 `500` | 原始 txt 文件 URL |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
#### 规则
|
||||
|
||||
- 创建请求禁止传服务端生成字段:`id/createdAt/updatedAt`。
|
||||
- `bookType` 是动态值域字典,业务侧只校验值存在性,不参与状态流转。
|
||||
|
||||
### 删除书籍信息
|
||||
|
||||
- Method:`DELETE`
|
||||
- Path:`/book/deleteBook`
|
||||
- Handler:`BookApi.DeleteBook`
|
||||
- Service:`BookService.DeleteBook`
|
||||
- 审计:是
|
||||
|
||||
#### Request Query
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| id | int | 是 | `> 0` | 书籍 ID |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
### 批量删除书籍信息
|
||||
|
||||
- Method:`DELETE`
|
||||
- Path:`/book/deleteBookByIds`
|
||||
- Handler:`BookApi.DeleteBookByIds`
|
||||
- Service:`BookService.DeleteBookByIds`
|
||||
- 审计:是
|
||||
|
||||
#### Request Query
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| ids | int[] | 二选一 | 非空,元素均 `> 0` | 书籍 ID 数组 |
|
||||
| ids[] | int[] | 二选一 | 非空,元素均 `> 0` | 书籍 ID 数组,兼容数组写法 |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
#### 规则
|
||||
|
||||
- `ids` 与 `ids[]` 二选一。
|
||||
|
||||
### 更新书籍信息
|
||||
|
||||
- Method:`PUT`
|
||||
- Path:`/book/updateBook`
|
||||
- Handler:`BookApi.UpdateBook`
|
||||
- Service:`BookService.UpdateBook`
|
||||
- 审计:是
|
||||
|
||||
#### Request Body `book.Book`
|
||||
|
||||
| 字段 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| id | uint | 是 | `> 0` | 书籍 ID |
|
||||
| title | string | 是 | 非空,最大 `255` | 书名主标题 |
|
||||
| subtitle | string | 否 | 最大 `255` | 书籍副标题 |
|
||||
| bookType | string | 是 | 非空,值必须存在于系统字典 `book_type` | 书籍类型字典值 |
|
||||
| eraTag | string | 否 | `book_era_tag`:`unknown/ancient/han/tang/song/yuan/ming/qing/modern/contemporary` | 时代标签字典值 |
|
||||
| coverUrl | string | 否 | 最大 `500` | 封面图片 URL |
|
||||
| publisher | string | 否 | 最大 `128` | 出版社名称 |
|
||||
| publishedAt | string | 否 | 日期类型 | 出版日期 |
|
||||
| intro | string | 否 | 文本 | 书籍简介 |
|
||||
| hotScore | int64 | 否 | `>= 0` | 热度聚合值 |
|
||||
| rating | float64 | 否 | `0 <= rating <= 10` | 书籍评分 |
|
||||
| commentCount | int64 | 否 | `>= 0` | 点评数聚合值 |
|
||||
| wordCount | int64 | 否 | `>= 0` | 书籍总字数 |
|
||||
| completionStatus | string | 否 | `book_completion_status`:`completed/serializing` | 书籍完结状态 |
|
||||
| publishStatus | string | 否 | `book_publish_status`:`draft/off_shelf/on_shelf` | 书籍上下架状态 |
|
||||
| seriesId | uint | 否 | 可为空;存在时应为有效系列 ID | 所属系列 ID |
|
||||
| seriesSort | int | 否 | `>= 0` | 同系列内展示排序 |
|
||||
| rawTxtUrl | string | 否 | 最大 `500` | 原始 txt 文件 URL |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
#### 规则
|
||||
|
||||
- 更新请求禁止传服务端维护字段:`createdAt/updatedAt`。
|
||||
- 更新使用实体 `Save`,前端应传完整可编辑实体,避免字段被零值覆盖。
|
||||
- `bookType` 是动态值域字典,业务侧只校验值存在性,不参与状态流转。
|
||||
|
||||
### 查询书籍信息详情
|
||||
|
||||
- Method:`GET`
|
||||
- Path:`/book/findBook`
|
||||
- Handler:`BookApi.FindBook`
|
||||
- Service:`BookService.GetBook`
|
||||
- 审计:否
|
||||
|
||||
#### Request Query
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| id | int | 是 | `> 0` | 书籍 ID |
|
||||
|
||||
#### Response `bookRes.BookResponse`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|:---|:---|:---|
|
||||
| book | object | 书籍实体 |
|
||||
| book.id | uint | 主键 ID |
|
||||
| book.createdAt | string | 创建时间 |
|
||||
| book.updatedAt | string | 更新时间 |
|
||||
| book.title | string | 书名主标题 |
|
||||
| book.subtitle | string | 书籍副标题 |
|
||||
| book.bookType | string | 书籍类型字典值,对应 `book_type` |
|
||||
| book.eraTag | string | 时代标签字典值,对应 `book_era_tag` |
|
||||
| book.coverUrl | string | 封面图片 URL |
|
||||
| book.publisher | string | 出版社名称 |
|
||||
| book.publishedAt | string | 出版日期 |
|
||||
| book.intro | string | 书籍简介 |
|
||||
| book.hotScore | int64 | 热度聚合值 |
|
||||
| book.rating | float64 | 书籍评分,范围 `0-10` |
|
||||
| book.commentCount | int64 | 点评数聚合值 |
|
||||
| book.wordCount | int64 | 书籍总字数 |
|
||||
| book.completionStatus | string | 书籍完结状态字典值,对应 `book_completion_status` |
|
||||
| book.publishStatus | string | 书籍上下架状态字典值,对应 `book_publish_status` |
|
||||
| book.seriesId | uint | 所属系列 ID |
|
||||
| book.seriesSort | int | 同系列内展示排序 |
|
||||
| book.rawTxtUrl | string | 原始 txt 文件 URL |
|
||||
|
||||
### 分页查询书籍信息列表
|
||||
|
||||
- Method:`GET`
|
||||
- Path:`/book/getBookList`
|
||||
- Handler:`BookApi.GetBookList`
|
||||
- Service:`BookService.GetBookInfoList`
|
||||
- 审计:否
|
||||
|
||||
#### Request Query `bookReq.BookSearch`
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| page | int | 否 | 默认 `1`,最小 `1` | 页码 |
|
||||
| pageSize | int | 否 | 默认 `10`,最大 `100` | 每页数量 |
|
||||
| keyword | string | 否 | 模糊匹配 `title` 或 `subtitle` | 关键字 |
|
||||
| title | string | 否 | 模糊匹配 `title` | 书名主标题 |
|
||||
| bookType | string | 否 | 值必须存在于系统字典 `book_type` | 书籍类型 |
|
||||
| eraTag | string | 否 | `book_era_tag`:`unknown/ancient/han/tang/song/yuan/ming/qing/modern/contemporary` | 时代标签 |
|
||||
| completionStatus | string | 否 | `book_completion_status`:`completed/serializing` | 完结状态 |
|
||||
| publishStatus | string | 否 | `book_publish_status`:`draft/off_shelf/on_shelf` | 上下架状态 |
|
||||
| seriesId | uint | 否 | `> 0` | 系列 ID |
|
||||
|
||||
#### Response `response.PageResult`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|:---|:---|:---|
|
||||
| list | array | `book.Book` 列表 |
|
||||
| list[].id | uint | 主键 ID |
|
||||
| list[].createdAt | string | 创建时间 |
|
||||
| list[].updatedAt | string | 更新时间 |
|
||||
| list[].title | string | 书名主标题 |
|
||||
| list[].subtitle | string | 书籍副标题 |
|
||||
| list[].bookType | string | 书籍类型字典值,对应 `book_type` |
|
||||
| list[].eraTag | string | 时代标签字典值,对应 `book_era_tag` |
|
||||
| list[].coverUrl | string | 封面图片 URL |
|
||||
| list[].publisher | string | 出版社名称 |
|
||||
| list[].publishedAt | string | 出版日期 |
|
||||
| list[].intro | string | 书籍简介 |
|
||||
| list[].hotScore | int64 | 热度聚合值 |
|
||||
| list[].rating | float64 | 书籍评分,范围 `0-10` |
|
||||
| list[].commentCount | int64 | 点评数聚合值 |
|
||||
| list[].wordCount | int64 | 书籍总字数 |
|
||||
| list[].completionStatus | string | 书籍完结状态字典值,对应 `book_completion_status` |
|
||||
| list[].publishStatus | string | 书籍上下架状态字典值,对应 `book_publish_status` |
|
||||
| list[].seriesId | uint | 所属系列 ID |
|
||||
| list[].seriesSort | int | 同系列内展示排序 |
|
||||
| list[].rawTxtUrl | string | 原始 txt 文件 URL |
|
||||
| total | int64 | 总数 |
|
||||
| page | int | 当前页 |
|
||||
| pageSize | int | 每页数量 |
|
||||
|
||||
#### 规则
|
||||
|
||||
- 列表默认排序:`id desc`。
|
||||
|
||||
## 规则
|
||||
|
||||
- admin 端书籍信息 CRUD 统一挂载到 `PrivateGroup`,需要 `JWT + Casbin`。
|
||||
- 写操作启用 `OperationRecord`;读操作不启用操作审计。
|
||||
- 删除策略为硬删,实体使用 `book.HardDeleteModel`,不维护 `deleted_at`。
|
||||
- `eraTag/completionStatus/publishStatus` 必须符合对应固定值域字典。
|
||||
- `hotScore/commentCount/wordCount/seriesSort` 不能小于 `0`;`rating` 范围为 `0-10`。
|
||||
- `seriesId` 可为空;非空时表示书籍挂载到对应系列,展示排序使用 `seriesSort`。
|
||||
|
||||
@@ -1,29 +1,194 @@
|
||||
# 书籍作者 admin 接口
|
||||
# 书籍作者 admin 接口
|
||||
|
||||
## 基本信息
|
||||
|
||||
- 模块:book
|
||||
- 资源:作者
|
||||
- 资源:书籍作者
|
||||
- 端:admin
|
||||
- 鉴权:挂载 `PrivateGroup`,需要 `JWT + Casbin`
|
||||
- 操作审计:创建、更新、单删、批量删除写操作启用 `OperationRecord`
|
||||
- 路由前缀:`/book`
|
||||
- 鉴权:`PrivateGroup`,需要 `JWT + Casbin`
|
||||
- 审计:创建、更新、单删、批量删除启用 `OperationRecord`
|
||||
- 前缀:`/book`
|
||||
- 实体模型:`book.BookAuthor`
|
||||
- 搜索入参:`bookReq.BookAuthorSearch`
|
||||
- 详情响应:`bookRes.BookAuthorResponse`
|
||||
- 列表项:`bookRes.BookAuthorListItem`
|
||||
- 返回:写操作 `response.Response{msg}`;详情 `response.Response{data}`;列表 `response.PageResult`
|
||||
- 删除策略:硬删
|
||||
|
||||
## 默认 CRUD
|
||||
## CRUD
|
||||
|
||||
| 动作 | Method | 路径 | API 方法 | Service 方法 |
|
||||
|:---|:---|:---|:---|:---|
|
||||
| 创建 | `POST` | `/book/createBookAuthor` | `CreateBookAuthor` | `CreateBookAuthor` |
|
||||
| 单删 | `DELETE` | `/book/deleteBookAuthor` | `DeleteBookAuthor` | `DeleteBookAuthor` |
|
||||
| 批量删除 | `DELETE` | `/book/deleteBookAuthorByIds` | `DeleteBookAuthorByIds` | `DeleteBookAuthorByIds` |
|
||||
| 更新 | `PUT` | `/book/updateBookAuthor` | `UpdateBookAuthor` | `UpdateBookAuthor` |
|
||||
| 详情 | `GET` | `/book/findBookAuthor` | `FindBookAuthor` | `GetBookAuthor` |
|
||||
| 分页列表 | `GET` | `/book/getBookAuthorList` | `GetBookAuthorList` | `GetBookAuthorInfoList` |
|
||||
### 创建书籍作者
|
||||
|
||||
## 参数与返回
|
||||
- Method:`POST`
|
||||
- Path:`/book/createBookAuthor`
|
||||
- Handler:`BookAuthorApi.CreateBookAuthor`
|
||||
- Service:`BookAuthorService.CreateBookAuthor`
|
||||
- 审计:是
|
||||
|
||||
- 创建、更新:`body` 使用 `book.BookAuthor`。
|
||||
- 单删、详情:`query id`。
|
||||
- 批量删除:`query ids[]`。
|
||||
- 分页列表:`query` 使用 `bookReq.BookAuthorSearch`,返回 `response.PageResult`。
|
||||
- 详情返回:`bookRes.BookAuthorResponse`。
|
||||
#### Request Body `book.BookAuthor`
|
||||
|
||||
| 字段 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| name | string | 是 | 非空,最大 `128` 字符,唯一 | 作者名称 |
|
||||
| authorStatus | string | 否 | `common_enabled_status`:`enabled`/`disabled`;默认 `enabled` | 作者启用状态 |
|
||||
| intro | string | 否 | 可为空 | 作者简介 |
|
||||
| coverUrl | string | 否 | 可为空,最大 `500` 字符 | 作者头像或封面 URL |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
#### 规则
|
||||
|
||||
- 创建请求禁止传服务端生成字段:`id/createdAt/updatedAt`。
|
||||
- `name` 必须唯一,对应唯一索引 `uk_book_author_name`。
|
||||
- `authorStatus` 为空时按数据库默认值 `enabled` 落库;传值时必须符合 `common_enabled_status`。
|
||||
|
||||
### 删除书籍作者
|
||||
|
||||
- Method:`DELETE`
|
||||
- Path:`/book/deleteBookAuthor`
|
||||
- Handler:`BookAuthorApi.DeleteBookAuthor`
|
||||
- Service:`BookAuthorService.DeleteBookAuthor`
|
||||
- 审计:是
|
||||
|
||||
#### Request Query
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| id | int | 是 | `> 0` | 作者 ID |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
#### 规则
|
||||
|
||||
- 删除策略为硬删。
|
||||
|
||||
### 批量删除书籍作者
|
||||
|
||||
- Method:`DELETE`
|
||||
- Path:`/book/deleteBookAuthorByIds`
|
||||
- Handler:`BookAuthorApi.DeleteBookAuthorByIds`
|
||||
- Service:`BookAuthorService.DeleteBookAuthorByIds`
|
||||
- 审计:是
|
||||
|
||||
#### Request Query
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| ids | int[] | 二选一 | 非空,元素均 `> 0` | 作者 ID 数组 |
|
||||
| ids[] | int[] | 二选一 | 非空,元素均 `> 0` | 作者 ID 数组,兼容数组写法 |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
#### 规则
|
||||
|
||||
- `ids` 与 `ids[]` 二选一。
|
||||
- 删除策略为硬删。
|
||||
|
||||
### 更新书籍作者
|
||||
|
||||
- Method:`PUT`
|
||||
- Path:`/book/updateBookAuthor`
|
||||
- Handler:`BookAuthorApi.UpdateBookAuthor`
|
||||
- Service:`BookAuthorService.UpdateBookAuthor`
|
||||
- 审计:是
|
||||
|
||||
#### Request Body `book.BookAuthor`
|
||||
|
||||
| 字段 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| id | uint | 是 | `> 0` | 作者 ID |
|
||||
| name | string | 是 | 非空,最大 `128` 字符,唯一 | 作者名称 |
|
||||
| authorStatus | string | 否 | `common_enabled_status`:`enabled`/`disabled` | 作者启用状态 |
|
||||
| intro | string | 否 | 可为空 | 作者简介 |
|
||||
| coverUrl | string | 否 | 可为空,最大 `500` 字符 | 作者头像或封面 URL |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
#### 规则
|
||||
|
||||
- 更新请求禁止传服务端维护字段:`createdAt/updatedAt`。
|
||||
- 更新为实体全量保存,前端应传完整可编辑实体,避免字段被零值覆盖。
|
||||
- `name` 必须唯一,对应唯一索引 `uk_book_author_name`。
|
||||
- `authorStatus` 为空时会按空值保存;传值时必须符合 `common_enabled_status`。
|
||||
|
||||
### 查询书籍作者详情
|
||||
|
||||
- Method:`GET`
|
||||
- Path:`/book/findBookAuthor`
|
||||
- Handler:`BookAuthorApi.FindBookAuthor`
|
||||
- Service:`BookAuthorService.GetBookAuthor`
|
||||
- 审计:否
|
||||
|
||||
#### Request Query
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| id | int | 是 | `> 0` | 作者 ID |
|
||||
|
||||
#### Response `bookRes.BookAuthorResponse`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|:---|:---|:---|
|
||||
| bookAuthor | object | 作者实体 |
|
||||
| bookAuthor.id | uint | 作者 ID |
|
||||
| bookAuthor.createdAt | time | 创建时间 |
|
||||
| bookAuthor.updatedAt | time | 更新时间 |
|
||||
| bookAuthor.name | string | 作者名称 |
|
||||
| bookAuthor.authorStatus | string | 作者启用状态,见 `common_enabled_status` |
|
||||
| bookAuthor.intro | string | 作者简介 |
|
||||
| bookAuthor.coverUrl | string | 作者头像或封面 URL |
|
||||
|
||||
### 分页查询书籍作者列表
|
||||
|
||||
- Method:`GET`
|
||||
- Path:`/book/getBookAuthorList`
|
||||
- Handler:`BookAuthorApi.GetBookAuthorList`
|
||||
- Service:`BookAuthorService.GetBookAuthorInfoList`
|
||||
- 审计:否
|
||||
|
||||
#### Request Query `bookReq.BookAuthorSearch`
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| page | int | 否 | 默认 `1`,最小 `1` | 页码 |
|
||||
| pageSize | int | 否 | 默认 `10`,最大 `100` | 每页数量 |
|
||||
| keyword | string | 否 | 模糊匹配 `name` | 通用关键字 |
|
||||
| name | string | 否 | 模糊匹配 `name` | 作者名称 |
|
||||
| authorStatus | string | 否 | `common_enabled_status`:`enabled`/`disabled` | 作者启用状态 |
|
||||
|
||||
#### Response `response.PageResult`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|:---|:---|:---|
|
||||
| list | array | `bookRes.BookAuthorListItem` 列表 |
|
||||
| list[].id | uint | 作者 ID |
|
||||
| list[].createdAt | time | 创建时间 |
|
||||
| list[].updatedAt | time | 更新时间 |
|
||||
| list[].name | string | 作者名称 |
|
||||
| list[].authorStatus | string | 作者启用状态,见 `common_enabled_status` |
|
||||
| list[].intro | string | 作者简介 |
|
||||
| list[].coverUrl | string | 作者头像或封面 URL |
|
||||
| list[].authorName | string | 作者名称展示字段,来源于 `book_author.name AS author_name` |
|
||||
| total | int64 | 总数 |
|
||||
| page | int | 当前页 |
|
||||
| pageSize | int | 每页数量 |
|
||||
|
||||
#### 规则
|
||||
|
||||
- 列表默认排序:`id desc`。
|
||||
- `keyword` 与 `name` 同时传入时,会叠加为两个 `name LIKE` 条件。
|
||||
|
||||
## 规则
|
||||
|
||||
- admin 端书籍作者 CRUD 挂载到 `PrivateGroup`,需要 `JWT + Casbin`。
|
||||
- 写操作挂载 `middleware.OperationRecord()`;读操作不挂操作审计。
|
||||
- `authorStatus` 固定值域来自 `common_enabled_status`:`enabled`、`disabled`。
|
||||
- 表结构、字段长度、唯一约束和索引以 `.ai-specs/doc-sql/book_author.sql` 为准。
|
||||
|
||||
@@ -1,29 +1,180 @@
|
||||
# 书籍作者关系 admin 接口
|
||||
# 书籍作者关系 admin 接口
|
||||
|
||||
## 基本信息
|
||||
|
||||
- 模块:book
|
||||
- 资源:书籍作者关系
|
||||
- 端:admin
|
||||
- 鉴权:挂载 `PrivateGroup`,需要 `JWT + Casbin`
|
||||
- 操作审计:创建、更新、单删、批量删除写操作启用 `OperationRecord`
|
||||
- 路由前缀:`/book`
|
||||
- 鉴权:`PrivateGroup`,需要 `JWT + Casbin`
|
||||
- 审计:创建、更新、单删、批量删除启用 `OperationRecord`
|
||||
- 前缀:`/book`
|
||||
- 实体模型:`book.BookAuthorRelation`
|
||||
- 搜索入参:`bookReq.BookAuthorRelationSearch`
|
||||
- 详情响应:`bookRes.BookAuthorRelationResponse`
|
||||
- 列表项:`bookRes.BookAuthorRelationListItem`
|
||||
- 返回:写操作 `response.Response{msg}`;详情 `response.Response{data}`;列表 `response.PageResult`
|
||||
- 删除策略:硬删
|
||||
|
||||
## 默认 CRUD
|
||||
## CRUD
|
||||
|
||||
| 动作 | Method | 路径 | API 方法 | Service 方法 |
|
||||
|:---|:---|:---|:---|:---|
|
||||
| 创建 | `POST` | `/book/createBookAuthorRelation` | `CreateBookAuthorRelation` | `CreateBookAuthorRelation` |
|
||||
| 单删 | `DELETE` | `/book/deleteBookAuthorRelation` | `DeleteBookAuthorRelation` | `DeleteBookAuthorRelation` |
|
||||
| 批量删除 | `DELETE` | `/book/deleteBookAuthorRelationByIds` | `DeleteBookAuthorRelationByIds` | `DeleteBookAuthorRelationByIds` |
|
||||
| 更新 | `PUT` | `/book/updateBookAuthorRelation` | `UpdateBookAuthorRelation` | `UpdateBookAuthorRelation` |
|
||||
| 详情 | `GET` | `/book/findBookAuthorRelation` | `FindBookAuthorRelation` | `GetBookAuthorRelation` |
|
||||
| 分页列表 | `GET` | `/book/getBookAuthorRelationList` | `GetBookAuthorRelationList` | `GetBookAuthorRelationInfoList` |
|
||||
### 创建书籍作者关系
|
||||
|
||||
## 参数与返回
|
||||
- Method:`POST`
|
||||
- Path:`/book/createBookAuthorRelation`
|
||||
- Handler:`BookAuthorRelationApi.CreateBookAuthorRelation`
|
||||
- Service:`BookAuthorRelationService.CreateBookAuthorRelation`
|
||||
- 审计:是
|
||||
|
||||
- 创建、更新:`body` 使用 `book.BookAuthorRelation`。
|
||||
- 单删、详情:`query id`。
|
||||
- 批量删除:`query ids[]`。
|
||||
- 分页列表:`query` 使用 `bookReq.BookAuthorRelationSearch`,返回 `response.PageResult`。
|
||||
- 详情返回:`bookRes.BookAuthorRelationResponse`。
|
||||
#### Request Body `book.BookAuthorRelation`
|
||||
|
||||
| 字段 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| bookId | uint | 是 | `> 0` | 关联书籍 ID |
|
||||
| authorId | uint | 是 | `> 0` | 关联作者 ID |
|
||||
| authorSort | int | 否 | 未传或为 `0` 时默认 `1`;最终值必须 `> 0` | 展示顺序 |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
#### 规则
|
||||
|
||||
- 创建请求禁止传 `id/createdAt/updatedAt`。
|
||||
- 创建前必须校验 `bookId + authorId` 未被占用。
|
||||
|
||||
### 删除书籍作者关系
|
||||
|
||||
- Method:`DELETE`
|
||||
- Path:`/book/deleteBookAuthorRelation`
|
||||
- Handler:`BookAuthorRelationApi.DeleteBookAuthorRelation`
|
||||
- Service:`BookAuthorRelationService.DeleteBookAuthorRelation`
|
||||
- 审计:是
|
||||
|
||||
#### Request Query
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| id | int | 是 | `> 0` | 关系 ID |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
### 批量删除书籍作者关系
|
||||
|
||||
- Method:`DELETE`
|
||||
- Path:`/book/deleteBookAuthorRelationByIds`
|
||||
- Handler:`BookAuthorRelationApi.DeleteBookAuthorRelationByIds`
|
||||
- Service:`BookAuthorRelationService.DeleteBookAuthorRelationByIds`
|
||||
- 审计:是
|
||||
|
||||
#### Request Query
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| ids | int[] | 二选一 | 非空,元素均 `> 0` | 关系 ID 数组 |
|
||||
| ids[] | int[] | 二选一 | 非空,元素均 `> 0` | 关系 ID 数组,兼容数组写法 |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
#### 规则
|
||||
|
||||
- `ids` 与 `ids[]` 二选一。
|
||||
|
||||
### 更新书籍作者关系
|
||||
|
||||
- Method:`PUT`
|
||||
- Path:`/book/updateBookAuthorRelation`
|
||||
- Handler:`BookAuthorRelationApi.UpdateBookAuthorRelation`
|
||||
- Service:`BookAuthorRelationService.UpdateBookAuthorRelation`
|
||||
- 审计:是
|
||||
|
||||
#### Request Body `book.BookAuthorRelation`
|
||||
|
||||
| 字段 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| id | uint | 是 | `> 0` | 关系 ID |
|
||||
| bookId | uint | 是 | `> 0` | 关联书籍 ID |
|
||||
| authorId | uint | 是 | `> 0` | 关联作者 ID |
|
||||
| authorSort | int | 是 | `> 0` | 展示顺序 |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
#### 规则
|
||||
|
||||
- 更新请求禁止传 `createdAt/updatedAt`。
|
||||
- 更新前必须校验 `bookId + authorId` 未被其他记录占用。
|
||||
- 更新为实体全量保存,前端应传完整可编辑实体,避免字段被零值覆盖。
|
||||
|
||||
### 查询书籍作者关系详情
|
||||
|
||||
- Method:`GET`
|
||||
- Path:`/book/findBookAuthorRelation`
|
||||
- Handler:`BookAuthorRelationApi.FindBookAuthorRelation`
|
||||
- Service:`BookAuthorRelationService.GetBookAuthorRelation`
|
||||
- 审计:否
|
||||
|
||||
#### Request Query
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| id | int | 是 | `> 0` | 关系 ID |
|
||||
|
||||
#### Response `bookRes.BookAuthorRelationResponse`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|:---|:---|:---|
|
||||
| bookAuthorRelation | object | 关系实体 |
|
||||
| bookAuthorRelation.id | uint | 关系 ID |
|
||||
| bookAuthorRelation.bookId | uint | 书籍 ID |
|
||||
| bookAuthorRelation.authorId | uint | 作者 ID |
|
||||
| bookAuthorRelation.authorSort | int | 作者展示顺序 |
|
||||
| bookAuthorRelation.createdAt | string | 创建时间 |
|
||||
| bookAuthorRelation.updatedAt | string | 更新时间 |
|
||||
|
||||
### 分页查询书籍作者关系列表
|
||||
|
||||
- Method:`GET`
|
||||
- Path:`/book/getBookAuthorRelationList`
|
||||
- Handler:`BookAuthorRelationApi.GetBookAuthorRelationList`
|
||||
- Service:`BookAuthorRelationService.GetBookAuthorRelationInfoList`
|
||||
- 审计:否
|
||||
|
||||
#### Request Query `bookReq.BookAuthorRelationSearch`
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| page | int | 否 | 默认 `1`,最小 `1` | 页码 |
|
||||
| pageSize | int | 否 | 默认 `10`,最大 `100` | 每页数量 |
|
||||
| bookId | uint | 否 | `> 0` | 按书籍 ID 精确筛选 |
|
||||
| authorId | uint | 否 | `> 0` | 按作者 ID 精确筛选 |
|
||||
|
||||
#### Response `response.PageResult`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|:---|:---|:---|
|
||||
| list | array | `bookRes.BookAuthorRelationListItem` 列表 |
|
||||
| list[].id | uint | 关系 ID |
|
||||
| list[].bookId | uint | 书籍 ID |
|
||||
| list[].authorId | uint | 作者 ID |
|
||||
| list[].authorSort | int | 作者展示顺序 |
|
||||
| list[].authorName | string | 作者名称展示字段 |
|
||||
| total | int64 | 总数 |
|
||||
| page | int | 当前页 |
|
||||
| pageSize | int | 每页数量 |
|
||||
|
||||
#### 规则
|
||||
|
||||
- 列表默认排序:`bookId asc, authorSort asc, id desc`。
|
||||
|
||||
## 规则
|
||||
|
||||
- 默认鉴权为 `PrivateGroup`,需要 `JWT + Casbin`。
|
||||
- `bookId + authorId` 唯一,对应数据库唯一索引 `uk_book_author_relation_book_id_author_id`。
|
||||
- `authorSort` 必须大于 `0`。
|
||||
- 创建时 `authorSort` 未传或为 `0` 时默认 `1`。
|
||||
- 删除策略为硬删。
|
||||
|
||||
@@ -1,29 +1,201 @@
|
||||
# 书籍章节 admin 接口
|
||||
# 书籍章节 admin 接口
|
||||
|
||||
## 基本信息
|
||||
|
||||
- 模块:book
|
||||
- 资源:章节
|
||||
- 资源:书籍章节
|
||||
- 端:admin
|
||||
- 鉴权:挂载 `PrivateGroup`,需要 `JWT + Casbin`
|
||||
- 操作审计:创建、更新、单删、批量删除写操作启用 `OperationRecord`
|
||||
- 路由前缀:`/book`
|
||||
- 鉴权:`PrivateGroup`,需要 `JWT + Casbin`
|
||||
- 审计:创建、更新、单删、批量删除启用 `OperationRecord`
|
||||
- 前缀:`/book`
|
||||
- 实体模型:`book.BookChapter`
|
||||
- 搜索入参:`bookReq.BookChapterSearch`
|
||||
- 详情响应:`bookRes.BookChapterResponse`
|
||||
- 列表项:`book.BookChapter`
|
||||
- 返回:写操作 `response.Response{msg}`;详情 `response.Response{data}`;列表 `response.PageResult`
|
||||
- 删除策略:硬删
|
||||
|
||||
## 默认 CRUD
|
||||
## CRUD
|
||||
|
||||
| 动作 | Method | 路径 | API 方法 | Service 方法 |
|
||||
|:---|:---|:---|:---|:---|
|
||||
| 创建 | `POST` | `/book/createBookChapter` | `CreateBookChapter` | `CreateBookChapter` |
|
||||
| 单删 | `DELETE` | `/book/deleteBookChapter` | `DeleteBookChapter` | `DeleteBookChapter` |
|
||||
| 批量删除 | `DELETE` | `/book/deleteBookChapterByIds` | `DeleteBookChapterByIds` | `DeleteBookChapterByIds` |
|
||||
| 更新 | `PUT` | `/book/updateBookChapter` | `UpdateBookChapter` | `UpdateBookChapter` |
|
||||
| 详情 | `GET` | `/book/findBookChapter` | `FindBookChapter` | `GetBookChapter` |
|
||||
| 分页列表 | `GET` | `/book/getBookChapterList` | `GetBookChapterList` | `GetBookChapterInfoList` |
|
||||
### 创建书籍章节
|
||||
|
||||
## 参数与返回
|
||||
- Method:`POST`
|
||||
- Path:`/book/createBookChapter`
|
||||
- Handler:`BookChapterApi.CreateBookChapter`
|
||||
- Service:`BookChapterService.CreateBookChapter`
|
||||
- 审计:是
|
||||
|
||||
- 创建、更新:`body` 使用 `book.BookChapter`。
|
||||
- 单删、详情:`query id`。
|
||||
- 批量删除:`query ids[]`。
|
||||
- 分页列表:`query` 使用 `bookReq.BookChapterSearch`,返回 `response.PageResult`。
|
||||
- 详情返回:`bookRes.BookChapterResponse`。
|
||||
#### Request Body `book.BookChapter`
|
||||
|
||||
| 字段 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| bookId | uint | 是 | `> 0` | 所属书籍 ID |
|
||||
| title | string | 是 | 非空,最长 `255` | 章节标题 |
|
||||
| chapterNo | int | 是 | `> 0`;同一 `bookId` 下唯一 | 同书内章节顺序编号 |
|
||||
| isReadable | bool | 否 | 默认 `false`;为 `true` 时 `totalLines > 0` | 是否对 app 端开放阅读 |
|
||||
| contentFileUrl | string | 是 | 非空,最长 `500` | 章节内容文件 URL |
|
||||
| totalLines | int | 否 | 默认 `0`,`>= 0` | 章节正文总行数 |
|
||||
| isEnabled | bool | 否 | 默认 `true` | 章节是否启用 |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
#### 规则
|
||||
|
||||
- 创建请求禁止传服务端生成字段:`id/createdAt/updatedAt`。
|
||||
- `bookId + chapterNo` 唯一。
|
||||
- `isReadable=true` 时,`totalLines` 必须大于 `0`。
|
||||
|
||||
### 删除书籍章节
|
||||
|
||||
- Method:`DELETE`
|
||||
- Path:`/book/deleteBookChapter`
|
||||
- Handler:`BookChapterApi.DeleteBookChapter`
|
||||
- Service:`BookChapterService.DeleteBookChapter`
|
||||
- 审计:是
|
||||
|
||||
#### Request Query
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| id | int | 是 | `> 0` | 章节 ID |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
### 批量删除书籍章节
|
||||
|
||||
- Method:`DELETE`
|
||||
- Path:`/book/deleteBookChapterByIds`
|
||||
- Handler:`BookChapterApi.DeleteBookChapterByIds`
|
||||
- Service:`BookChapterService.DeleteBookChapterByIds`
|
||||
- 审计:是
|
||||
|
||||
#### Request Query
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| ids | int[] | 二选一 | 非空,元素均 `> 0` | 章节 ID 数组 |
|
||||
| ids[] | int[] | 二选一 | 非空,元素均 `> 0` | 章节 ID 数组,兼容数组写法 |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
#### 规则
|
||||
|
||||
- `ids` 与 `ids[]` 二选一。
|
||||
|
||||
### 更新书籍章节
|
||||
|
||||
- Method:`PUT`
|
||||
- Path:`/book/updateBookChapter`
|
||||
- Handler:`BookChapterApi.UpdateBookChapter`
|
||||
- Service:`BookChapterService.UpdateBookChapter`
|
||||
- 审计:是
|
||||
|
||||
#### Request Body `book.BookChapter`
|
||||
|
||||
| 字段 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| id | uint | 是 | `> 0` | 章节 ID |
|
||||
| bookId | uint | 是 | `> 0` | 所属书籍 ID |
|
||||
| title | string | 是 | 非空,最长 `255` | 章节标题 |
|
||||
| chapterNo | int | 是 | `> 0`;同一 `bookId` 下唯一 | 同书内章节顺序编号 |
|
||||
| isReadable | bool | 否 | 为 `true` 时 `totalLines > 0` | 是否对 app 端开放阅读 |
|
||||
| contentFileUrl | string | 是 | 非空,最长 `500` | 章节内容文件 URL |
|
||||
| totalLines | int | 否 | `>= 0` | 章节正文总行数 |
|
||||
| isEnabled | bool | 否 | 布尔值 | 章节是否启用 |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
#### 规则
|
||||
|
||||
- 更新请求禁止传服务端维护字段:`createdAt/updatedAt`。
|
||||
- 更新为实体全量保存,前端应传完整可编辑实体,避免字段被零值覆盖。
|
||||
- `bookId + chapterNo` 唯一。
|
||||
- `isReadable=true` 时,`totalLines` 必须大于 `0`。
|
||||
|
||||
### 查询书籍章节详情
|
||||
|
||||
- Method:`GET`
|
||||
- Path:`/book/findBookChapter`
|
||||
- Handler:`BookChapterApi.FindBookChapter`
|
||||
- Service:`BookChapterService.GetBookChapter`
|
||||
- 审计:否
|
||||
|
||||
#### Request Query
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| id | int | 是 | `> 0` | 章节 ID |
|
||||
|
||||
#### Response `bookRes.BookChapterResponse`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|:---|:---|:---|
|
||||
| bookChapter | object | 章节实体 |
|
||||
| bookChapter.id | uint | 章节 ID |
|
||||
| bookChapter.createdAt | string | 创建时间 |
|
||||
| bookChapter.updatedAt | string | 更新时间 |
|
||||
| bookChapter.bookId | uint | 所属书籍 ID |
|
||||
| bookChapter.title | string | 章节标题 |
|
||||
| bookChapter.chapterNo | int | 同书内章节顺序编号 |
|
||||
| bookChapter.isReadable | bool | 是否对 app 端开放阅读 |
|
||||
| bookChapter.contentFileUrl | string | 章节内容文件 URL |
|
||||
| bookChapter.totalLines | int | 章节正文总行数 |
|
||||
| bookChapter.isEnabled | bool | 章节是否启用 |
|
||||
|
||||
### 分页查询书籍章节列表
|
||||
|
||||
- Method:`GET`
|
||||
- Path:`/book/getBookChapterList`
|
||||
- Handler:`BookChapterApi.GetBookChapterList`
|
||||
- Service:`BookChapterService.GetBookChapterInfoList`
|
||||
- 审计:否
|
||||
|
||||
#### Request Query `bookReq.BookChapterSearch`
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| page | int | 否 | 默认 `1`,最小 `1` | 页码 |
|
||||
| pageSize | int | 否 | 默认 `10`,最大 `100` | 每页数量 |
|
||||
| keyword | string | 否 | 章节标题模糊查询 | 关键字 |
|
||||
| bookId | uint | 否 | `> 0` | 所属书籍 ID |
|
||||
| isReadable | bool | 否 | 布尔值 | 是否对 app 端开放阅读 |
|
||||
| isEnabled | bool | 否 | 布尔值 | 章节是否启用 |
|
||||
|
||||
#### Response `response.PageResult`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|:---|:---|:---|
|
||||
| list | array | `book.BookChapter` 列表 |
|
||||
| list[].id | uint | 章节 ID |
|
||||
| list[].createdAt | string | 创建时间 |
|
||||
| list[].updatedAt | string | 更新时间 |
|
||||
| list[].bookId | uint | 所属书籍 ID |
|
||||
| list[].title | string | 章节标题 |
|
||||
| list[].chapterNo | int | 同书内章节顺序编号 |
|
||||
| list[].isReadable | bool | 是否对 app 端开放阅读 |
|
||||
| list[].contentFileUrl | string | 章节内容文件 URL |
|
||||
| list[].totalLines | int | 章节正文总行数 |
|
||||
| list[].isEnabled | bool | 章节是否启用 |
|
||||
| total | int64 | 总数 |
|
||||
| page | int | 当前页 |
|
||||
| pageSize | int | 每页数量 |
|
||||
|
||||
#### 规则
|
||||
|
||||
- 列表默认排序:`book_id asc, chapter_no asc`。
|
||||
|
||||
## 规则
|
||||
|
||||
- 章节使用硬删;删除后数据库不保留软删标记。
|
||||
- `bookId + chapterNo` 是章节唯一约束;新增或更新时不能与同书已有章节冲突。
|
||||
- `chapterNo` 必须大于 `0`。
|
||||
- `totalLines` 不能小于 `0`;`isReadable=true` 时 `totalLines` 必须大于 `0`。
|
||||
- 创建、更新复用实体 `book.BookChapter`;列表查询复用 `bookReq.BookChapterSearch`;详情返回 `bookRes.BookChapterResponse`。
|
||||
|
||||
@@ -1,29 +1,199 @@
|
||||
# 书籍评论 admin 接口
|
||||
# 书籍评论 admin 接口
|
||||
|
||||
## 基本信息
|
||||
|
||||
- 模块:book
|
||||
- 资源:评论
|
||||
- 资源:书籍评论
|
||||
- 端:admin
|
||||
- 鉴权:挂载 `PrivateGroup`,需要 `JWT + Casbin`
|
||||
- 操作审计:创建、更新、单删、批量删除写操作启用 `OperationRecord`
|
||||
- 路由前缀:`/book`
|
||||
- 鉴权:`PrivateGroup`,需要 `JWT + Casbin`
|
||||
- 审计:创建、更新、单删、批量删除启用 `OperationRecord`
|
||||
- 前缀:`/book`
|
||||
- 实体模型:`book.BookComment`
|
||||
- 搜索入参:`bookReq.BookCommentSearch`
|
||||
- 详情响应:`bookRes.BookCommentResponse`
|
||||
- 返回:写操作 `response.Response{msg}`;详情 `response.Response{data}`;列表 `response.PageResult`
|
||||
- 删除策略:硬删
|
||||
|
||||
## 默认 CRUD
|
||||
## CRUD
|
||||
|
||||
| 动作 | Method | 路径 | API 方法 | Service 方法 |
|
||||
|:---|:---|:---|:---|:---|
|
||||
| 创建 | `POST` | `/book/createBookComment` | `CreateBookComment` | `CreateBookComment` |
|
||||
| 单删 | `DELETE` | `/book/deleteBookComment` | `DeleteBookComment` | `DeleteBookComment` |
|
||||
| 批量删除 | `DELETE` | `/book/deleteBookCommentByIds` | `DeleteBookCommentByIds` | `DeleteBookCommentByIds` |
|
||||
| 更新 | `PUT` | `/book/updateBookComment` | `UpdateBookComment` | `UpdateBookComment` |
|
||||
| 详情 | `GET` | `/book/findBookComment` | `FindBookComment` | `GetBookComment` |
|
||||
| 分页列表 | `GET` | `/book/getBookCommentList` | `GetBookCommentList` | `GetBookCommentInfoList` |
|
||||
### 创建书籍评论
|
||||
|
||||
## 参数与返回
|
||||
- Method:`POST`
|
||||
- Path:`/book/createBookComment`
|
||||
- Handler:`BookCommentApi.CreateBookComment`
|
||||
- Service:`BookCommentService.CreateBookComment`
|
||||
- 审计:是
|
||||
|
||||
- 创建、更新:`body` 使用 `book.BookComment`。
|
||||
- 单删、详情:`query id`。
|
||||
- 批量删除:`query ids[]`。
|
||||
- 分页列表:`query` 使用 `bookReq.BookCommentSearch`,返回 `response.PageResult`。
|
||||
- 详情返回:`bookRes.BookCommentResponse`。
|
||||
#### Request Body `book.BookComment`
|
||||
|
||||
| 字段 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| memberUserId | uint | 是 | 数据库非空 | 评论用户的会员 ID |
|
||||
| bookId | uint | 是 | 数据库非空 | 所属书籍 ID |
|
||||
| chapterId | uint | 否 | 默认 `0`;`>= 0` | 评论目标章节 ID,`0` 表示整本书 |
|
||||
| lineIndex | int | 否 | 默认 `0`;`>= 0`;整书评论时必须为 `0` | 评论目标文本行下标,`0` 表示整章或整本书 |
|
||||
| content | string | 是 | 数据库非空 | 评论正文内容 |
|
||||
| likeCount | int64 | 否 | 默认 `0`;`>= 0` | 评论点赞聚合值 |
|
||||
| commentStatus | string | 否 | 默认 `normal`;仅允许 `normal/hidden` | 评论状态字典值,对应 `book_comment_status` |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
#### 规则
|
||||
|
||||
- 创建请求禁止传服务端生成字段:`id/createdAt/updatedAt`。
|
||||
- `chapterId=0` 表示整书评论,此时 `lineIndex` 必须为 `0`。
|
||||
- `chapterId>0` 时允许 `lineIndex>=0`,其中 `lineIndex=0` 表示整章评论。
|
||||
|
||||
### 删除书籍评论
|
||||
|
||||
- Method:`DELETE`
|
||||
- Path:`/book/deleteBookComment`
|
||||
- Handler:`BookCommentApi.DeleteBookComment`
|
||||
- Service:`BookCommentService.DeleteBookComment`
|
||||
- 审计:是
|
||||
|
||||
#### Request Query
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| id | int | 是 | `> 0` | 评论 ID |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
### 批量删除书籍评论
|
||||
|
||||
- Method:`DELETE`
|
||||
- Path:`/book/deleteBookCommentByIds`
|
||||
- Handler:`BookCommentApi.DeleteBookCommentByIds`
|
||||
- Service:`BookCommentService.DeleteBookCommentByIds`
|
||||
- 审计:是
|
||||
|
||||
#### Request Query
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| ids | int[] | 二选一 | 非空,元素均为主键 ID | 评论 ID 数组 |
|
||||
| ids[] | int[] | 二选一 | 非空,元素均为主键 ID | 评论 ID 数组,兼容数组写法 |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
#### 规则
|
||||
|
||||
- `ids` 与 `ids[]` 二选一。
|
||||
|
||||
### 更新书籍评论
|
||||
|
||||
- Method:`PUT`
|
||||
- Path:`/book/updateBookComment`
|
||||
- Handler:`BookCommentApi.UpdateBookComment`
|
||||
- Service:`BookCommentService.UpdateBookComment`
|
||||
- 审计:是
|
||||
|
||||
#### Request Body `book.BookComment`
|
||||
|
||||
| 字段 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| id | uint | 是 | `> 0` | 评论 ID |
|
||||
| memberUserId | uint | 是 | 数据库非空 | 评论用户的会员 ID |
|
||||
| bookId | uint | 是 | 数据库非空 | 所属书籍 ID |
|
||||
| chapterId | uint | 否 | 默认 `0`;`>= 0` | 评论目标章节 ID,`0` 表示整本书 |
|
||||
| lineIndex | int | 否 | 默认 `0`;`>= 0`;整书评论时必须为 `0` | 评论目标文本行下标,`0` 表示整章或整本书 |
|
||||
| content | string | 是 | 数据库非空 | 评论正文内容 |
|
||||
| likeCount | int64 | 否 | 默认 `0`;`>= 0` | 评论点赞聚合值 |
|
||||
| commentStatus | string | 否 | 默认 `normal`;仅允许 `normal/hidden` | 评论状态字典值,对应 `book_comment_status` |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
#### 规则
|
||||
|
||||
- 更新请求禁止传服务端维护字段:`createdAt/updatedAt`。
|
||||
- 更新为实体全量保存,前端应传完整可编辑实体,避免字段被零值覆盖。
|
||||
- `chapterId=0` 表示整书评论,此时 `lineIndex` 必须为 `0`。
|
||||
- `chapterId>0` 时允许 `lineIndex>=0`,其中 `lineIndex=0` 表示整章评论。
|
||||
|
||||
### 查询书籍评论详情
|
||||
|
||||
- Method:`GET`
|
||||
- Path:`/book/findBookComment`
|
||||
- Handler:`BookCommentApi.FindBookComment`
|
||||
- Service:`BookCommentService.GetBookComment`
|
||||
- 审计:否
|
||||
|
||||
#### Request Query
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| id | int | 是 | `> 0` | 评论 ID |
|
||||
|
||||
#### Response `bookRes.BookCommentResponse`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|:---|:---|:---|
|
||||
| bookComment | object | 评论实体 |
|
||||
| bookComment.id | uint | 评论 ID |
|
||||
| bookComment.createdAt | time | 创建时间 |
|
||||
| bookComment.updatedAt | time | 更新时间 |
|
||||
| bookComment.memberUserId | uint | 评论用户的会员 ID |
|
||||
| bookComment.bookId | uint | 所属书籍 ID |
|
||||
| bookComment.chapterId | uint | 评论目标章节 ID,`0` 表示整本书 |
|
||||
| bookComment.lineIndex | int | 评论目标文本行下标,`0` 表示整章或整本书 |
|
||||
| bookComment.content | string | 评论正文内容 |
|
||||
| bookComment.likeCount | int64 | 评论点赞聚合值 |
|
||||
| bookComment.commentStatus | string | 评论状态字典值,对应 `book_comment_status` |
|
||||
|
||||
### 分页查询书籍评论列表
|
||||
|
||||
- Method:`GET`
|
||||
- Path:`/book/getBookCommentList`
|
||||
- Handler:`BookCommentApi.GetBookCommentList`
|
||||
- Service:`BookCommentService.GetBookCommentInfoList`
|
||||
- 审计:否
|
||||
|
||||
#### Request Query `bookReq.BookCommentSearch`
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| page | int | 否 | 默认 `1`,最小 `1` | 页码 |
|
||||
| pageSize | int | 否 | 默认 `10`,最大 `100` | 每页数量 |
|
||||
| memberUserId | uint | 否 | 精确匹配 | 评论用户的会员 ID |
|
||||
| bookId | uint | 否 | 精确匹配 | 所属书籍 ID |
|
||||
| chapterId | uint | 否 | 精确匹配 | 评论目标章节 ID,`0` 表示整本书 |
|
||||
| commentStatus | string | 否 | 仅允许 `normal/hidden` | 评论状态字典值,对应 `book_comment_status` |
|
||||
|
||||
#### Response `response.PageResult`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|:---|:---|:---|
|
||||
| list | array | `book.BookComment` 列表 |
|
||||
| list[].id | uint | 评论 ID |
|
||||
| list[].createdAt | time | 创建时间 |
|
||||
| list[].updatedAt | time | 更新时间 |
|
||||
| list[].memberUserId | uint | 评论用户的会员 ID |
|
||||
| list[].bookId | uint | 所属书籍 ID |
|
||||
| list[].chapterId | uint | 评论目标章节 ID,`0` 表示整本书 |
|
||||
| list[].lineIndex | int | 评论目标文本行下标,`0` 表示整章或整本书 |
|
||||
| list[].content | string | 评论正文内容 |
|
||||
| list[].likeCount | int64 | 评论点赞聚合值 |
|
||||
| list[].commentStatus | string | 评论状态字典值,对应 `book_comment_status` |
|
||||
| total | int64 | 总数 |
|
||||
| page | int | 当前页 |
|
||||
| pageSize | int | 每页数量 |
|
||||
|
||||
#### 规则
|
||||
|
||||
- 列表默认排序:`id desc`。
|
||||
|
||||
## 规则
|
||||
|
||||
- `commentStatus` 必须符合 `book_comment_status`:`normal` 正常,`hidden` 隐藏。
|
||||
- `lineIndex/likeCount` 不能小于 `0`。
|
||||
- 整书评论 `chapterId=0` 时 `lineIndex` 必须为 `0`。
|
||||
- 删除策略为硬删。
|
||||
|
||||
@@ -1,29 +1,180 @@
|
||||
# 评论点赞记录 admin 接口
|
||||
# 评论点赞记录 admin 接口
|
||||
|
||||
## 基本信息
|
||||
|
||||
- 模块:book
|
||||
- 资源:评论点赞记录
|
||||
- 端:admin
|
||||
- 鉴权:挂载 `PrivateGroup`,需要 `JWT + Casbin`
|
||||
- 操作审计:创建、更新、单删、批量删除写操作启用 `OperationRecord`
|
||||
- 路由前缀:`/book`
|
||||
- 鉴权:`PrivateGroup`,需要 `JWT + Casbin`
|
||||
- 审计:创建、更新、单删、批量删除启用 `OperationRecord`
|
||||
- 前缀:`/book`
|
||||
- 实体模型:`book.BookCommentLikeRecord`
|
||||
- 搜索入参:`bookReq.BookCommentLikeRecordSearch`
|
||||
- 详情响应:`bookRes.BookCommentLikeRecordResponse`
|
||||
- 列表项:`book.BookCommentLikeRecord`
|
||||
- 返回:写操作 `response.Response{msg}`;详情 `response.Response{data}`;列表 `response.PageResult`
|
||||
- 删除策略:硬删
|
||||
|
||||
## 默认 CRUD
|
||||
## CRUD
|
||||
|
||||
| 动作 | Method | 路径 | API 方法 | Service 方法 |
|
||||
|:---|:---|:---|:---|:---|
|
||||
| 创建 | `POST` | `/book/createBookCommentLikeRecord` | `CreateBookCommentLikeRecord` | `CreateBookCommentLikeRecord` |
|
||||
| 单删 | `DELETE` | `/book/deleteBookCommentLikeRecord` | `DeleteBookCommentLikeRecord` | `DeleteBookCommentLikeRecord` |
|
||||
| 批量删除 | `DELETE` | `/book/deleteBookCommentLikeRecordByIds` | `DeleteBookCommentLikeRecordByIds` | `DeleteBookCommentLikeRecordByIds` |
|
||||
| 更新 | `PUT` | `/book/updateBookCommentLikeRecord` | `UpdateBookCommentLikeRecord` | `UpdateBookCommentLikeRecord` |
|
||||
| 详情 | `GET` | `/book/findBookCommentLikeRecord` | `FindBookCommentLikeRecord` | `GetBookCommentLikeRecord` |
|
||||
| 分页列表 | `GET` | `/book/getBookCommentLikeRecordList` | `GetBookCommentLikeRecordList` | `GetBookCommentLikeRecordInfoList` |
|
||||
### 创建评论点赞记录
|
||||
|
||||
## 参数与返回
|
||||
- Method:`POST`
|
||||
- Path:`/book/createBookCommentLikeRecord`
|
||||
- Handler:`BookCommentLikeRecordApi.CreateBookCommentLikeRecord`
|
||||
- Service:`BookCommentLikeRecordService.CreateBookCommentLikeRecord`
|
||||
- 审计:是
|
||||
|
||||
- 创建、更新:`body` 使用 `book.BookCommentLikeRecord`。
|
||||
- 单删、详情:`query id`。
|
||||
- 批量删除:`query ids[]`。
|
||||
- 分页列表:`query` 使用 `bookReq.BookCommentLikeRecordSearch`,返回 `response.PageResult`。
|
||||
- 详情返回:`bookRes.BookCommentLikeRecordResponse`。
|
||||
#### Request Body `book.BookCommentLikeRecord`
|
||||
|
||||
| 字段 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| commentId | uint | 是 | `> 0`;与 `memberUserId` 组成唯一约束 | 被点赞评论 ID |
|
||||
| memberUserId | uint | 是 | `> 0`;与 `commentId` 组成唯一约束 | 点赞用户的会员 ID |
|
||||
| likedAt | string | 否 | RFC3339 时间;不传使用数据库默认 `CURRENT_TIMESTAMP` | 点赞发生时间 |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
#### 规则
|
||||
|
||||
- 创建请求禁止传服务端生成字段:`id/createdAt/updatedAt`。
|
||||
- `commentId + memberUserId` 必须唯一;重复创建应返回失败,不得生成重复有效点赞关系。
|
||||
|
||||
### 删除评论点赞记录
|
||||
|
||||
- Method:`DELETE`
|
||||
- Path:`/book/deleteBookCommentLikeRecord`
|
||||
- Handler:`BookCommentLikeRecordApi.DeleteBookCommentLikeRecord`
|
||||
- Service:`BookCommentLikeRecordService.DeleteBookCommentLikeRecord`
|
||||
- 审计:是
|
||||
|
||||
#### Request Query
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| id | int | 是 | `> 0` | 点赞记录 ID |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
### 批量删除评论点赞记录
|
||||
|
||||
- Method:`DELETE`
|
||||
- Path:`/book/deleteBookCommentLikeRecordByIds`
|
||||
- Handler:`BookCommentLikeRecordApi.DeleteBookCommentLikeRecordByIds`
|
||||
- Service:`BookCommentLikeRecordService.DeleteBookCommentLikeRecordByIds`
|
||||
- 审计:是
|
||||
|
||||
#### Request Query
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| ids | int[] | 二选一 | 非空,元素均 `> 0` | 点赞记录 ID 数组 |
|
||||
| ids[] | int[] | 二选一 | 非空,元素均 `> 0` | 点赞记录 ID 数组,兼容数组写法 |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
#### 规则
|
||||
|
||||
- `ids` 与 `ids[]` 二选一。
|
||||
|
||||
### 更新评论点赞记录
|
||||
|
||||
- Method:`PUT`
|
||||
- Path:`/book/updateBookCommentLikeRecord`
|
||||
- Handler:`BookCommentLikeRecordApi.UpdateBookCommentLikeRecord`
|
||||
- Service:`BookCommentLikeRecordService.UpdateBookCommentLikeRecord`
|
||||
- 审计:是
|
||||
|
||||
#### Request Body `book.BookCommentLikeRecord`
|
||||
|
||||
| 字段 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| id | uint | 是 | `> 0` | 点赞记录 ID |
|
||||
| commentId | uint | 是 | `> 0`;与 `memberUserId` 组成唯一约束 | 被点赞评论 ID |
|
||||
| memberUserId | uint | 是 | `> 0`;与 `commentId` 组成唯一约束 | 点赞用户的会员 ID |
|
||||
| likedAt | string | 是 | RFC3339 时间;不能为空 | 点赞发生时间 |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
#### 规则
|
||||
|
||||
- 更新请求禁止传服务端维护字段:`createdAt/updatedAt`。
|
||||
- 更新为实体全量保存,前端必须传完整可编辑实体,避免字段被零值覆盖。
|
||||
- 更新后的 `commentId + memberUserId` 必须继续满足唯一约束。
|
||||
|
||||
### 查询评论点赞记录详情
|
||||
|
||||
- Method:`GET`
|
||||
- Path:`/book/findBookCommentLikeRecord`
|
||||
- Handler:`BookCommentLikeRecordApi.FindBookCommentLikeRecord`
|
||||
- Service:`BookCommentLikeRecordService.GetBookCommentLikeRecord`
|
||||
- 审计:否
|
||||
|
||||
#### Request Query
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| id | int | 是 | `> 0` | 点赞记录 ID |
|
||||
|
||||
#### Response `bookRes.BookCommentLikeRecordResponse`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|:---|:---|:---|
|
||||
| bookCommentLikeRecord | object | 点赞记录实体 |
|
||||
| bookCommentLikeRecord.id | uint | 点赞记录 ID |
|
||||
| bookCommentLikeRecord.createdAt | string | 创建时间 |
|
||||
| bookCommentLikeRecord.updatedAt | string | 更新时间 |
|
||||
| bookCommentLikeRecord.commentId | uint | 被点赞评论 ID |
|
||||
| bookCommentLikeRecord.memberUserId | uint | 点赞用户的会员 ID |
|
||||
| bookCommentLikeRecord.likedAt | string | 点赞发生时间 |
|
||||
|
||||
### 分页查询评论点赞记录列表
|
||||
|
||||
- Method:`GET`
|
||||
- Path:`/book/getBookCommentLikeRecordList`
|
||||
- Handler:`BookCommentLikeRecordApi.GetBookCommentLikeRecordList`
|
||||
- Service:`BookCommentLikeRecordService.GetBookCommentLikeRecordInfoList`
|
||||
- 审计:否
|
||||
|
||||
#### Request Query `bookReq.BookCommentLikeRecordSearch`
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| page | int | 否 | 默认 `1`,最小 `1` | 页码 |
|
||||
| pageSize | int | 否 | 默认 `10`,最大 `100` | 每页数量 |
|
||||
| commentId | uint | 否 | `> 0` | 按被点赞评论 ID 筛选 |
|
||||
| memberUserId | uint | 否 | `> 0` | 按点赞用户的会员 ID 筛选 |
|
||||
|
||||
#### Response `response.PageResult`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|:---|:---|:---|
|
||||
| list | array | `book.BookCommentLikeRecord` 列表 |
|
||||
| list[].id | uint | 点赞记录 ID |
|
||||
| list[].createdAt | string | 创建时间 |
|
||||
| list[].updatedAt | string | 更新时间 |
|
||||
| list[].commentId | uint | 被点赞评论 ID |
|
||||
| list[].memberUserId | uint | 点赞用户的会员 ID |
|
||||
| list[].likedAt | string | 点赞发生时间 |
|
||||
| total | int64 | 总数 |
|
||||
| page | int | 当前页 |
|
||||
| pageSize | int | 每页数量 |
|
||||
|
||||
#### 规则
|
||||
|
||||
- 列表默认排序:`id desc`。
|
||||
|
||||
## 规则
|
||||
|
||||
- 该资源承载用户对评论的有效点赞关系,后台 CRUD 仅维护记录本身。
|
||||
- `commentId + memberUserId` 是幂等判断边界,必须保持唯一。
|
||||
- 删除策略为硬删;删除后该点赞关系不再存在。
|
||||
- 时间字段以接口实际 JSON 序列化格式为准,业务语义为 `liked_at`。
|
||||
|
||||
@@ -1,29 +1,180 @@
|
||||
# 书籍收藏记录 admin 接口
|
||||
# 书籍收藏记录 admin 接口
|
||||
|
||||
## 基本信息
|
||||
|
||||
- 模块:book
|
||||
- 资源:收藏记录
|
||||
- 资源:书籍收藏记录
|
||||
- 端:admin
|
||||
- 鉴权:挂载 `PrivateGroup`,需要 `JWT + Casbin`
|
||||
- 操作审计:创建、更新、单删、批量删除写操作启用 `OperationRecord`
|
||||
- 路由前缀:`/book`
|
||||
- 鉴权:`PrivateGroup`,需要 `JWT + Casbin`
|
||||
- 审计:创建、更新、单删、批量删除启用 `OperationRecord`
|
||||
- 前缀:`/book`
|
||||
- 实体模型:`book.BookFavoriteRecord`
|
||||
- 搜索入参:`bookReq.BookFavoriteRecordSearch`
|
||||
- 详情响应:`bookRes.BookFavoriteRecordResponse`
|
||||
- 列表项:`book.BookFavoriteRecord`
|
||||
- 返回:写操作 `response.Response{msg}`;详情 `response.Response{data}`;列表 `response.PageResult`
|
||||
- 删除策略:硬删
|
||||
|
||||
## 默认 CRUD
|
||||
## CRUD
|
||||
|
||||
| 动作 | Method | 路径 | API 方法 | Service 方法 |
|
||||
|:---|:---|:---|:---|:---|
|
||||
| 创建 | `POST` | `/book/createBookFavoriteRecord` | `CreateBookFavoriteRecord` | `CreateBookFavoriteRecord` |
|
||||
| 单删 | `DELETE` | `/book/deleteBookFavoriteRecord` | `DeleteBookFavoriteRecord` | `DeleteBookFavoriteRecord` |
|
||||
| 批量删除 | `DELETE` | `/book/deleteBookFavoriteRecordByIds` | `DeleteBookFavoriteRecordByIds` | `DeleteBookFavoriteRecordByIds` |
|
||||
| 更新 | `PUT` | `/book/updateBookFavoriteRecord` | `UpdateBookFavoriteRecord` | `UpdateBookFavoriteRecord` |
|
||||
| 详情 | `GET` | `/book/findBookFavoriteRecord` | `FindBookFavoriteRecord` | `GetBookFavoriteRecord` |
|
||||
| 分页列表 | `GET` | `/book/getBookFavoriteRecordList` | `GetBookFavoriteRecordList` | `GetBookFavoriteRecordInfoList` |
|
||||
### 创建书籍收藏记录
|
||||
|
||||
## 参数与返回
|
||||
- Method:`POST`
|
||||
- Path:`/book/createBookFavoriteRecord`
|
||||
- Handler:`BookFavoriteRecordApi.CreateBookFavoriteRecord`
|
||||
- Service:`BookFavoriteRecordService.CreateBookFavoriteRecord`
|
||||
- 审计:是
|
||||
|
||||
- 创建、更新:`body` 使用 `book.BookFavoriteRecord`。
|
||||
- 单删、详情:`query id`。
|
||||
- 批量删除:`query ids[]`。
|
||||
- 分页列表:`query` 使用 `bookReq.BookFavoriteRecordSearch`,返回 `response.PageResult`。
|
||||
- 详情返回:`bookRes.BookFavoriteRecordResponse`。
|
||||
#### Request Body `book.BookFavoriteRecord`
|
||||
|
||||
| 字段 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| memberUserId | uint | 是 | `> 0`;与 `bookId` 组成唯一约束 | 收藏用户的会员 ID |
|
||||
| bookId | uint | 是 | `> 0`;与 `memberUserId` 组成唯一约束 | 收藏书籍 ID |
|
||||
| favoritedAt | string | 否 | RFC3339 时间;不传使用数据库默认 `CURRENT_TIMESTAMP` | 收藏发生时间 |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
#### 规则
|
||||
|
||||
- 创建请求禁止传服务端生成字段:`id/createdAt/updatedAt`。
|
||||
- 同一 `memberUserId + bookId` 只能存在一条收藏记录。
|
||||
|
||||
### 删除书籍收藏记录
|
||||
|
||||
- Method:`DELETE`
|
||||
- Path:`/book/deleteBookFavoriteRecord`
|
||||
- Handler:`BookFavoriteRecordApi.DeleteBookFavoriteRecord`
|
||||
- Service:`BookFavoriteRecordService.DeleteBookFavoriteRecord`
|
||||
- 审计:是
|
||||
|
||||
#### Request Query
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| id | int | 是 | `> 0` | 收藏记录 ID |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
### 批量删除书籍收藏记录
|
||||
|
||||
- Method:`DELETE`
|
||||
- Path:`/book/deleteBookFavoriteRecordByIds`
|
||||
- Handler:`BookFavoriteRecordApi.DeleteBookFavoriteRecordByIds`
|
||||
- Service:`BookFavoriteRecordService.DeleteBookFavoriteRecordByIds`
|
||||
- 审计:是
|
||||
|
||||
#### Request Query
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| ids | int[] | 二选一 | 非空,元素均 `> 0` | 收藏记录 ID 数组 |
|
||||
| ids[] | int[] | 二选一 | 非空,元素均 `> 0` | 收藏记录 ID 数组,兼容数组写法 |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
#### 规则
|
||||
|
||||
- `ids` 与 `ids[]` 二选一。
|
||||
|
||||
### 更新书籍收藏记录
|
||||
|
||||
- Method:`PUT`
|
||||
- Path:`/book/updateBookFavoriteRecord`
|
||||
- Handler:`BookFavoriteRecordApi.UpdateBookFavoriteRecord`
|
||||
- Service:`BookFavoriteRecordService.UpdateBookFavoriteRecord`
|
||||
- 审计:是
|
||||
|
||||
#### Request Body `book.BookFavoriteRecord`
|
||||
|
||||
| 字段 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| id | uint | 是 | `> 0` | 收藏记录 ID |
|
||||
| memberUserId | uint | 是 | `> 0`;与 `bookId` 组成唯一约束 | 收藏用户的会员 ID |
|
||||
| bookId | uint | 是 | `> 0`;与 `memberUserId` 组成唯一约束 | 收藏书籍 ID |
|
||||
| favoritedAt | string | 是 | RFC3339 时间 | 收藏发生时间 |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
#### 规则
|
||||
|
||||
- 更新请求禁止传服务端维护字段:`createdAt/updatedAt`。
|
||||
- 更新为实体全量保存,前端应传完整可编辑实体,避免字段被零值覆盖。
|
||||
- 同一 `memberUserId + bookId` 只能存在一条收藏记录。
|
||||
|
||||
### 查询书籍收藏记录详情
|
||||
|
||||
- Method:`GET`
|
||||
- Path:`/book/findBookFavoriteRecord`
|
||||
- Handler:`BookFavoriteRecordApi.FindBookFavoriteRecord`
|
||||
- Service:`BookFavoriteRecordService.GetBookFavoriteRecord`
|
||||
- 审计:否
|
||||
|
||||
#### Request Query
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| id | int | 是 | `> 0` | 收藏记录 ID |
|
||||
|
||||
#### Response `bookRes.BookFavoriteRecordResponse`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|:---|:---|:---|
|
||||
| bookFavoriteRecord | object | 收藏记录实体 |
|
||||
| bookFavoriteRecord.id | uint | 收藏记录 ID |
|
||||
| bookFavoriteRecord.createdAt | string | 创建时间 |
|
||||
| bookFavoriteRecord.updatedAt | string | 更新时间 |
|
||||
| bookFavoriteRecord.memberUserId | uint | 收藏用户的会员 ID |
|
||||
| bookFavoriteRecord.bookId | uint | 收藏书籍 ID |
|
||||
| bookFavoriteRecord.favoritedAt | string | 收藏发生时间 |
|
||||
|
||||
### 分页查询书籍收藏记录列表
|
||||
|
||||
- Method:`GET`
|
||||
- Path:`/book/getBookFavoriteRecordList`
|
||||
- Handler:`BookFavoriteRecordApi.GetBookFavoriteRecordList`
|
||||
- Service:`BookFavoriteRecordService.GetBookFavoriteRecordInfoList`
|
||||
- 审计:否
|
||||
|
||||
#### Request Query `bookReq.BookFavoriteRecordSearch`
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| page | int | 否 | 默认 `1`,最小 `1` | 页码 |
|
||||
| pageSize | int | 否 | 默认 `10`,最大 `100` | 每页数量 |
|
||||
| memberUserId | uint | 否 | `> 0` | 按收藏用户的会员 ID 精确筛选 |
|
||||
| bookId | uint | 否 | `> 0` | 按收藏书籍 ID 精确筛选 |
|
||||
|
||||
#### Response `response.PageResult`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|:---|:---|:---|
|
||||
| list | array | `book.BookFavoriteRecord` 列表 |
|
||||
| list[].id | uint | 收藏记录 ID |
|
||||
| list[].createdAt | string | 创建时间 |
|
||||
| list[].updatedAt | string | 更新时间 |
|
||||
| list[].memberUserId | uint | 收藏用户的会员 ID |
|
||||
| list[].bookId | uint | 收藏书籍 ID |
|
||||
| list[].favoritedAt | string | 收藏发生时间 |
|
||||
| total | int64 | 总数 |
|
||||
| page | int | 当前页 |
|
||||
| pageSize | int | 每页数量 |
|
||||
|
||||
#### 规则
|
||||
|
||||
- 列表默认排序:`id desc`。
|
||||
|
||||
## 规则
|
||||
|
||||
- admin 端书籍收藏记录接口统一挂载到 `PrivateGroup`,需要后台 `JWT + Casbin` 权限。
|
||||
- 写操作挂载 `middleware.OperationRecord()`;详情和分页列表不挂操作审计。
|
||||
- `memberUserId + bookId` 唯一约束由数据库索引 `uk_book_favorite_record_member_user_id_book_id` 保证。
|
||||
- 删除策略为硬删,实体使用 `HardDeleteModel`,不维护 `deletedAt`。
|
||||
|
||||
@@ -1,29 +1,199 @@
|
||||
# 书籍阅读记录 admin 接口
|
||||
# 书籍阅读记录 admin 接口
|
||||
|
||||
## 基本信息
|
||||
|
||||
- 模块:book
|
||||
- 资源:阅读记录
|
||||
- 资源:书籍阅读记录
|
||||
- 端:admin
|
||||
- 鉴权:挂载 `PrivateGroup`,需要 `JWT + Casbin`
|
||||
- 操作审计:创建、更新、单删、批量删除写操作启用 `OperationRecord`
|
||||
- 路由前缀:`/book`
|
||||
- 鉴权:`PrivateGroup`,需要 `JWT + Casbin`
|
||||
- 审计:创建、更新、单删、批量删除启用 `OperationRecord`
|
||||
- 前缀:`/book`
|
||||
- 实体模型:`book.BookReadRecord`
|
||||
- 搜索入参:`bookReq.BookReadRecordSearch`
|
||||
- 详情响应:`bookRes.BookReadRecordResponse`
|
||||
- 列表项:`book.BookReadRecord`
|
||||
- 返回:写操作 `response.Response{msg}`;详情 `response.Response{data}`;列表 `response.PageResult`
|
||||
- 删除策略:硬删
|
||||
|
||||
## 默认 CRUD
|
||||
## CRUD
|
||||
|
||||
| 动作 | Method | 路径 | API 方法 | Service 方法 |
|
||||
|:---|:---|:---|:---|:---|
|
||||
| 创建 | `POST` | `/book/createBookReadRecord` | `CreateBookReadRecord` | `CreateBookReadRecord` |
|
||||
| 单删 | `DELETE` | `/book/deleteBookReadRecord` | `DeleteBookReadRecord` | `DeleteBookReadRecord` |
|
||||
| 批量删除 | `DELETE` | `/book/deleteBookReadRecordByIds` | `DeleteBookReadRecordByIds` | `DeleteBookReadRecordByIds` |
|
||||
| 更新 | `PUT` | `/book/updateBookReadRecord` | `UpdateBookReadRecord` | `UpdateBookReadRecord` |
|
||||
| 详情 | `GET` | `/book/findBookReadRecord` | `FindBookReadRecord` | `GetBookReadRecord` |
|
||||
| 分页列表 | `GET` | `/book/getBookReadRecordList` | `GetBookReadRecordList` | `GetBookReadRecordInfoList` |
|
||||
### 创建书籍阅读记录
|
||||
|
||||
## 参数与返回
|
||||
- Method:`POST`
|
||||
- Path:`/book/createBookReadRecord`
|
||||
- Handler:`BookReadRecordApi.CreateBookReadRecord`
|
||||
- Service:`BookReadRecordService.CreateBookReadRecord`
|
||||
- 审计:是
|
||||
|
||||
- 创建、更新:`body` 使用 `book.BookReadRecord`。
|
||||
- 单删、详情:`query id`。
|
||||
- 批量删除:`query ids[]`。
|
||||
- 分页列表:`query` 使用 `bookReq.BookReadRecordSearch`,返回 `response.PageResult`。
|
||||
- 详情返回:`bookRes.BookReadRecordResponse`。
|
||||
#### Request Body `book.BookReadRecord`
|
||||
|
||||
| 字段 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| memberUserId | uint | 是 | `> 0` | 阅读用户的会员 ID |
|
||||
| bookId | uint | 是 | `> 0` | 所属书籍 ID |
|
||||
| bookTitleSnapshot | string | 是 | 非空,最大 `255` | 阅读书籍标题快照 |
|
||||
| readProgress | float | 否 | 默认 `0.00`,范围 `0-100` | 阅读进度百分比 |
|
||||
| chapterId | uint | 是 | `> 0` | 当前续读章节 ID |
|
||||
| lineIndex | int | 是 | `> 0` | 当前续读文本行下标,正文首行为 `1` |
|
||||
| lastReadAt | string | 否 | 不传使用数据库默认时间 | 最近一次阅读时间 |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
#### 规则
|
||||
|
||||
- 创建请求禁止传服务端生成字段:`id/createdAt/updatedAt`。
|
||||
- `memberUserId + bookId` 唯一,同一用户同一本书只保留一条最新阅读记录。
|
||||
- `readProgress/chapterId/lineIndex` 必须通过 Service 校验后写入。
|
||||
|
||||
### 删除书籍阅读记录
|
||||
|
||||
- Method:`DELETE`
|
||||
- Path:`/book/deleteBookReadRecord`
|
||||
- Handler:`BookReadRecordApi.DeleteBookReadRecord`
|
||||
- Service:`BookReadRecordService.DeleteBookReadRecord`
|
||||
- 审计:是
|
||||
|
||||
#### Request Query
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| id | int | 是 | `> 0` | 阅读记录 ID |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
### 批量删除书籍阅读记录
|
||||
|
||||
- Method:`DELETE`
|
||||
- Path:`/book/deleteBookReadRecordByIds`
|
||||
- Handler:`BookReadRecordApi.DeleteBookReadRecordByIds`
|
||||
- Service:`BookReadRecordService.DeleteBookReadRecordByIds`
|
||||
- 审计:是
|
||||
|
||||
#### Request Query
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| ids | int[] | 二选一 | 非空,元素均 `> 0` | 阅读记录 ID 数组 |
|
||||
| ids[] | int[] | 二选一 | 非空,元素均 `> 0` | 阅读记录 ID 数组,兼容数组写法 |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
#### 规则
|
||||
|
||||
- `ids` 与 `ids[]` 二选一。
|
||||
|
||||
### 更新书籍阅读记录
|
||||
|
||||
- Method:`PUT`
|
||||
- Path:`/book/updateBookReadRecord`
|
||||
- Handler:`BookReadRecordApi.UpdateBookReadRecord`
|
||||
- Service:`BookReadRecordService.UpdateBookReadRecord`
|
||||
- 审计:是
|
||||
|
||||
#### Request Body `book.BookReadRecord`
|
||||
|
||||
| 字段 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| id | uint | 是 | `> 0` | 阅读记录 ID |
|
||||
| memberUserId | uint | 是 | `> 0` | 阅读用户的会员 ID |
|
||||
| bookId | uint | 是 | `> 0` | 所属书籍 ID |
|
||||
| bookTitleSnapshot | string | 是 | 非空,最大 `255` | 阅读书籍标题快照 |
|
||||
| readProgress | float | 是 | 范围 `0-100` | 阅读进度百分比 |
|
||||
| chapterId | uint | 是 | `> 0` | 当前续读章节 ID |
|
||||
| lineIndex | int | 是 | `> 0` | 当前续读文本行下标,正文首行为 `1` |
|
||||
| lastReadAt | string | 是 | 有效时间 | 最近一次阅读时间 |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
#### 规则
|
||||
|
||||
- 更新请求禁止传服务端维护字段:`createdAt/updatedAt`。
|
||||
- 更新为实体全量保存,前端应传完整可编辑实体,避免字段被零值覆盖。
|
||||
- `memberUserId + bookId` 唯一,同一用户同一本书不能更新成重复记录。
|
||||
- `readProgress/chapterId/lineIndex` 必须通过 Service 校验后写入。
|
||||
|
||||
### 查询书籍阅读记录详情
|
||||
|
||||
- Method:`GET`
|
||||
- Path:`/book/findBookReadRecord`
|
||||
- Handler:`BookReadRecordApi.FindBookReadRecord`
|
||||
- Service:`BookReadRecordService.GetBookReadRecord`
|
||||
- 审计:否
|
||||
|
||||
#### Request Query
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| id | int | 是 | `> 0` | 阅读记录 ID |
|
||||
|
||||
#### Response `BookReadRecordResponse`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|:---|:---|:---|
|
||||
| bookReadRecord | object | 阅读记录实体 |
|
||||
| bookReadRecord.id | uint | 阅读记录 ID |
|
||||
| bookReadRecord.createdAt | string | 创建时间 |
|
||||
| bookReadRecord.updatedAt | string | 更新时间 |
|
||||
| bookReadRecord.memberUserId | uint | 阅读用户的会员 ID |
|
||||
| bookReadRecord.bookId | uint | 所属书籍 ID |
|
||||
| bookReadRecord.bookTitleSnapshot | string | 阅读书籍标题快照 |
|
||||
| bookReadRecord.readProgress | float | 阅读进度百分比 |
|
||||
| bookReadRecord.chapterId | uint | 当前续读章节 ID |
|
||||
| bookReadRecord.lineIndex | int | 当前续读文本行下标,正文首行为 `1` |
|
||||
| bookReadRecord.lastReadAt | string | 最近一次阅读时间 |
|
||||
|
||||
### 分页查询书籍阅读记录列表
|
||||
|
||||
- Method:`GET`
|
||||
- Path:`/book/getBookReadRecordList`
|
||||
- Handler:`BookReadRecordApi.GetBookReadRecordList`
|
||||
- Service:`BookReadRecordService.GetBookReadRecordInfoList`
|
||||
- 审计:否
|
||||
|
||||
#### Request Query `bookReq.BookReadRecordSearch`
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| page | int | 否 | 默认 `1`,最小 `1` | 页码 |
|
||||
| pageSize | int | 否 | 默认 `10`,最大 `100` | 每页数量 |
|
||||
| memberUserId | uint | 否 | `> 0` | 按阅读用户的会员 ID 筛选 |
|
||||
| bookId | uint | 否 | `> 0` | 按所属书籍 ID 筛选 |
|
||||
|
||||
#### Response `response.PageResult`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|:---|:---|:---|
|
||||
| list | array | `book.BookReadRecord` 列表 |
|
||||
| list[].id | uint | 阅读记录 ID |
|
||||
| list[].createdAt | string | 创建时间 |
|
||||
| list[].updatedAt | string | 更新时间 |
|
||||
| list[].memberUserId | uint | 阅读用户的会员 ID |
|
||||
| list[].bookId | uint | 所属书籍 ID |
|
||||
| list[].bookTitleSnapshot | string | 阅读书籍标题快照 |
|
||||
| list[].readProgress | float | 阅读进度百分比 |
|
||||
| list[].chapterId | uint | 当前续读章节 ID |
|
||||
| list[].lineIndex | int | 当前续读文本行下标,正文首行为 `1` |
|
||||
| list[].lastReadAt | string | 最近一次阅读时间 |
|
||||
| total | int64 | 总数 |
|
||||
| page | int | 当前页 |
|
||||
| pageSize | int | 每页数量 |
|
||||
|
||||
#### 规则
|
||||
|
||||
- 列表默认排序:`last_read_at desc, id desc`。
|
||||
|
||||
## 规则
|
||||
|
||||
- admin 端阅读记录 CRUD 默认挂载到 `PrivateGroup`,统一需要后台 `JWT + Casbin` 权限。
|
||||
- 写操作启用 `OperationRecord`;读操作不启用操作审计。
|
||||
- 删除策略为硬删,删除后不保留软删标记。
|
||||
- `memberUserId + bookId` 是业务唯一键。
|
||||
- `readProgress` 范围为 `0-100`;`chapterId` 必须大于 `0`;`lineIndex` 必须大于 `0`。
|
||||
|
||||
@@ -1,29 +1,193 @@
|
||||
# 书籍系列 admin 接口
|
||||
# 书籍系列 admin 接口
|
||||
|
||||
## 基本信息
|
||||
|
||||
- 模块:book
|
||||
- 资源:系列
|
||||
- 资源:书籍系列
|
||||
- 端:admin
|
||||
- 鉴权:挂载 `PrivateGroup`,需要 `JWT + Casbin`
|
||||
- 操作审计:创建、更新、单删、批量删除写操作启用 `OperationRecord`
|
||||
- 路由前缀:`/book`
|
||||
- 鉴权:`PrivateGroup`,需要 `JWT + Casbin`
|
||||
- 审计:创建、更新、单删、批量删除启用 `OperationRecord`
|
||||
- 前缀:`/book`
|
||||
- 实体模型:`book.BookSeries`
|
||||
- 搜索入参:`bookReq.BookSeriesSearch`
|
||||
- 详情响应:`bookRes.BookSeriesResponse`
|
||||
- 列表项:`book.BookSeries`
|
||||
- 返回:写操作 `response.Response{msg}`;详情 `response.Response{data}`;列表 `response.PageResult`
|
||||
- 删除策略:硬删
|
||||
|
||||
## 默认 CRUD
|
||||
## CRUD
|
||||
|
||||
| 动作 | Method | 路径 | API 方法 | Service 方法 |
|
||||
|:---|:---|:---|:---|:---|
|
||||
| 创建 | `POST` | `/book/createBookSeries` | `CreateBookSeries` | `CreateBookSeries` |
|
||||
| 单删 | `DELETE` | `/book/deleteBookSeries` | `DeleteBookSeries` | `DeleteBookSeries` |
|
||||
| 批量删除 | `DELETE` | `/book/deleteBookSeriesByIds` | `DeleteBookSeriesByIds` | `DeleteBookSeriesByIds` |
|
||||
| 更新 | `PUT` | `/book/updateBookSeries` | `UpdateBookSeries` | `UpdateBookSeries` |
|
||||
| 详情 | `GET` | `/book/findBookSeries` | `FindBookSeries` | `GetBookSeries` |
|
||||
| 分页列表 | `GET` | `/book/getBookSeriesList` | `GetBookSeriesList` | `GetBookSeriesInfoList` |
|
||||
### 创建书籍系列
|
||||
|
||||
## 参数与返回
|
||||
- Method:`POST`
|
||||
- Path:`/book/createBookSeries`
|
||||
- Handler:`BookSeriesApi.CreateBookSeries`
|
||||
- Service:`BookSeriesService.CreateBookSeries`
|
||||
- 审计:是
|
||||
|
||||
- 创建、更新:`body` 使用 `book.BookSeries`。
|
||||
- 单删、详情:`query id`。
|
||||
- 批量删除:`query ids[]`。
|
||||
- 分页列表:`query` 使用 `bookReq.BookSeriesSearch`,返回 `response.PageResult`。
|
||||
- 详情返回:`bookRes.BookSeriesResponse`。
|
||||
#### Request Body `book.BookSeries`
|
||||
|
||||
| 字段 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| name | string | 是 | 非空,最大长度 `128` | 系列名称 |
|
||||
| coverUrl | string | 否 | 最大长度 `500` | 系列封面图片 URL |
|
||||
| intro | string | 否 | 文本 | 系列简介 |
|
||||
| isEnabled | bool | 否 | 默认 `true` | 系列是否启用 |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
#### 规则
|
||||
|
||||
- 创建请求禁止传服务端生成字段:`id/createdAt/updatedAt`。
|
||||
- `name` 写入 `book_series.name`,数据库要求非空。
|
||||
- `isEnabled` 未传时按数据库默认值 `true` 落库。
|
||||
|
||||
### 删除书籍系列
|
||||
|
||||
- Method:`DELETE`
|
||||
- Path:`/book/deleteBookSeries`
|
||||
- Handler:`BookSeriesApi.DeleteBookSeries`
|
||||
- Service:`BookSeriesService.DeleteBookSeries`
|
||||
- 审计:是
|
||||
|
||||
#### Request Query
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| id | int | 是 | `> 0` | 系列 ID |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
#### 规则
|
||||
|
||||
- 删除策略为硬删,删除后记录不再保留在 `book_series` 表。
|
||||
|
||||
### 批量删除书籍系列
|
||||
|
||||
- Method:`DELETE`
|
||||
- Path:`/book/deleteBookSeriesByIds`
|
||||
- Handler:`BookSeriesApi.DeleteBookSeriesByIds`
|
||||
- Service:`BookSeriesService.DeleteBookSeriesByIds`
|
||||
- 审计:是
|
||||
|
||||
#### Request Query
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| ids | int[] | 二选一 | 非空,元素均 `> 0` | 系列 ID 数组 |
|
||||
| ids[] | int[] | 二选一 | 非空,元素均 `> 0` | 系列 ID 数组,兼容数组写法 |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
#### 规则
|
||||
|
||||
- `ids` 与 `ids[]` 二选一。
|
||||
- 删除策略为硬删,删除后记录不再保留在 `book_series` 表。
|
||||
|
||||
### 更新书籍系列
|
||||
|
||||
- Method:`PUT`
|
||||
- Path:`/book/updateBookSeries`
|
||||
- Handler:`BookSeriesApi.UpdateBookSeries`
|
||||
- Service:`BookSeriesService.UpdateBookSeries`
|
||||
- 审计:是
|
||||
|
||||
#### Request Body `book.BookSeries`
|
||||
|
||||
| 字段 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| id | uint | 是 | `> 0` | 系列 ID |
|
||||
| name | string | 是 | 非空,最大长度 `128` | 系列名称 |
|
||||
| coverUrl | string | 否 | 最大长度 `500` | 系列封面图片 URL |
|
||||
| intro | string | 否 | 文本 | 系列简介 |
|
||||
| isEnabled | bool | 否 | `true/false` | 系列是否启用 |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
#### 规则
|
||||
|
||||
- 更新请求禁止传服务端维护字段:`createdAt/updatedAt`。
|
||||
- 当前 Service 使用实体 `Save`,前端应传完整可编辑实体,避免未传字段被零值覆盖。
|
||||
- `id` 不能为空;`name` 写入 `book_series.name`,数据库要求非空。
|
||||
|
||||
### 查询书籍系列详情
|
||||
|
||||
- Method:`GET`
|
||||
- Path:`/book/findBookSeries`
|
||||
- Handler:`BookSeriesApi.FindBookSeries`
|
||||
- Service:`BookSeriesService.GetBookSeries`
|
||||
- 审计:否
|
||||
|
||||
#### Request Query
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| id | int | 是 | `> 0` | 系列 ID |
|
||||
|
||||
#### Response `bookRes.BookSeriesResponse`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|:---|:---|:---|
|
||||
| bookSeries | object | 书籍系列实体 |
|
||||
| bookSeries.id | uint | 系列 ID |
|
||||
| bookSeries.createdAt | time | 创建时间 |
|
||||
| bookSeries.updatedAt | time | 更新时间 |
|
||||
| bookSeries.name | string | 系列名称 |
|
||||
| bookSeries.coverUrl | string | 系列封面图片 URL |
|
||||
| bookSeries.intro | string | 系列简介 |
|
||||
| bookSeries.isEnabled | bool | 系列是否启用 |
|
||||
|
||||
### 分页查询书籍系列列表
|
||||
|
||||
- Method:`GET`
|
||||
- Path:`/book/getBookSeriesList`
|
||||
- Handler:`BookSeriesApi.GetBookSeriesList`
|
||||
- Service:`BookSeriesService.GetBookSeriesInfoList`
|
||||
- 审计:否
|
||||
|
||||
#### Request Query `bookReq.BookSeriesSearch`
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| page | int | 否 | 默认 `1`,最小 `1` | 页码 |
|
||||
| pageSize | int | 否 | 默认 `10`,最大 `100` | 每页数量 |
|
||||
| keyword | string | 否 | 模糊匹配 `name` | 关键字 |
|
||||
| name | string | 否 | 模糊匹配 `name` | 系列名称 |
|
||||
| isEnabled | bool | 否 | `true/false` | 系列是否启用 |
|
||||
|
||||
#### Response `response.PageResult`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|:---|:---|:---|
|
||||
| list | array | `book.BookSeries` 列表 |
|
||||
| list[].id | uint | 系列 ID |
|
||||
| list[].createdAt | time | 创建时间 |
|
||||
| list[].updatedAt | time | 更新时间 |
|
||||
| list[].name | string | 系列名称 |
|
||||
| list[].coverUrl | string | 系列封面图片 URL |
|
||||
| list[].intro | string | 系列简介 |
|
||||
| list[].isEnabled | bool | 系列是否启用 |
|
||||
| total | int64 | 总数 |
|
||||
| page | int | 当前页 |
|
||||
| pageSize | int | 每页数量 |
|
||||
|
||||
#### 规则
|
||||
|
||||
- 列表默认排序:`id desc`。
|
||||
- `keyword` 与 `name` 同时传入时,两个条件按 `AND` 叠加过滤。
|
||||
|
||||
## 规则
|
||||
|
||||
- admin 端书籍系列 CRUD 挂载在 `PrivateGroup`,统一需要 `JWT + Casbin`。
|
||||
- 写操作挂载 `middleware.OperationRecord()`;读操作不挂操作审计。
|
||||
- `isEnabled` 当前按实体和 SQL 使用 `bool`:`true` 表示启用,`false` 表示禁用。
|
||||
- `book_series.name` 建普通索引,不定义唯一约束;接口不要求系列名称全局唯一。
|
||||
- `book_series` 为硬删表,当前接口不提供软删除恢复能力。
|
||||
|
||||
@@ -5,35 +5,96 @@
|
||||
- 模块:sys_api
|
||||
- 资源:API 管理
|
||||
- 端:admin
|
||||
- 鉴权:挂载 `PrivateGroup`,需要 `JWT + Casbin`
|
||||
- 操作审计:`/api/enterSyncApi` 启用 `OperationRecord`
|
||||
- 路由前缀:`/api`
|
||||
- 鉴权:默认 `PrivateGroup`,需要 `JWT + Casbin`;`/api/freshCasbin` 挂 `PublicGroup`
|
||||
- 审计:除 `getAllApis/getApiList/getApiRoles/freshCasbin` 外,其余接口启用 `OperationRecord`
|
||||
- 前缀:`/api`
|
||||
- 模型:`system.SysApi`、`system.SysIgnoreApi`;搜索:`systemReq.SearchApiParams`;角色绑定:`systemReq.SetApiAuthorities`
|
||||
- 返回:统一 `response.Response`
|
||||
|
||||
## 同步接口
|
||||
## 接口
|
||||
|
||||
| 动作 | Method | 路径 | API 方法 | Service 方法 |
|
||||
| 动作 | Method | 路径 | 入参 | 返回重点 |
|
||||
|:---|:---|:---|:---|:---|
|
||||
| 预览同步差异 | `GET` | `/api/syncApi` | `SyncApi` | `SyncApi` |
|
||||
| 确认同步路由 | `POST` | `/api/enterSyncApi` | `EnterSyncApi` | `EnterSyncApi` / `SyncApiToDB` |
|
||||
| 获取 API 关联角色 | `GET` | `/api/getApiRoles` | `GetApiRoles` | `GetAuthoritiesByApi` |
|
||||
| 覆盖 API 关联角色 | `POST` | `/api/setApiRoles` | `SetApiRoles` | `SetApiAuthorities` |
|
||||
| 刷新 Casbin 缓存 | `GET` | `/api/freshCasbin` | `FreshCasbin` | `FreshCasbin` |
|
||||
| 创建 API | `POST` | `/api/createApi` | `system.SysApi` body | 操作结果 |
|
||||
| 删除 API | `POST` | `/api/deleteApi` | `system.SysApi` body,仅需 `ID` | 操作结果 |
|
||||
| 批量删除 API | `DELETE` | `/api/deleteApisByIds` | `request.IdsReq` body | 操作结果 |
|
||||
| 更新 API | `POST` | `/api/updateApi` | `system.SysApi` body | 操作结果 |
|
||||
| API 详情 | `POST` | `/api/getApiById` | `request.GetById` body | `api` |
|
||||
| API 分页列表 | `POST` | `/api/getApiList` | `systemReq.SearchApiParams` body | `response.PageResult` |
|
||||
| 全量 API 列表 | `POST` | `/api/getAllApis` | 无 | `apis` |
|
||||
| API 分组 | `GET` | `/api/getApiGroups` | 无 | `groups/apiGroupMap` |
|
||||
| 预览同步差异 | `GET` | `/api/syncApi` | 无 | `newApis/deleteApis/ignoreApis` |
|
||||
| 忽略/取消忽略 API | `POST` | `/api/ignoreApi` | `system.SysIgnoreApi` body | 操作结果 |
|
||||
| 确认同步路由 | `POST` | `/api/enterSyncApi` | 空 body 或 `systemRes.SysSyncApis` | 操作结果 |
|
||||
| 获取 API 关联角色 | `GET` | `/api/getApiRoles` | `path/method` query | `uint[]` |
|
||||
| 覆盖 API 关联角色 | `POST` | `/api/setApiRoles` | `systemReq.SetApiAuthorities` body | 操作结果 |
|
||||
| 刷新 Casbin 缓存 | `GET` | `/api/freshCasbin` | 无 | 操作结果 |
|
||||
|
||||
## 参数与返回
|
||||
## 请求字段
|
||||
|
||||
- `/api/syncApi`:无入参,返回 `newApis`、`deleteApis`、`ignoreApis`,只预览差异,不写库。
|
||||
- `/api/enterSyncApi`:允许空 body 或 `{}`,默认以当前 Gin 路由表 `global.GVA_ROUTERS` 为事实来源同步 `sys_apis`。
|
||||
- `/api/enterSyncApi`:兼容旧请求体 `systemRes.SysSyncApis`,传入 `newApis/deleteApis` 时按传入列表写入或删除。
|
||||
- `/api/getApiRoles`:query 传入 `path`、`method`,返回该 API 已关联的角色 ID 列表。
|
||||
- `/api/setApiRoles`:body 传入 `path`、`method`、`authorityIds`,全量覆盖该 API 的角色权限。
|
||||
- `/api/freshCasbin`:无入参,刷新 Casbin 缓存;该接口走公开路由但写入 `sys_ignore_apis`,不作为角色权限点维护。
|
||||
- 返回:统一使用 `response.Response`。
|
||||
### SysApi Body
|
||||
|
||||
## 同步规则
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|:---|:---|:---:|:---|
|
||||
| ID | uint | 更新/删除必填 | API ID;来自 `global.GVA_MODEL` 的 JSON 字段 |
|
||||
| path | string | 创建/更新必填 | API 路径 |
|
||||
| description | string | 创建/更新必填 | API 中文描述 |
|
||||
| apiGroup | string | 创建/更新必填 | API 分组 |
|
||||
| method | string | 创建/更新必填 | HTTP Method |
|
||||
|
||||
- 新路由:`sys_apis` 中不存在同一 `path + method` 时自动新增。
|
||||
- 已有路由:保留原 `description`、`apiGroup` 等人工维护字段,不自动覆盖。
|
||||
- 忽略路由:存在于 `sys_ignore_apis` 的 `path + method` 不写入 `sys_apis`。
|
||||
- 失效路由:数据库中存在但当前 Gin 路由表不存在时,从 `sys_apis` 删除,并清理对应 Casbin 权限。
|
||||
- 默认管理员角色 `888` 必须具备 `/api/getApiRoles` 与 `/api/setApiRoles` 权限,避免出现“无权分配权限”的系统初始化死锁。
|
||||
- 公开接口、仅登录接口不应长期作为角色权限点维护;需要通过 `sys_ignore_apis` 排除。
|
||||
### SearchApiParams Body
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|:---|:---|:---:|:---|
|
||||
| page/pageSize | int | 是 | 页码/每页数量 |
|
||||
| path | string | 否 | API 路径筛选 |
|
||||
| description | string | 否 | API 描述筛选 |
|
||||
| apiGroup | string | 否 | API 分组筛选 |
|
||||
| method | string | 否 | HTTP Method 筛选 |
|
||||
| orderKey | string | 否 | 排序字段 |
|
||||
| desc | bool | 否 | 是否倒序 |
|
||||
|
||||
### SysIgnoreApi Body
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|:---|:---|:---:|:---|
|
||||
| path | string | 是 | API 路径 |
|
||||
| method | string | 是 | HTTP Method |
|
||||
| flag | bool | 是 | `true` 写入忽略;`false` 取消忽略 |
|
||||
|
||||
### 其他 Body/Query
|
||||
|
||||
| 场景 | 字段 | 类型 | 必填 | 说明 |
|
||||
|:---|:---|:---|:---:|:---|
|
||||
| getApiById | id | int | 是 | API ID;此处使用 `request.GetById`,字段为小写 `id` |
|
||||
| deleteApisByIds | ids | int[] | 是 | API ID 数组 |
|
||||
| enterSyncApi | newApis | system.SysApi[] | 否 | 兼容旧请求体;传入时按列表新增 |
|
||||
| enterSyncApi | deleteApis | system.SysApi[] | 否 | 兼容旧请求体;传入时按列表删除 |
|
||||
| getApiRoles | path | string | 是 | API 路径 |
|
||||
| getApiRoles | method | string | 是 | HTTP Method |
|
||||
| setApiRoles | path | string | 是 | API 路径 |
|
||||
| setApiRoles | method | string | 是 | HTTP Method |
|
||||
| setApiRoles | authorityIds | uint[] | 是 | 全量覆盖后的角色 ID 列表 |
|
||||
|
||||
## 响应字段
|
||||
|
||||
| 场景 | 字段 | 类型 | 说明 |
|
||||
|:---|:---|:---|:---|
|
||||
| getApiById | api | object | `system.SysApi` |
|
||||
| getApiList | list/total/page/pageSize | mixed | 分页结果 |
|
||||
| getAllApis | apis | array | `system.SysApi` 列表 |
|
||||
| getApiGroups | groups | string[] | API 分组列表 |
|
||||
| getApiGroups | apiGroupMap | object | 路径首段到 API 分组映射 |
|
||||
| syncApi | newApis/deleteApis/ignoreApis | array | 待新增、待删除、已忽略 API |
|
||||
| getApiRoles | data | uint[] | 角色 ID 列表 |
|
||||
|
||||
## 规则
|
||||
|
||||
- `path + method` 唯一;创建重复 API 返回失败。
|
||||
- `/api/syncApi` 只预览差异,不写库。
|
||||
- `/api/enterSyncApi` 空 body 时以 `global.GVA_ROUTERS` 为事实来源同步 `sys_apis`。
|
||||
- 同步时新路由按 `path + method` 新增;已有路由保留人工维护的 `description/apiGroup`。
|
||||
- `sys_ignore_apis` 中的 `path + method` 不写入 `sys_apis`。
|
||||
- 当前路由表不存在的旧 API 从 `sys_apis` 删除,并清理对应 Casbin 权限。
|
||||
- `setApiRoles` 为全量覆盖,成功后刷新 Casbin 缓存。
|
||||
- 默认管理员角色 `888` 必须具备 `/api/getApiRoles` 与 `/api/setApiRoles` 权限。
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
# 作者状态
|
||||
|
||||
- 模块:book
|
||||
- 字典编码:`book_author_status`
|
||||
- 字典类型:`固定值域字典`
|
||||
|
||||
| Label | Value | Sort | Status | Desc |
|
||||
|:---|:---|:---|:---|:---|
|
||||
| 启用 | `enabled` | 10 | true | 作者可正常展示,并可被书籍继续关联 |
|
||||
| 禁用 | `disabled` | 20 | true | 作者不再对外展示,且不应再被新增书籍关联 |
|
||||
10
server/.ai-specs/doc-dict/common_enabled_status.md
Normal file
10
server/.ai-specs/doc-dict/common_enabled_status.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# 通用启用状态
|
||||
|
||||
- 模块:common
|
||||
- 字典编码:`common_enabled_status`
|
||||
- 字典类型:`固定值域字典`
|
||||
|
||||
| Label | Value | Sort | Status | Desc |
|
||||
|:---|:---|:---|:---|:---|
|
||||
| 启用 | `enabled` | 10 | true | 业务对象处于启用状态,可按对应业务规则正常使用 |
|
||||
| 禁用 | `disabled` | 20 | true | 业务对象处于禁用状态,不应再被新增业务关系使用 |
|
||||
@@ -7,7 +7,7 @@
|
||||
-- 模型:model/book/book_author.go
|
||||
-- 迁移接入:initialize/gorm_biz.go
|
||||
-- 删除策略:硬删表
|
||||
-- 状态字典:book_author_status
|
||||
-- 启用状态字典:common_enabled_status
|
||||
-- 职责:承载书籍作者主体信息,用于作者资料展示、书籍作者关联和后台作者管理。
|
||||
|
||||
CREATE TABLE book_author (
|
||||
@@ -25,7 +25,7 @@ COMMENT ON COLUMN book_author.id IS '主键';
|
||||
COMMENT ON COLUMN book_author.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN book_author.updated_at IS '更新时间';
|
||||
COMMENT ON COLUMN book_author.name IS '作者名称';
|
||||
COMMENT ON COLUMN book_author.author_status IS '作者状态字典值,对应 book_author_status';
|
||||
COMMENT ON COLUMN book_author.author_status IS '作者启用状态字典值,对应 common_enabled_status';
|
||||
COMMENT ON COLUMN book_author.intro IS '作者简介';
|
||||
COMMENT ON COLUMN book_author.cover_url IS '作者封面图片 URL';
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
|
||||
### 书籍作者表
|
||||
- 名称:作者名称
|
||||
- 状态:字典 `book_author_status`
|
||||
- 状态:字典 `common_enabled_status`
|
||||
- 简介:作者简介
|
||||
- 封面图片URL:作者封面地址
|
||||
|
||||
|
||||
240
server/.ai-specs/sys-specs/doc-api-doc-spec.md
Normal file
240
server/.ai-specs/sys-specs/doc-api-doc-spec.md
Normal file
@@ -0,0 +1,240 @@
|
||||
# doc-api 文档规范
|
||||
|
||||
## 适用范围
|
||||
|
||||
- 新增、重建、校准 `.ai-specs/doc-api/<端>/<resource>.md` 时必读。
|
||||
- 目标:即使目标 `doc-api` 为空,也能按本文稳定生成接口 contract 文档。
|
||||
- `doc-api` 只写端点、`Handler`、`Service`、鉴权、审计、请求、响应、规则;表结构看 `doc-sql`,值域看 `doc-dict`,代码落点看 `coding-specs`。
|
||||
|
||||
## 生成输入
|
||||
|
||||
按顺序读取,缺失则跳过并从下一项补齐:
|
||||
|
||||
1. `AGENTS.md`:确认项目链路、文档索引、鉴权入口。
|
||||
2. `.ai-specs/coding-specs/module-admin-crud-default.md`:确认 admin 默认 CRUD、命名、Method、Service 映射。
|
||||
3. `.ai-specs/coding-specs/api-auth-control.md`:确认 `PublicGroup`、`PrivateGroup`、`JWT + Casbin` 规则。
|
||||
4. `.ai-specs/coding-specs/vo-model-request-response.md`:确认实体、request、response 落点。
|
||||
5. 对应 `.ai-specs/doc-sql/<resource>.sql`:确认字段、默认值、唯一约束、索引、删除策略、排序依据。
|
||||
6. 对应 `.ai-specs/doc-dict/*.md`:确认状态、类型、枚举值域。
|
||||
7. 源码:`router/<module>`、`api/v1/<module>`、`service/<module>`、`model/<module>`、`initialize/router_biz.go`。
|
||||
|
||||
## 文档结构
|
||||
|
||||
```md
|
||||
# <资源中文名> <端> 接口
|
||||
|
||||
## 基本信息
|
||||
|
||||
- 模块:<module>
|
||||
- 资源:<资源中文名>
|
||||
- 端:<admin/app/平台>
|
||||
- 鉴权:<PrivateGroup/PublicGroup/LoginGroup 描述>
|
||||
- 审计:<启用 OperationRecord 的端点>
|
||||
- 前缀:/<abbreviation>
|
||||
- 实体模型:<model>
|
||||
- 搜索入参:<Search request,可选>
|
||||
- 详情响应:<Detail response,可选>
|
||||
- 列表项:<ListItem response,可选>
|
||||
- 返回:写操作 `response.Response{msg}`;详情 `response.Response{data}`;列表 `response.PageResult`
|
||||
- 删除策略:<硬删/软删/不支持删除>
|
||||
|
||||
## CRUD
|
||||
|
||||
<按端点模板展开>
|
||||
|
||||
## 规则
|
||||
|
||||
- <资源级通用规则>
|
||||
```
|
||||
|
||||
## admin CRUD 模板
|
||||
|
||||
默认 admin CRUD 必须按以下 6 个端点展开;有明确例外时,在对应 `doc-api` 的 `## 规则` 写明。
|
||||
|
||||
### 创建
|
||||
|
||||
```md
|
||||
### 创建<资源>
|
||||
|
||||
- Method:`POST`
|
||||
- Path:`/<abbreviation>/create<StructName>`
|
||||
- Handler:`<StructName>Api.Create<StructName>`
|
||||
- Service:`<StructName>Service.Create<StructName>`
|
||||
- 审计:是
|
||||
|
||||
#### Request Body `<Entity 或 CreateReq>`
|
||||
|
||||
| 字段 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| <field> | <type> | <是/否> | <来自 doc-sql/doc-dict/代码校验> | <字段说明> |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
#### 规则
|
||||
|
||||
- 创建请求禁止传服务端生成字段:`id/createdAt/updatedAt`。
|
||||
- <唯一约束、默认值、引用校验等创建规则>
|
||||
```
|
||||
|
||||
### 单删
|
||||
|
||||
```md
|
||||
### 删除<资源>
|
||||
|
||||
- Method:`DELETE`
|
||||
- Path:`/<abbreviation>/delete<StructName>`
|
||||
- Handler:`<StructName>Api.Delete<StructName>`
|
||||
- Service:`<StructName>Service.Delete<StructName>`
|
||||
- 审计:是
|
||||
|
||||
#### Request Query
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| id | int | 是 | `> 0` | 主键 ID |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
```
|
||||
|
||||
### 批量删除
|
||||
|
||||
```md
|
||||
### 批量删除<资源>
|
||||
|
||||
- Method:`DELETE`
|
||||
- Path:`/<abbreviation>/delete<StructName>ByIds`
|
||||
- Handler:`<StructName>Api.Delete<StructName>ByIds`
|
||||
- Service:`<StructName>Service.Delete<StructName>ByIds`
|
||||
- 审计:是
|
||||
|
||||
#### Request Query
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| ids | int[] | 二选一 | 非空,元素均 `> 0` | 主键 ID 数组 |
|
||||
| ids[] | int[] | 二选一 | 非空,元素均 `> 0` | 主键 ID 数组,兼容数组写法 |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
#### 规则
|
||||
|
||||
- `ids` 与 `ids[]` 二选一。
|
||||
```
|
||||
|
||||
### 更新
|
||||
|
||||
```md
|
||||
### 更新<资源>
|
||||
|
||||
- Method:`PUT`
|
||||
- Path:`/<abbreviation>/update<StructName>`
|
||||
- Handler:`<StructName>Api.Update<StructName>`
|
||||
- Service:`<StructName>Service.Update<StructName>`
|
||||
- 审计:是
|
||||
|
||||
#### Request Body `<Entity 或 UpdateReq>`
|
||||
|
||||
| 字段 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| id | uint | 是 | `> 0` | 主键 ID |
|
||||
| <field> | <type> | <是/否> | <来自 doc-sql/doc-dict/代码校验> | <字段说明> |
|
||||
|
||||
#### Response
|
||||
|
||||
- `response.Response{msg}`
|
||||
|
||||
#### 规则
|
||||
|
||||
- 更新请求禁止传服务端维护字段:`createdAt/updatedAt`。
|
||||
- <全量保存/局部更新、唯一约束、引用校验等更新规则>
|
||||
```
|
||||
|
||||
### 详情
|
||||
|
||||
```md
|
||||
### 查询<资源>详情
|
||||
|
||||
- Method:`GET`
|
||||
- Path:`/<abbreviation>/find<StructName>`
|
||||
- Handler:`<StructName>Api.Find<StructName>`
|
||||
- Service:`<StructName>Service.Get<StructName>`
|
||||
- 审计:否
|
||||
|
||||
#### Request Query
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| id | int | 是 | `> 0` | 主键 ID |
|
||||
|
||||
#### Response `<StructName>Response`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|:---|:---|:---|
|
||||
| <resource> | object | 详情实体 |
|
||||
| <resource>.id | uint | 主键 ID |
|
||||
| <resource>.<field> | <type> | <字段说明> |
|
||||
```
|
||||
|
||||
### 分页列表
|
||||
|
||||
```md
|
||||
### 分页查询<资源>列表
|
||||
|
||||
- Method:`GET`
|
||||
- Path:`/<abbreviation>/get<StructName>List`
|
||||
- Handler:`<StructName>Api.Get<StructName>List`
|
||||
- Service:`<StructName>Service.Get<StructName>InfoList`
|
||||
- 审计:否
|
||||
|
||||
#### Request Query `<StructName>Search`
|
||||
|
||||
| 参数 | 类型 | 必填 | 规则 | 说明 |
|
||||
|:---|:---|:---:|:---|:---|
|
||||
| page | int | 否 | 默认 `1`,最小 `1` | 页码 |
|
||||
| pageSize | int | 否 | 默认 `10`,最大 `100` | 每页数量 |
|
||||
| <filter> | <type> | 否 | <规则> | <筛选说明> |
|
||||
|
||||
#### Response `response.PageResult`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|:---|:---|:---|
|
||||
| list | array | `<ListItem>` 列表 |
|
||||
| list[].id | uint | 主键 ID |
|
||||
| list[].<field> | <type> | <字段说明> |
|
||||
| total | int64 | 总数 |
|
||||
| page | int | 当前页 |
|
||||
| pageSize | int | 每页数量 |
|
||||
|
||||
#### 规则
|
||||
|
||||
- 列表默认排序:`<order by>`。
|
||||
```
|
||||
|
||||
## 字段来源
|
||||
|
||||
- Body 字段:优先取 `request`;没有独立 `request` 时取实体可编辑字段。
|
||||
- Query 字段:取 `request/Search`、`common.GetById`、`common.IdsReq`。
|
||||
- Detail 响应:取 `response` 包装结构和实体 JSON 字段。
|
||||
- List 响应:取 `ListItem`、`Select/Scan` 字段、额外展示字段。
|
||||
- 字段规则:取 `doc-sql` 非空/默认值/唯一索引/check,叠加 `doc-dict` 值域和 `Service` 校验。
|
||||
- 字段名:使用实际 `json/form` 名称,禁止使用 Go 字段名替代。
|
||||
- 端点鉴权:默认继承 `## 基本信息`;只有端点鉴权不同才在端点内单独写。
|
||||
- 写操作响应:统一写 `response.Response{msg}`,不展开 `code/msg` 表格。
|
||||
- 请求/响应汇总:默认不写 `## 请求字段`、`## 响应字段`;字段以端点内 `Request/Response` 为准。
|
||||
|
||||
## 硬性要求
|
||||
|
||||
- `## CRUD` 必须展开端点,禁止只写 CRUD 总表。
|
||||
- 每个端点必须有自己的 `Request`、`Response`;无请求参数时保留 `Request` 小节并写 `- 无。`。
|
||||
- 端点特有规则按需写在端点下;通用规则写到文末 `## 规则`。
|
||||
- 请求字段表列固定为:字段/参数、类型、必填、规则、说明。
|
||||
- 详情/列表响应字段表列固定为:字段、类型、说明;写操作响应简写为 `response.Response{msg}`。
|
||||
- 关键响应字段必须展开,禁止写 `mixed`。
|
||||
- `ids` 与 `ids[]` 必须写清二选一。
|
||||
- 文档规则要求业务校验时,代码必须同步落到 `API` 或 `Service`。
|
||||
@@ -16,5 +16,6 @@
|
||||
|
||||
| 中文 | 英文 | 说明 |
|
||||
|:---|:---|:---|
|
||||
| 通用 | common | 跨业务复用的通用值域与模型 |
|
||||
| 书籍 | book | 书籍与章节相关业务模块 |
|
||||
| 设备 | device | 设备管理模块 |
|
||||
|
||||
@@ -28,9 +28,17 @@ WHERE NOT EXISTS (
|
||||
|
||||
-- book 业务字典初始化补齐 / sys_dictionaries, sys_dictionary_details / 2026-04-26
|
||||
|
||||
DELETE FROM sys_dictionary_details d
|
||||
USING sys_dictionaries dict
|
||||
WHERE d.sys_dictionary_id = dict.id
|
||||
AND dict.type = 'book_author_status';
|
||||
|
||||
DELETE FROM sys_dictionaries
|
||||
WHERE type = 'book_author_status';
|
||||
|
||||
WITH dict_seed(name, type, status, description) AS (
|
||||
VALUES
|
||||
('作者状态', 'book_author_status', true, '作者状态字典'),
|
||||
('通用启用状态', 'common_enabled_status', true, '通用启用禁用状态字典'),
|
||||
('书籍评论状态', 'book_comment_status', true, '书籍评论状态字典'),
|
||||
('书籍完结状态', 'book_completion_status', true, '书籍完结状态字典'),
|
||||
('书籍时代标签', 'book_era_tag', true, '书籍时代标签字典'),
|
||||
@@ -48,7 +56,7 @@ WHERE d.type = s.type;
|
||||
|
||||
WITH dict_seed(name, type, status, description) AS (
|
||||
VALUES
|
||||
('作者状态', 'book_author_status', true, '作者状态字典'),
|
||||
('通用启用状态', 'common_enabled_status', true, '通用启用禁用状态字典'),
|
||||
('书籍评论状态', 'book_comment_status', true, '书籍评论状态字典'),
|
||||
('书籍完结状态', 'book_completion_status', true, '书籍完结状态字典'),
|
||||
('书籍时代标签', 'book_era_tag', true, '书籍时代标签字典'),
|
||||
@@ -64,8 +72,8 @@ WHERE NOT EXISTS (
|
||||
|
||||
WITH detail_seed(dict_type, label, value, sort, status) AS (
|
||||
VALUES
|
||||
('book_author_status', '启用', 'enabled', 10, true),
|
||||
('book_author_status', '禁用', 'disabled', 20, true),
|
||||
('common_enabled_status', '启用', 'enabled', 10, true),
|
||||
('common_enabled_status', '禁用', 'disabled', 20, true),
|
||||
('book_comment_status', '正常', 'normal', 10, true),
|
||||
('book_comment_status', '隐藏', 'hidden', 20, true),
|
||||
('book_completion_status', '完结', 'completed', 10, true),
|
||||
@@ -100,8 +108,8 @@ WHERE d.sys_dictionary_id = dict.id
|
||||
|
||||
WITH detail_seed(dict_type, label, value, sort, status) AS (
|
||||
VALUES
|
||||
('book_author_status', '启用', 'enabled', 10, true),
|
||||
('book_author_status', '禁用', 'disabled', 20, true),
|
||||
('common_enabled_status', '启用', 'enabled', 10, true),
|
||||
('common_enabled_status', '禁用', 'disabled', 20, true),
|
||||
('book_comment_status', '正常', 'normal', 10, true),
|
||||
('book_comment_status', '隐藏', 'hidden', 20, true),
|
||||
('book_completion_status', '完结', 'completed', 10, true),
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# AI 开发入口 [!IMPORTANT]
|
||||
# AI 开发入口 [!IMPORTANT]
|
||||
|
||||
- **本文档要求**:本文档为项目级别规范和重要导航,必须严格参考
|
||||
- **本文档要求**:本文档只允许在已有的结构上CURD,不允许增加其他标题区
|
||||
- **本文档要求**:.ai-specs 目录下新增/删除任何文档的时候都应该 在本文档中修改 `## 项目文档`
|
||||
- **文档要求**:规范型文档是给 AI 的顶层入口文档,不是“解释得更全”就更好,而是要 更短、更硬、更可判定
|
||||
- **文档要求**:如果我的`需求/要求`和`规范文档`冲突,你应该及时提醒我,让我决策是修正`需求/规范文档`
|
||||
- **文档要求**:规范型文档是给 AI 的顶层入口文档,不是“解释得更全”就更好,而是要 更短、更硬、更可判定,推荐文档内容以“硬规则 + 模板”为主
|
||||
- **文档要求**:如果我的`需求/要求`和`规范文档`冲突,你应该及时提醒我,让我决策是否修正`需求/规范文档`
|
||||
- **代码优化**:先复用再新增,允许抽公共逻辑,但公共逻辑必须保证边界仍清晰。
|
||||
- **代码优化**:优化代码时必须同时考虑冗余、孤岛代码、代码清晰度、复杂度、边界条件和兼容性,不能只追求功能跑通。不要修改ui/ux 视觉效果,除非明确要求。
|
||||
- **代码默认遵循**:业务流程需要遵循 `主流做法` `工业级正规`
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
## 工具使用规则
|
||||
|
||||
- **搜索范围限制**:Grep/Glob 严禁全盘搜索,绝对禁止扫描 `.gitignore` 忽略的目录,以避免性能卡顿。
|
||||
- **搜索范围限制**:Grep/Glob 严禁全盘搜索,绝对禁止扫描 `server\docs`、`.worktrees`、`web\node_modules`、`web\dist`、`server\log`、`server\uploads`、`rm_file` 等大目录,以避免性能卡顿。
|
||||
- **读写**:所有文件读取/写入统一使用 UTF-8(建议无 BOM)
|
||||
- **读写**:PowerShell/脚本读取项目文件必须显式指定 `-Encoding utf8`
|
||||
- **画图**:优先使用 `Mermaid 图` 不能混入非 Mermaid 语法文本。
|
||||
@@ -134,6 +134,7 @@ flowchart LR
|
||||
| `.ai-specs\sys-specs\business-table-spec.md` | 规定新增业务表的 SQL 设计、索引、约束、迁移和兼容要求 | 涉及新增/修改业务表、字段、索引、唯一约束、迁移注册时必读 |
|
||||
| `.ai-specs\sys-specs\business-dictionary-spec.md` | 规定新增业务字典的定义方式,以及代码枚举与字典值的一一对应关系 | 涉及新增业务状态、类型、级别、来源、模式、分类等值域时必读 |
|
||||
| `.ai-specs\sys-specs\module-naming-spec.md` | 规定业务模块中文名与英文名的统一登记方式 | 涉及新增/修改业务模块命名、中英文对照、目录命名时必读 |
|
||||
| `.ai-specs\sys-specs\doc-api-doc-spec.md` | 规定 `doc-api` 从空文档生成接口 contract 的输入源、admin CRUD 模板、字段来源和硬性要求 | 涉及新增/修改 `.ai-specs\doc-api` 接口文档时必读 |
|
||||
| `.ai-specs\sys-specs\database-upgrade-doc-spec.md` | 规定 `.ai-transition\database-upgrade-doc` 数据库升级 SQL 的版本定位、写入时机和兼容 SQL 要求 | 涉及修改 `doc-sql` 并产生数据库结构变更、维护 `v1.sql`/`v2.sql` 等升级 SQL 时必读 |
|
||||
|
||||
### doc-api <admin or app or `平台`>
|
||||
@@ -169,7 +170,7 @@ flowchart LR
|
||||
|
||||
| 路径 | 用途 | 说明 |
|
||||
|:---|:---|:---|
|
||||
| `.ai-specs\doc-dict\book_author_status.md` | 定义作者状态的标准值域 | 涉及作者状态的存储、校验、展示和接口出入参时必读 |
|
||||
| `.ai-specs\doc-dict\common_enabled_status.md` | 定义通用启用/禁用状态的标准值域 | 涉及业务对象启用禁用状态的存储、校验、展示和接口出入参时必读 |
|
||||
| `.ai-specs\doc-dict\book_comment_status.md` | 定义书籍评论状态的标准值域 | 涉及评论状态存储、评论隐藏和评论出入参展示时必读 |
|
||||
| `.ai-specs\doc-dict\book_completion_status.md` | 定义书籍完结状态的标准值域 | 涉及书籍完结状态的存储、校验、展示和接口出入参时必读 |
|
||||
| `.ai-specs\doc-dict\book_era_tag.md` | 定义书籍时代标签的标准值域 | 涉及时代标签存储、筛选聚合和接口出入参时必读 |
|
||||
|
||||
@@ -5,9 +5,10 @@ go mod tidy
|
||||
go run main.go
|
||||
|
||||
# 更新api文档
|
||||
swag init
|
||||
|
||||
go install github.com/swaggo/swag/cmd/swag@latest
|
||||
swag init
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
2762
server/docs/docs.go
2762
server/docs/docs.go
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -18,8 +18,6 @@ const (
|
||||
BookPublishStatusDraft = "draft"
|
||||
BookPublishStatusOffShelf = "off_shelf"
|
||||
BookPublishStatusOnShelf = "on_shelf"
|
||||
BookAuthorStatusEnabled = "enabled"
|
||||
BookAuthorStatusDisabled = "disabled"
|
||||
BookCommentStatusNormal = "normal"
|
||||
BookCommentStatusHidden = "hidden"
|
||||
)
|
||||
|
||||
@@ -3,7 +3,7 @@ package book
|
||||
type BookAuthor struct {
|
||||
HardDeleteModel
|
||||
Name string `json:"name" form:"name" gorm:"type:varchar(128);not null;uniqueIndex:uk_book_author_name;comment:作者名称"`
|
||||
AuthorStatus string `json:"authorStatus" form:"authorStatus" gorm:"type:varchar(32);not null;default:enabled;index;comment:作者状态字典值,对应 book_author_status"`
|
||||
AuthorStatus string `json:"authorStatus" form:"authorStatus" gorm:"type:varchar(32);not null;default:enabled;index;comment:作者启用状态字典值,对应 common_enabled_status"`
|
||||
Intro string `json:"intro" form:"intro" gorm:"type:text;comment:作者简介"`
|
||||
CoverUrl string `json:"coverUrl" form:"coverUrl" gorm:"type:varchar(500);comment:作者头像或封面 URL"`
|
||||
}
|
||||
|
||||
@@ -8,9 +8,17 @@ type BookResponse struct {
|
||||
type BookAuthorResponse struct {
|
||||
BookAuthor book.BookAuthor `json:"bookAuthor"`
|
||||
}
|
||||
type BookAuthorListItem struct {
|
||||
book.BookAuthor `gorm:"embedded"`
|
||||
AuthorName string `json:"authorName" gorm:"column:author_name"`
|
||||
}
|
||||
type BookAuthorRelationResponse struct {
|
||||
BookAuthorRelation book.BookAuthorRelation `json:"bookAuthorRelation"`
|
||||
}
|
||||
type BookAuthorRelationListItem struct {
|
||||
book.BookAuthorRelation `gorm:"embedded"`
|
||||
AuthorName string `json:"authorName" gorm:"column:author_name"`
|
||||
}
|
||||
type BookChapterResponse struct {
|
||||
BookChapter book.BookChapter `json:"bookChapter"`
|
||||
}
|
||||
|
||||
6
server/model/common/status.go
Normal file
6
server/model/common/status.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package common
|
||||
|
||||
const (
|
||||
CommonEnabledStatusEnabled = "enabled"
|
||||
CommonEnabledStatusDisabled = "disabled"
|
||||
)
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/book"
|
||||
bookReq "github.com/flipped-aurora/gin-vue-admin/server/model/book/request"
|
||||
bookRes "github.com/flipped-aurora/gin-vue-admin/server/model/book/response"
|
||||
commonReq "github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
|
||||
)
|
||||
|
||||
@@ -36,7 +37,7 @@ func (s *BookAuthorService) GetBookAuthor(id uint) (item book.BookAuthor, err er
|
||||
return
|
||||
}
|
||||
|
||||
func (s *BookAuthorService) GetBookAuthorInfoList(info bookReq.BookAuthorSearch) (list []book.BookAuthor, total int64, err error) {
|
||||
func (s *BookAuthorService) GetBookAuthorInfoList(info bookReq.BookAuthorSearch) (list []bookRes.BookAuthorListItem, total int64, err error) {
|
||||
db := global.GVA_DB.Model(&book.BookAuthor{})
|
||||
if info.Name != "" {
|
||||
db = db.Where("name LIKE ?", "%"+info.Name+"%")
|
||||
@@ -51,6 +52,6 @@ func (s *BookAuthorService) GetBookAuthorInfoList(info bookReq.BookAuthorSearch)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = db.Scopes(paginate(info.PageInfo)).Order("id desc").Find(&list).Error
|
||||
err = db.Select("book_author.*, book_author.name AS author_name").Scopes(paginate(info.PageInfo)).Order("id desc").Scan(&list).Error
|
||||
return
|
||||
}
|
||||
|
||||
70
server/service/book/book_author_list_test.go
Normal file
70
server/service/book/book_author_list_test.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package book
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/book"
|
||||
bookReq "github.com/flipped-aurora/gin-vue-admin/server/model/book/request"
|
||||
commonReq "github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
|
||||
"github.com/glebarez/sqlite"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func setupBookAuthorListTestDB(t *testing.T) {
|
||||
t.Helper()
|
||||
|
||||
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.AutoMigrate(&book.BookAuthor{}, &book.BookAuthorRelation{}))
|
||||
|
||||
global.GVA_DB = db
|
||||
t.Cleanup(func() {
|
||||
global.GVA_DB = nil
|
||||
})
|
||||
}
|
||||
|
||||
func TestBookAuthorService_GetBookAuthorInfoListReturnsAuthorName(t *testing.T) {
|
||||
setupBookAuthorListTestDB(t)
|
||||
|
||||
require.NoError(t, global.GVA_DB.Create(&book.BookAuthor{
|
||||
Name: "鲁迅",
|
||||
AuthorStatus: "enabled",
|
||||
}).Error)
|
||||
|
||||
list, total, err := (&BookAuthorService{}).GetBookAuthorInfoList(bookReq.BookAuthorSearch{
|
||||
PageInfo: commonReq.PageInfo{Page: 1, PageSize: 10},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 1, total)
|
||||
require.Len(t, list, 1)
|
||||
require.Equal(t, "鲁迅", list[0].Name)
|
||||
require.Equal(t, "鲁迅", list[0].AuthorName)
|
||||
}
|
||||
|
||||
func TestBookAuthorRelationService_GetBookAuthorRelationInfoListReturnsAuthorName(t *testing.T) {
|
||||
setupBookAuthorListTestDB(t)
|
||||
|
||||
author := book.BookAuthor{Name: "沈从文", AuthorStatus: "enabled"}
|
||||
require.NoError(t, global.GVA_DB.Create(&author).Error)
|
||||
require.NoError(t, global.GVA_DB.Create(&book.BookAuthorRelation{
|
||||
BookID: 11,
|
||||
AuthorID: author.ID,
|
||||
AuthorSort: 1,
|
||||
}).Error)
|
||||
|
||||
list, total, err := (&BookAuthorRelationService{}).GetBookAuthorRelationInfoList(bookReq.BookAuthorRelationSearch{
|
||||
PageInfo: commonReq.PageInfo{Page: 1, PageSize: 10},
|
||||
BookID: uintPtr(11),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 1, total)
|
||||
require.Len(t, list, 1)
|
||||
require.Equal(t, author.ID, list[0].AuthorID)
|
||||
require.Equal(t, "沈从文", list[0].AuthorName)
|
||||
}
|
||||
|
||||
func uintPtr(v uint) *uint {
|
||||
return &v
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/book"
|
||||
bookReq "github.com/flipped-aurora/gin-vue-admin/server/model/book/request"
|
||||
bookRes "github.com/flipped-aurora/gin-vue-admin/server/model/book/response"
|
||||
commonReq "github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
|
||||
)
|
||||
|
||||
@@ -37,18 +38,22 @@ func (s *BookAuthorRelationService) GetBookAuthorRelation(id uint) (item book.Bo
|
||||
return
|
||||
}
|
||||
|
||||
func (s *BookAuthorRelationService) GetBookAuthorRelationInfoList(info bookReq.BookAuthorRelationSearch) (list []book.BookAuthorRelation, total int64, err error) {
|
||||
db := global.GVA_DB.Model(&book.BookAuthorRelation{})
|
||||
func (s *BookAuthorRelationService) GetBookAuthorRelationInfoList(info bookReq.BookAuthorRelationSearch) (list []bookRes.BookAuthorRelationListItem, total int64, err error) {
|
||||
db := global.GVA_DB.Table("book_author_relation AS bar")
|
||||
if info.BookID != nil {
|
||||
db = db.Where("book_id = ?", *info.BookID)
|
||||
db = db.Where("bar.book_id = ?", *info.BookID)
|
||||
}
|
||||
if info.AuthorID != nil {
|
||||
db = db.Where("author_id = ?", *info.AuthorID)
|
||||
db = db.Where("bar.author_id = ?", *info.AuthorID)
|
||||
}
|
||||
err = db.Count(&total).Error
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = db.Scopes(paginate(info.PageInfo)).Order("book_id asc, author_sort asc, id desc").Find(&list).Error
|
||||
err = db.Select("bar.*, ba.name AS author_name").
|
||||
Joins("LEFT JOIN book_author AS ba ON ba.id = bar.author_id").
|
||||
Scopes(paginate(info.PageInfo)).
|
||||
Order("bar.book_id asc, bar.author_sort asc, bar.id desc").
|
||||
Scan(&list).Error
|
||||
return
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"errors"
|
||||
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/book"
|
||||
commonModel "github.com/flipped-aurora/gin-vue-admin/server/model/common"
|
||||
)
|
||||
|
||||
func validateBook(item book.Book) error {
|
||||
@@ -59,8 +60,8 @@ var validBookPublishStatuses = map[string]bool{
|
||||
}
|
||||
|
||||
var validBookAuthorStatuses = map[string]bool{
|
||||
book.BookAuthorStatusEnabled: true,
|
||||
book.BookAuthorStatusDisabled: true,
|
||||
commonModel.CommonEnabledStatusEnabled: true,
|
||||
commonModel.CommonEnabledStatusDisabled: true,
|
||||
}
|
||||
|
||||
var validBookCommentStatuses = map[string]bool{
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/book"
|
||||
commonModel "github.com/flipped-aurora/gin-vue-admin/server/model/common"
|
||||
)
|
||||
|
||||
func TestValidateBookRejectsOutOfRangeAggregates(t *testing.T) {
|
||||
@@ -51,6 +52,15 @@ func TestValidateBookAuthorRejectsInvalidStatus(t *testing.T) {
|
||||
assertValidationErrorContains(t, err, "authorStatus")
|
||||
}
|
||||
|
||||
func TestValidateBookAuthorAcceptsCommonEnabledStatus(t *testing.T) {
|
||||
if err := validateBookAuthor(book.BookAuthor{AuthorStatus: commonModel.CommonEnabledStatusEnabled}); err != nil {
|
||||
t.Fatalf("validateBookAuthor enabled error = %v", err)
|
||||
}
|
||||
if err := validateBookAuthor(book.BookAuthor{AuthorStatus: commonModel.CommonEnabledStatusDisabled}); err != nil {
|
||||
t.Fatalf("validateBookAuthor disabled error = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyBookAuthorRelationDefaults(t *testing.T) {
|
||||
item := applyBookAuthorRelationDefaults(book.BookAuthorRelation{})
|
||||
if item.AuthorSort != 1 {
|
||||
|
||||
@@ -50,7 +50,7 @@ func (i *initDict) InitializeData(ctx context.Context) (next context.Context, er
|
||||
{Name: "数据库浮点型", Type: "float64", Status: &True, Desc: "数据库浮点型"},
|
||||
{Name: "数据库字符串", Type: "string", Status: &True, Desc: "数据库字符串"},
|
||||
{Name: "数据库bool类型", Type: "bool", Status: &True, Desc: "数据库bool类型"},
|
||||
{Name: "作者状态", Type: "book_author_status", Status: &True, Desc: "作者状态字典"},
|
||||
{Name: "通用启用状态", Type: "common_enabled_status", Status: &True, Desc: "通用启用禁用状态字典"},
|
||||
{Name: "书籍评论状态", Type: "book_comment_status", Status: &True, Desc: "书籍评论状态字典"},
|
||||
{Name: "书籍完结状态", Type: "book_completion_status", Status: &True, Desc: "书籍完结状态字典"},
|
||||
{Name: "书籍时代标签", Type: "book_era_tag", Status: &True, Desc: "书籍时代标签字典"},
|
||||
|
||||
Reference in New Issue
Block a user