# 官网资讯 PC 接口对接设计 ## 1. 目标 把现有静态 `news.html` 和 `article-detail.html` 接入后端已经存在的 PC 站点文章接口,形成“资讯列表 → 文章详情”的公开只读闭环。 本批只处理官网资讯,不修改关于我们、家族文化、隐私政策、用户协议、姓氏百科及个人中心谱文 CRUD。 ## 2. 契约来源 后端只读项目:`D:\WorkSpace\Java\Genealogy`。 接口: | method | path | 参数 | 响应 | | --- | --- | --- | --- | | GET | `/genealogy/pc/site/articles` | Query `articleType?`、`limit?` | 直接 `SiteArticleVo[]` | 该操作在 YAML 中标记为 `security: []`,后端 `PcSiteContentController` 也没有页面侧登录要求。本批按公开接口处理:`ApiClient` 为该请求设置 `auth: false`,不携带或读取登录 token;公共请求层仍自动携带基础 `clientid` Header。 后端没有站点文章单条详情接口。详情页必须重新读取文章列表,再按 URL 中由列表链接产生的 `articleId` 精确匹配;不存在时显示明确的未找到状态,不得回退到第一条文章。 ## 3. SQL 冻结值 文章类型字典 `gen_site_article_type`: | 值 | 含义 | | --- | --- | | `news` | 新闻,默认 | | `notice` | 公告 | | `download` | 下载 | `gen_site_article` 的页面相关约束: | 字段 | SQL 约束 | | --- | --- | | `article_id` | `BIGINT NOT NULL`,主键 | | `article_type` | `varchar(50) NOT NULL DEFAULT 'news'` | | `article_title` | `varchar(200) NOT NULL` | | `article_summary` | `varchar(500) DEFAULT ''` | | `article_content` | `text`,可空 | | `cover_oss_id` | `BIGINT`,可空 | | `external_url` | `varchar(500) DEFAULT ''` | | `publish_time` | `datetime`,可空 | | `sort_order` | `BIGINT NOT NULL DEFAULT 0` | | `status` | `char(1) NOT NULL DEFAULT '0'`,`0` 正常、`1` 停用 | | `remark` | `varchar(500) DEFAULT NULL` | 服务端只返回正常状态记录,按 `sortOrder ASC`、`publishTime DESC`、`articleId DESC` 排序。正数 `limit` 最大按 100 执行;本批固定发送 `limit=100`。 ## 4. 前端 owner | 文件 | 职责 | | --- | --- | | `utils/ApiClient.js` | 唯一拥有 `/genealogy/pc/site/articles` 请求路径、Query 白名单与枚举校验 | | `utils/AxiosRequestUtil.js` | 确保 `auth: false` 的公开请求不携带 token,且其 401 不清理用户在其他页面建立的登录态 | | `public/js/site-news-pages.js` | 唯一拥有站点文章响应规范化、列表/详情渲染、URL ID 解析和页面初始化 | | `news.html` | 只提供资讯列表、分类入口及加载/空/失败挂载点 | | `article-detail.html` | 只提供公开文章详情挂载点 | 不得复用 `public/js/article-pages.js`。该脚本属于登录后的家谱谱文 CRUD,契约、权限和数据结构均不同。 ## 5. 页面数据流 ### 5.1 资讯列表 1. `news.html` 初始化读取 URL Query `articleType`。 2. Query 为空时不发送 `articleType`,读取全部三类文章;非空时只接受 `news/notice/download`。 URL 中出现其他值时显示“资讯分类无效”且不发请求。 3. 请求固定携带 `limit=100`。 4. 每个列表项使用响应中的字符串 `articleId` 生成 `article-detail.html?articleId=...`。 5. 分类入口只生成本地固定链接: - 全部:`news.html` - 新闻:`news.html?articleType=news` - 公告:`news.html?articleType=notice` - 下载:`news.html?articleType=download` 6. 空数组显示“当前暂无资讯”;畸形响应或网络失败显示区域错误,不跳转。 ### 5.2 文章详情 1. `articleId` 只能来自 URL Query,并按非零十进制字符串校验,禁止转成 JavaScript Number。 2. 页面调用同一个文章列表接口,固定 `limit=100`,不制造不存在的单条详情路径。 3. 只接受 `articleId` 完全相同的文章。 4. 缺失或非法 ID 显示“资讯编号无效”;合法但未匹配显示“资讯不存在或已下线”。 5. 页面不提供 ID 输入框、编辑、发布、删除、状态切换或 OSS ID 输入。 ## 6. 字段分类与展示 | 字段 | 分类 | 页面使用 | | --- | --- | --- | | `articleId` | I | 列表链接和详情精确匹配;不直接展示 | | `articleType` | R | 显示中文类型标签;只接受 SQL 字典枚举 | | `articleTitle` | R | 列表和详情标题,必须非空 | | `articleSummary` | R | 列表摘要和详情导语,可空 | | `articleContent` | R | 详情正文,可空 | | `coverOssId` | I | 没有文件 URL 契约,不显示、不拼接、不手填 | | `externalUrl` | R | 仅接受绝对 HTTP/HTTPS;合法时显示“查看外部内容” | | `publishTime` | R | 可空;按后端 `yyyy-MM-dd HH:mm:ss` 文本安全展示 | | `sortOrder` | I | 仅后端排序,不展示 | | `status` | I | 只接受 `0`,其他值使整批响应失败 | | `remark` | I | 后台备注,不展示 | `articleType` 是列表页 Query 时分类为 S,由用户点击固定分类入口产生;`limit=100` 分类为 A,由系统自动提交。 ## 7. 安全与渲染 - 所有业务 ID 始终保持字符串。 - 标题、摘要、正文、类型和时间全部 HTML 转义。 - 正文只保留换行,不执行后端返回的 HTML、脚本或事件属性。 - `externalUrl` 只允许绝对 `http:` 或 `https:`,并使用 `target="_blank"` 与 `rel="noopener noreferrer"`。 - 任一列表元素缺少稳定 ID、合法类型、标题或正常状态时,整批响应失败。 - 响应不接受分页对象、`rows` 包装或旧字段别名。 - 页面公开访问,请求显式使用 `auth: false`;公开请求的 401/403 不清理既有 token,也不跳转登录页。 ## 8. HTML 迁移 `news.html` 删除两条硬编码新闻和固定分类卡片,改为: - `data-site-news-page` - `data-site-news-list` - `data-site-news-status` - 固定四个分类链接 - 加载完整 API 基础脚本和 `public/js/site-news-pages.js` `article-detail.html` 保留现有视觉结构,将硬编码示例正文改为: - `data-site-article-page` - `data-site-article-detail` - `data-site-article-status` - 加载 `public/js/site-news-pages.js` 现有 `notice-detail.html` 本批不改。后端的公告也是 `SiteArticleVo`,统一进入 `article-detail.html`,避免维护两个详情模板。 ## 9. 错误与空状态 | 场景 | 行为 | | --- | --- | | 列表空数组 | 显示“当前暂无资讯” | | 列表响应畸形 | 显示“资讯列表响应无效” | | 网络或业务失败 | 显示“资讯读取失败,请稍后重试” | | 详情 ID 缺失或非法 | 显示“资讯编号无效”且不请求 | | 详情未匹配 | 显示“资讯不存在或已下线” | | 危险外链 | 不渲染外链入口,正文仍可查看 | | 401/403 | 作为公开内容读取失败处理,不清理登录态、不跳转 | ## 10. 测试与验收 必须以 TDD 覆盖: 1. `ApiClient` 使用公开 PC path,只发送 `articleType/limit`,设置 `auth: false`,拒绝非法类型与超范围 limit。 2. 公共请求即使收到 401 也不清理既有登录 token。 3. 长 ID 保持字符串,非法安全整数被拒绝。 4. `SiteArticleVo` 全字段规范化与直接数组校验。 5. 任一非法元素使整批失败。 6. 列表链接只使用响应 ID,页面无手填 ID/OSS ID。 7. 详情精确匹配,不回退。 8. 正文转义、换行保留、危险外链拒绝。 9. `news.html` 和 `article-detail.html` 加载新脚本,且不加载家谱谱文 CRUD 脚本。 10. 先运行资讯专项测试,再运行全量 `node --test tests/*.test.js`。 11. 使用浏览器验证公开列表、分类链接、详情或真实空状态,控制台无业务错误。 ## 11. 明确不做 - 不修改后端。 - 不新增文章管理能力。 - 不接 APP 或后台管理接口。 - 不把 `coverOssId` 猜成文件 URL。 - 不接 `about/privacy/agreement` 固定页面。 - 不修改 `culture.html` 和首页文章卡片;它们作为后续独立批次。 - 不修改法律页“待法务确认”状态。