create 与 update)qc_report_template_version 的写入口新增两条**拒绝规则**,各对应一个新错误码。
两条都不是新增字段、也不是新增接口,而是把「以前会静默存下 / 存下后才炸」的情况改成**当场报错**。
前端需要做的是:把后端返回的 msg 原样展示(文案已可直接给用户看),并保证这两种失败**不弹通用「系统异常」**。
| 接口 | 方法 | 新增拒绝规则 | 错误码 |
|---|---|---|---|
/qc-report/template-version/create |
POST | 画布含不允许渲染的内容 | 1_070_101_009 |
/qc-report/template-version/update |
PUT | 同上 | 1_070_101_009 |
/qc-report/template-version/disable |
POST | 目标是模板的**当前版本** | 1_070_101_010 |
create与update共用同一段 Schema 校验,两条入口行为一致:**只要提交的 Schema 不合格,一律不落库**。
1_070_101_009)报告产物是拼字符串拼出来的,模板画布里有三处内容会**不经转义**直接进入 HTML:
tagName: "h2");styles 写成字符串时会被原样塞进 <style>)。模板画布又是用户可编辑数据,所以这三处都是可被写入的注入面。
| 维度 | 规则 |
|---|---|
| 标签名 | 必须落在白名单内:常规排版与文本标签(div/p/span/h1~h6/img/hr、表格一族、列表一族、常见行内语义标签)。脚本、样式、内嵌页面、表单类标签一律拒绝 |
| 标签名 | 需**整体**匹配白名单,"img src=x onerror=alert(1)" 这种「标签名里塞属性」的写法会被拒 |
| 属性名 | 只允许字母 / 数字 / - _ : .,且不能以数字开头;含引号或空格的属性名会被拒(它能顶出一个新属性) |
| 属性名 | 以 on 开头的一律视为事件属性,拒绝 |
styles |
必须是**样式规则数组**;写成一段 CSS 文本会被拒(改样式走设计器的样式面板,保存后自然是规则数组) |
selectors / mediaText / 样式属性名与属性值 |
出现 < 即拒绝(</style> 能提前闭合样式块,把后面的内容变成真 HTML) |
设计器正常保存的画布**不会**被拦,以下三类在实现里被明确排除,前端无需特殊处理:
textnode 节点上的 tagName:渲染器根本不读它;docEl / head 元数据:渲染器不读,校验也只沿 components 走;一次最多返回 8 条问题,每条都带**位置**与**违规内容**,形如:
模板画布里有不允许出现的内容,已拒绝保存:画布「根 > 第 1 个组件」的标签是「script」,
报告不支持该标签。可用的只有常规排版标签(div/p/span/h1~h6/img/hr 与表格、列表、行内文本标签),
脚本、样式、内嵌页面、表单类标签一律不允许。请在设计器中删掉这些内容后重新保存
多条问题以 ; 连接。改完再保存一次即可看到下一批。
1_070_101_010)模板表上的 current_version 指向「出件时默认用哪个版本」。
停用某个版本**不会**清空 current_version,于是停用当前版本会造出一份**自相矛盾**的模板:current_version 还指着它,它却已经不可用。这种模板自此出不了报告,
而且失败发生在**出件那一刻**(报 1_070_101_003),用户不会想到起因是之前那次停用。
因此 disable 直接拒绝,**不会**顺手替用户改掉 current_version——
「改哪个版本」是用户的决定,不该由「停用」这个动作悄悄代劳。
版本「v1.1」是模板「来料检验报告模板」当前正在使用的版本,不能停用。
请先到该模板的版本列表里对另一个已发布版本执行「回滚」,把当前版本切走,再停用本版本;
若要让整个模板停止使用,请改为停用模板本身
文案里给出了**两条可执行出路**,前端不需要自己组织引导话术。
current_version 的字符串**与**该版本记录的 version**;current_version 指到);本次无新增字段,无需调整列表或表单列。
| 场景 | 前端表现 |
|---|---|
保存模板报 1_070_101_009 |
用 msg 全文提示(可能含多条,用 ; 分隔);**不要**截断成「保存失败」 |
停用版本报 1_070_101_010 |
用 msg 全文提示;提示文案已含后续操作步骤,无需另加指引 |
| 其它错误码 | 行为不变 |
| 场景 | 规则 |
|---|---|
| 新建版本 / 更新版本时 Schema 为空 | 允许(先建版本后设计),不触发画布校验 |
新建版本 / 更新版本时 Schema 非空但缺 schemaVersion |
拒绝,1_070_101_004 |
| 画布有问题 | 拒绝保存,1_070_101_009,**不落库** |
| 更新**已发布**版本 | 仍然拒绝,1_070_101_002(改动只能另存新草稿),与本次变更无关 |
| 停用当前版本 | 拒绝,1_070_101_010 |
| 停用非当前版本 | 正常停用 |
| 停用整个模板 | 走「停用模板」入口,不受本次变更影响 |
msg 原样展示。; 拆行展示,便于逐条处理。1_070_101_009 的定位信息是「第 N 个组件」:指该组件在其父节点 components 数组中的序号(从 1 开始),根 > 第 2 个组件 > 第 1 个组件;层级过深时中间部分会折叠为 …。engine/render.ts 的逐字一致性和存量报告的regenerate 复现性都不受影响,本次只在**写入侧**加闸门。