海尔山茶花502值得买吗 零嵌冰箱对比
2026/8/25 11:46:13 网站建设 项目流程

字段审查结论

为避免后端过度设计,这一次只保留前端保存和下次恢复所必需的数据。

保留字段

字段保留原因
reviewId定位审核记录,沿用现有ReviewArticle.id
markupVersion/expectedMarkupVersion解决多人同时编辑时的覆盖问题
baseContentHash判断当前标记是否仍基于同一份原文
markupJson云端唯一需要持久化的标记快照
annotations备注和修改列表,下次进入页面需要还原
blockPath/from/to/quote用于把标记定位回原文
updatedBy/updatedAt仅用于展示最近保存信息和冲突提示

第一版去掉的字段

字段去掉原因
reviewVersion/expectedReviewVersion审核状态变化可通过后端校验monitorStatus = 0解决;标记并发由markupVersion解决
createdBy/createdAt/updatedBy/updatedAt(annotation 内)本期全量覆盖保存,不做单条批注审计;每条标记的独立历史不准确也不必要
prefix/suffix/blockTextHash原文冻结且只允许同块选区,blockPath/from/to/quote足够;这些字段可作为后续增强
finalContentHtml/finalContentMarkdown(草稿保存)终稿可由前端实时计算;草稿阶段只需要保存markupJson
contentFormat当前内容格式由既有content字段约定;若后端后续支持 HTML/Markdown 混合,再扩展
editable前端已有权限和状态判断,后端保存时仍必须做权限/状态校验;不是恢复标记所必需

数据结构

ReviewMarkupJson

interface ReviewMarkupJson { schema: 'review-markup/v1'; baseContentHash: string; annotations: ReviewMarkupAnnotation[]; }

字段说明:

字段类型必填说明
schemastring标记数据协议版本,固定review-markup/v1
baseContentHashstring原文内容 hash,用于判断原文是否变化
annotationsarray当前有效的备注和修改列表

markupVersion不放在markupJson内部,由接口顶层字段维护,避免前后端版本不一致。

ReviewMarkupAnnotation

interface ReviewMarkupAnnotation { id: string; type: 'comment' | 'replace'; anchor: ReviewTextAnchor; comment?: string; replacement?: string; }

字段说明:

字段类型必填说明
idstring前端生成的全局唯一标记 id,例如ann_...
typecomment/replacecomment=备注,replace=替换建议
anchorobject标记在原文中的位置
commentstring条件必填type=comment时必填
replacementstring条件必填type=replace时必填

ReviewTextAnchor

interface ReviewTextAnchor { blockPath: string; from: number; to: number; quote: string; }

字段说明:

字段类型必填说明
blockPathstring文本块位置,例如h1[0]p[2]li[4]
fromnumber在该文本块纯文本中的起始 offset,包含
tonumber在该文本块纯文本中的结束 offset,不包含
quotestring被选中的原文片段

示例

{ "schema": "review-markup/v1", "baseContentHash": "sha256:6adf9c...", "annotations": [ { "id": "ann_001", "type": "comment", "anchor": { "blockPath": "p[2]", "from": 10, "to": 18, "quote": "智能化高" }, "comment": "这里表述偏绝对,建议补充数据来源" }, { "id": "ann_002", "type": "replace", "anchor": { "blockPath": "p[4]", "from": 5, "to": 11, "quote": "行业领先" }, "replacement": "表现较强" } ] }

接口设计

统一响应结构

沿用现有后端风格:

interface GeoApiResponse<T> { success: boolean; code: number; message: string; data: T; }

如果后端支持 HTTP 409,冲突场景建议直接返回 HTTP 409。如果后端统一返回 HTTP 200,则必须使用明确业务 code,例如4090140902

接口 1:查询文章标记数据

GET /geo/api/review/getReviewMarkupByReviewId?reviewId=11

入参:

参数位置类型必填说明
reviewIdquerynumber审核记录 id,即当前ReviewArticle.id

出参:

interface GetReviewMarkupResponse { reviewId: number; baseContentHash: string; markupVersion: number; markupJson: ReviewMarkupJson | null; updatedBy?: string; updatedAt?: string; }

字段说明:

  • reviewId:审核记录 id,等于当前列表行ReviewArticle.id
  • baseContentHash:后端根据当前原文生成,前端保存和提交时必须原样传回。
  • markupVersion:标记数据版本,标记保存成功时递增。
  • markupJson为空时,前端按无标记初始化。
  • updatedBy/updatedAt:最近一次成功保存标记的人和时间,仅用于展示或冲突提示。

说明:

  • 文章标题、正文、状态继续复用现有ReviewArticle数据;如果后端希望详情页完全不依赖列表数据,可另行把title/content/monitorStatus合并进该接口,但第一版不是必须。
  • 前端权限仍按现有content_review_checkmonitorStatus判断;后端保存时必须再次校验状态和权限。

示例:

{ "success": true, "code": 200, "message": "success", "data": { "reviewId": 11, "baseContentHash": "sha256:6adf9c...", "markupVersion": 2, "markupJson": { "schema": "review-markup/v1", "baseContentHash": "sha256:6adf9c...", "annotations": [] }, "updatedBy": "zhangsan", "updatedAt": "2026-07-03 15:20:00" } }

接口 2:保存标记草稿

PUT /geo/api/review/saveReviewMarkup

调用时机:

  • 用户在备注弹窗点击保存。
  • 用户在修改弹窗点击保存。
  • 用户删除或编辑已有备注/修改后点击确认。

保存语义:

  • 前端每次提交当前文章的完整markupJson,不是只提交本次新增或修改的单条 annotation。
  • 后端只在expectedMarkupVersionbaseContentHash都校验通过,且当前审核状态仍允许编辑时覆盖保存。
  • 覆盖对象是该文章当前草稿的整份markup_json
  • 校验失败时必须返回冲突,不能覆盖云端已有草稿。

入参:

interface SaveReviewMarkupParams { reviewId: number; expectedMarkupVersion: number; baseContentHash: string; markupJson: ReviewMarkupJson; }

字段说明:

字段类型必填说明
reviewIdnumber审核记录 id
expectedMarkupVersionnumber前端当前基于的标记版本
baseContentHashstring前端当前基于的原文 hash
markupJsonobject完整标记 JSON

出参:

interface SaveReviewMarkupResponse { reviewId: number; markupVersion: number; updatedBy: string; updatedAt: string; }

后端校验:

  1. reviewId存在。
  2. 当前审核状态仍允许编辑,例如monitorStatus = 0
  3. expectedMarkupVersion等于后端当前markupVersion
  4. baseContentHash等于后端当前原文 hash。
  5. markupJson.baseContentHash等于后端当前原文 hash。
  6. 每个anchor.quote能在对应blockPath/from/to上匹配到原文。
  7. 第一版建议不允许有效标记区间互相重叠,尤其是replacereplace不能重叠。

成功保存后:

  • 后端用本次请求的完整markupJson整体覆盖保存该文章的markup_json
  • markupVersion + 1
  • 返回最新版本。

接口 3:提交审核结果

沿用现有接口,扩展标记快照和并发校验字段:

PUT /geo/api/review/updateArticleReview

入参:

interface UpdateArticleReviewWithMarkupParams { id: number; monitorStatus: 2 | 3; rejectReason?: string; expectedMarkupVersion: number; baseContentHash: string; markupJson?: ReviewMarkupJson; }

字段说明:

字段类型必填说明
idnumber审核记录 id
monitorStatus2/32=未通过,3=待投放
rejectReasonstring条件必填未通过时必填
expectedMarkupVersionnumber前端当前基于的标记版本
baseContentHashstring前端当前基于的原文 hash
markupJsonobject当前标记快照。建议提交时携带,便于后端事务内保存最终标记

后端事务要求:

  1. 锁定审核记录和标记记录。
  2. 校验当前monitorStatus仍允许提交。
  3. 校验expectedMarkupVersion等于当前markupVersion
  4. 校验baseContentHash等于当前原文 hash。
  5. 如果请求携带markupJson,校验所有 anchor 合法后保存为最终标记快照,并递增markupVersion
  6. 更新审核状态为monitorStatus
  7. 写入审核历史。

提交接口必须把"保存最终标记 + 更新审核状态 + 写审核历史"作为原子操作处理。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询