# 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:///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: (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": "

…安全帽在购买、日常检查时要检查如下内容…

", "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": "

安全帽验收接口测试正文:检查下颊带宽度。

" } ``` 成功响应:{ "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: " -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) |