424 lines
14 KiB
Markdown
424 lines
14 KiB
Markdown
# PDF 书籍模块 WebAPI 接口文档
|
||
|
||
> 对应功能:PC 端《PDF 书籍阅读》页(FineUIPro.Web/HSSE/PDFDOC/PdfBookView.aspx)—— 多级章节目录 + 富文本正文维护。
|
||
> 服务项目:SGGL/WebAPI(经典 ASP.NET Web API,.NET Framework 4.8);数据服务:SGGL/BLL/API/APIPdfBookService.cs。
|
||
> 数据表:Sys_PdfBook(书籍)/ Sys_PdfChapter(章节,目录层级用 ParentChapterId + Level(1章 2节 3小节),同级用 SortNo 排序,正文 HTML 存 [Text])。
|
||
> 状态:已实现并经本地 IIS Express 联调验证(2026-09)。
|
||
|
||
---
|
||
|
||
## 1. 通用约定
|
||
|
||
### 1.1 地址与路由
|
||
|
||
- 路由模板:api/{controller}/{action}/{id},本模块控制器名为 **PdfBook**。
|
||
- 调用前缀示例:http://<host>/api/PdfBook/getBooks
|
||
- 只支持 JSON 输出(服务端已清除 XML 格式化器);请使用 UTF-8 编码收发中文。
|
||
|
||
### 1.2 统一响应包装(Model.ResponeData)
|
||
|
||
所有接口返回同一结构:
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|---|---|---|
|
||
| code | int | **1** = 成功;**0** = 失败(注:权限过滤返回的 code 为字符串 "0") |
|
||
| message | string | 失败时的中文错误描述;成功为 null |
|
||
| data | object | 业务数据,失败为 null |
|
||
|
||
示例:
|
||
|
||
```json
|
||
{ "code": 1, "message": null, "data": { } }
|
||
```
|
||
|
||
### 1.3 字段命名
|
||
|
||
响应 JSON 键名与 C# 属性一致,采用 **PascalCase**(如 BookId、ChapterTitle),与全站既有 API 保持一致;请求 JSON 键名大小写不敏感(Newtonsoft 反序列化),文档示例统一小写开头书写。
|
||
|
||
### 1.4 鉴权
|
||
|
||
本模块接口按读/写区分权限(全局过滤器 WebAPI/Filter/TestPermissionAttribute.cs):
|
||
|
||
| 类型 | 接口 | 鉴权 |
|
||
|---|---|---|
|
||
| 只读 | getBooks / getChapterTree / getChapter / searchChapter | **免登录**(已加入白名单,与 ProtectionStandards 等规范类只读接口一致) |
|
||
| 维护 | addBook / addChapter / editChapter / deleteChapter / saveContent | 需**登录态 + token 双重校验**(见下) |
|
||
|
||
维护接口调用步骤:
|
||
|
||
1. 先调登录接口获取 FormsAuth Cookie:
|
||
POST /api/user/postLoginOn
|
||
```json
|
||
{ "Account": "jinkn", "Password": "xxxxxx" }
|
||
```
|
||
成功后响应会写入名为 auth 的 Cookie(十年有效),后续请求须携带该 Cookie。
|
||
2. 请求头携带 token: <UserId>(Sys_User.UserId,登录响应 data.UserId 即该值)。
|
||
3. 二者缺一不可:缺 Cookie 或缺有效 token 均返回 {"code":"0","message":"您没有权限!"}。
|
||
|
||
---
|
||
|
||
## 2. 接口总览
|
||
|
||
| # | 方法 | 路径 | 说明 |
|
||
|---|---|---|---|
|
||
| 1 | GET | /api/PdfBook/getBooks | 书籍列表(含章节数) |
|
||
| 2 | GET | /api/PdfBook/getChapterTree?bookId= | 某本书多级章节目录树 |
|
||
| 3 | GET | /api/PdfBook/getChapter?chapterId= | 章节正文详情(HTML + 纯文本) |
|
||
| 4 | POST | /api/PdfBook/searchChapter | 章节关键词检索(可限定书籍) |
|
||
| 5 | POST | /api/PdfBook/addBook | 新增书籍(需登录) |
|
||
| 6 | POST | /api/PdfBook/addChapter | 新增章节(可指定父章节,需登录) |
|
||
| 7 | POST | /api/PdfBook/editChapter | 修改章节名称(需登录) |
|
||
| 8 | POST | /api/PdfBook/deleteChapter | 删除章节(连同全部子章节,需登录) |
|
||
| 9 | POST | /api/PdfBook/saveContent | 保存章节正文(富文本 HTML,需登录) |
|
||
---
|
||
|
||
## 3. 接口明细
|
||
|
||
### 3.1 书籍列表
|
||
|
||
GET /api/PdfBook/getBooks
|
||
|
||
无参数。返回按登记时间升序的全部书籍(与 PC 页下拉一致,第一本即页面默认选中书)。
|
||
|
||
响应示例(实测):
|
||
|
||
```json
|
||
{
|
||
"code": 1,
|
||
"message": null,
|
||
"data": [
|
||
{
|
||
"BookId": "BOOK_SAFE_20260827",
|
||
"Title": "《施工现场安全防护手册》",
|
||
"ChapterCount": 366,
|
||
"CreateTime": "2026-09-03T10:30:49"
|
||
},
|
||
{
|
||
"BookId": "BOOK_TEST_001",
|
||
"Title": "《测试书籍-数据库连通》",
|
||
"ChapterCount": 0,
|
||
"CreateTime": "2026-09-04T15:50:30.39"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
data 数组元素字段:
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|---|---|---|
|
||
| BookId | string | 书籍主键 |
|
||
| Title | string | 书名 |
|
||
| ChapterCount | int | 章节总数 |
|
||
| CreateTime | datetime? | 登记时间 |
|
||
|
||
### 3.2 章节目录树
|
||
|
||
GET /api/PdfBook/getChapterTree?bookId=BOOK_SAFE_20260827
|
||
|
||
| 参数 | 必填 | 说明 |
|
||
|---|---|---|
|
||
| bookId | 是 | 书籍主键 |
|
||
|
||
返回**多级嵌套树**:顶级节点数组,子章节在 Children 中递归(叶子章节 Children 为空数组),同级按 SortNo 排序。
|
||
|
||
响应示例(实测节选):
|
||
|
||
```json
|
||
{
|
||
"code": 1,
|
||
"message": null,
|
||
"data": [
|
||
{
|
||
"ChapterId": "BOOK_SAFE_20260827_C001",
|
||
"ChapterTitle": "第一章 安全防护",
|
||
"Level": 1,
|
||
"PageStart": 0,
|
||
"PageEnd": 0,
|
||
"HasContent": false,
|
||
"Children": [
|
||
{
|
||
"ChapterId": "BOOK_SAFE_20260827_C002",
|
||
"ChapterTitle": "1.1三宝四口五临边",
|
||
"Level": 2,
|
||
"PageStart": 0,
|
||
"PageEnd": 0,
|
||
"HasContent": true,
|
||
"Children": []
|
||
},
|
||
{
|
||
"ChapterId": "BOOK_SAFE_20260827_C003",
|
||
"ChapterTitle": "1.2三宝",
|
||
"Level": 2,
|
||
"PageStart": 0,
|
||
"PageEnd": 0,
|
||
"HasContent": false,
|
||
"Children": [
|
||
{
|
||
"ChapterId": "BOOK_SAFE_20260827_C004",
|
||
"ChapterTitle": "1.2.1安全帽",
|
||
"Level": 3,
|
||
"PageStart": 0,
|
||
"PageEnd": 0,
|
||
"HasContent": true,
|
||
"Children": []
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
data 节点字段:
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|---|---|---|
|
||
| ChapterId | string | 章节主键(getChapter / saveContent 等接口用) |
|
||
| ChapterTitle | string | 章节名称 |
|
||
| Level | int | 层级:1=章,2=节,3=小节 |
|
||
| PageStart / PageEnd | int | 起止页码(手动维护模式无页码则为 0) |
|
||
| HasContent | bool | 该章节是否已录入正文(true 才建议作为可阅读节点) |
|
||
| Children | array | 子章节数组(叶子为 []) |
|
||
|
||
> 提示:与 PC 页交互一致——目录型节点(有子章节)自身通常无正文(HasContent=false),正文多录入在叶子章节。
|
||
|
||
### 3.3 章节正文详情
|
||
|
||
GET /api/PdfBook/getChapter?chapterId=BOOK_SAFE_20260827_C004
|
||
|
||
| 参数 | 必填 | 说明 |
|
||
|---|---|---|
|
||
| chapterId | 是 | 章节主键 |
|
||
|
||
响应示例(实测,Content 字段较长已省略):
|
||
|
||
```json
|
||
{
|
||
"code": 1,
|
||
"message": null,
|
||
"data": {
|
||
"ChapterId": "BOOK_SAFE_20260827_C004",
|
||
"BookId": "BOOK_SAFE_20260827",
|
||
"BookTitle": "《施工现场安全防护手册》",
|
||
"ChapterTitle": "1.2.1安全帽",
|
||
"ParentChapterId": "BOOK_SAFE_20260827_C003",
|
||
"Level": 3,
|
||
"PageStart": 0,
|
||
"PageEnd": 0,
|
||
"Content": "<p>…安全帽在购买、日常检查时要检查如下内容…</p>",
|
||
"ContentText": "1、安全帽在购买、日常检查时要检查如下内容: (1)安全帽如有下颊带,应使用宽度不小于10mm的织带…"
|
||
}
|
||
}
|
||
```
|
||
|
||
- Content:富文本 HTML(UMeditor 生成)。2026-09 起页面上传图片在保存时转为 base64 内嵌(data:image/png;base64,...),正文自包含不依赖图片文件;个别历史数据仍可能是 res/umeditor 路径引用。WebView/rich-text 均可直接渲染 data URL;
|
||
- ContentText:去标签纯文本,适合列表摘要/全文展示;
|
||
- 章节不存在时返回 code=0、message=章节不存在或已被删除。
|
||
|
||
### 3.4 章节关键词检索
|
||
|
||
POST /api/PdfBook/searchChapter
|
||
|
||
请求体:
|
||
|
||
```json
|
||
{ "keyword": "安全帽", "bookId": "BOOK_SAFE_20260827" }
|
||
```
|
||
|
||
| 字段 | 必填 | 说明 |
|
||
|---|---|---|
|
||
| keyword | 是 | 检索关键词(正文纯文本 LIKE 字面匹配;% _ 通配符已转义) |
|
||
| bookId | 否 | 限定书籍;不传则全库检索 |
|
||
|
||
响应示例(实测,命中两章):
|
||
|
||
```json
|
||
{
|
||
"code": 1,
|
||
"message": null,
|
||
"data": [
|
||
{
|
||
"BookId": "BOOK_SAFE_20260827",
|
||
"BookTitle": "《施工现场安全防护手册》",
|
||
"ChapterId": "BOOK_SAFE_20260827_C002",
|
||
"ChapterTitle": "1.1三宝四口五临边",
|
||
"PageStart": 0,
|
||
"PageEnd": 0,
|
||
"Snippet": "1.三宝:是指安全帽、安全带、安全网…"
|
||
},
|
||
{
|
||
"BookId": "BOOK_SAFE_20260827",
|
||
"BookTitle": "《施工现场安全防护手册》",
|
||
"ChapterId": "BOOK_SAFE_20260827_C004",
|
||
"ChapterTitle": "1.2.1安全帽",
|
||
"PageStart": 0,
|
||
"PageEnd": 0,
|
||
"Snippet": "1、安全帽在购买、日常检查时要检查如下内容…"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
- 匹配对象为 Sys_PdfChapter.[Text](先剔除 HTML 标签再做 LIKE),命中片段取关键词前后各约 40 字;
|
||
- 说明:当前为字面匹配,未做分词/全文索引,后续可升级 SQL Server 全文检索。
|
||
---
|
||
|
||
### 3.5 新增书籍(需登录)
|
||
|
||
POST /api/PdfBook/addBook
|
||
|
||
请求体:
|
||
|
||
```json
|
||
{ "title": "《新书示例》", "createUser": "apitest" }
|
||
```
|
||
|
||
| 字段 | 必填 | 说明 |
|
||
|---|---|---|
|
||
| title | 是 | 书名 |
|
||
| createUser | 否 | 登记人,缺省 api |
|
||
|
||
响应:
|
||
|
||
```json
|
||
{ "code": 1, "message": null, "data": { "bookId": "PB202609051447346108" } }
|
||
```
|
||
|
||
新增书籍无章节;与 PC 页一致:FilePath=NULL、TotalPages=0、IndexStatus=2(手动维护)。
|
||
|
||
### 3.6 新增章节(需登录)
|
||
|
||
POST /api/PdfBook/addChapter
|
||
|
||
请求体:
|
||
|
||
```json
|
||
{ "bookId": "PB202609051447346108", "parentChapterId": "", "chapterTitle": "第一章 示例" }
|
||
```
|
||
|
||
| 字段 | 必填 | 说明 |
|
||
|---|---|---|
|
||
| bookId | 是 | 所属书籍主键 |
|
||
| parentChapterId | 否 | 父章节主键;**为空=顶级章节**;传入则挂到该章节下(层级=父级+1) |
|
||
| chapterTitle | 是 | 章节名称 |
|
||
| createUser | 否 | 预留 |
|
||
|
||
响应:
|
||
|
||
```json
|
||
{ "code": 1, "message": null, "data": { "chapterId": "CH20260905144734f549" } }
|
||
```
|
||
|
||
### 3.7 修改章节名称(需登录)
|
||
|
||
POST /api/PdfBook/editChapter
|
||
|
||
```json
|
||
{ "chapterId": "CH20260905144734ba08", "chapterTitle": "1.1 子章节(改名后)" }
|
||
```
|
||
|
||
成功响应:{ "code": 1, "data": true };仅改名,不影响层级与正文。
|
||
|
||
### 3.8 删除章节(需登录,级联删除)
|
||
|
||
POST /api/PdfBook/deleteChapter
|
||
|
||
```json
|
||
{ "chapterId": "CH20260905144734f549" }
|
||
```
|
||
|
||
成功响应(实测:父章节带 1 个子章节,共删 2 条):
|
||
|
||
```json
|
||
{ "code": 1, "message": null, "data": { "deletedCount": 2 } }
|
||
```
|
||
|
||
> 删除会递归收集该章节的**全部后代子章节**一并删除(与 PC 页删除章节及其子章节行为一致),请谨慎调用。
|
||
|
||
### 3.9 保存章节正文(需登录)
|
||
|
||
POST /api/PdfBook/saveContent
|
||
|
||
```json
|
||
{
|
||
"chapterId": "CH20260905144734ba08",
|
||
"content": "<p>安全帽验收接口测试正文:检查下颊带宽度。</p>"
|
||
}
|
||
```
|
||
|
||
成功响应:{ "code": 1, "data": true };content 为 UMeditor 风格富文本 HTML,存 Sys_PdfChapter.[Text]。PC 页保存时会把本站上传图片引用转成 base64 内嵌,App/第三方提交的内容按原样存储。
|
||
|
||
---
|
||
|
||
## 4. 常见错误
|
||
|
||
| code | message | 场景 |
|
||
|---|---|---|
|
||
| 1 | - | 成功 |
|
||
| 0 | 书名不能为空 / 章节名称不能为空 / bookId 不能为空 / chapterId 不能为空 / keyword 不能为空 | 必填参数缺失 |
|
||
| 0 | 父章节不存在:xxx / 章节不存在:xxx / 章节不存在或已被删除 | 引用的数据不存在 |
|
||
| "0" | 您没有权限! | 维护接口未携带 auth Cookie 或有效 token |
|
||
| "0" | 登录超出,请重新登录! | 同上(过滤器另一分支文案,同为未授权) |
|
||
|
||
---
|
||
|
||
## 5. 附录
|
||
|
||
### 5.1 数据结构说明(SQL Server)
|
||
|
||
Sys_PdfBook:
|
||
|
||
| 列 | 说明 |
|
||
|---|---|
|
||
| BookId | 主键(PB+yyyyMMddHHmmss+4位随机,服务端生成) |
|
||
| Title | 书名 |
|
||
| IndexStatus | 2=手动维护(无自动索引流程) |
|
||
| CreateUser / CreateTime | 登记人 / 登记时间 |
|
||
|
||
Sys_PdfChapter:
|
||
|
||
| 列 | 说明 |
|
||
|---|---|
|
||
| ChapterId | 主键(CH+yyyyMMddHHmmss+4位随机,服务端生成) |
|
||
| BookId | 所属书籍 |
|
||
| ParentChapterId | 父章节,NULL=顶级 |
|
||
| Level | 1=章 2=节 3=小节(新增自动=父级+1) |
|
||
| ChapterTitle | 章节名称 |
|
||
| PageStart / PageEnd | 页码(手动维护为 NULL,接口输出 0) |
|
||
| Text | 正文富文本 HTML |
|
||
| SortNo | 同级排序(新增=全书 MAX+1) |
|
||
|
||
### 5.2 curl 调用示例(Windows;含中文的 JSON 请用文件方式 --data-binary 发送)
|
||
|
||
```bat
|
||
REM 1) 登录,保存 cookie(login.json 内容见 1.4)
|
||
curl -c cookies.txt -X POST -H "Content-Type: application/json" --data-binary "@login.json" http://localhost:7143/api/user/postLoginOn
|
||
|
||
REM 2) 只读(免登录)
|
||
curl "http://localhost:7143/api/PdfBook/getBooks"
|
||
curl "http://localhost:7143/api/PdfBook/getChapterTree?bookId=BOOK_SAFE_20260827"
|
||
|
||
REM 3) 维护(cookie + token 头)
|
||
curl -b cookies.txt -H "token: <UserId>" -X POST -H "Content-Type: application/json" --data-binary "@body.json" http://localhost:7143/api/PdfBook/saveContent
|
||
```
|
||
|
||
### 5.3 与 PC 页面(HSSE/PDFDOC/PdfBookView.aspx)的对应关系
|
||
|
||
| 页面操作 | 接口 |
|
||
|---|---|
|
||
| 页首书籍下拉(默认第一本) | getBooks |
|
||
| 左侧多级目录树 | getChapterTree |
|
||
| 点击叶子章节显示正文 | getChapter |
|
||
| 保存内容(富文本) | saveContent |
|
||
| 新增书籍弹窗 | addBook |
|
||
| 新增章节 / 编辑名称 / 删除章节(含子章节) | addChapter / editChapter / deleteChapter |
|
||
|
||
### 5.4 变更记录
|
||
|
||
| 日期 | 内容 |
|
||
|---|---|
|
||
| 2026-09-05 | 初版:新增 PdfBookController + APIPdfBookService,9 个接口全部经本地 IIS Express(http://localhost:7143)联调通过;只读接口加入权限白名单免登录 |
|
||
| 2026-09-05 | 页面富文本图片改为 base64 内嵌存储:保存内容时自动转换(getChapter 返回的 Content 中图片为 data URL) |
|