# -*- coding: utf-8 -*- """_patch_docs.py — 票 13:接口文档 v3 同步(两镜像 6 类 .bru)。跑一次即删。""" import io, sys, os sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') MAIN = "A7 后台管理/系统设置/数据字典" MIRROR = "A7 后台管理/业务规则/商机规则/商机相关字典" def patch(path, reps): txt = open(path, 'r', encoding='utf-8').read() for tag, (old, new) in reps.items(): assert old in txt, f'{path} NOT FOUND: {tag}' txt = txt.replace(old, new, 1) open(path, 'w', encoding='utf-8', newline='\n').write(txt) print('patched', path) # ---------- 新建编辑字典项.bru(两镜像同文) ---------- reps_save = { 'body-value': (' code: internet\n value: internet\n', ' code: internet\n'), 'body-isdefault': (''' description: 互联网行业 isDefault: false children[0].name: 电商 children[0].code: elec children[0].sortNo: 1 children[0].isDefault: false children[1].name: 游戏 children[1].code: children[1].sortNo: 2 children[1].isDefault: false ''', ''' description: 互联网行业 children[0].name: 电商 children[0].code: elec children[0].sortNo: 1 children[1].name: 游戏 children[1].code: children[1].sortNo: 2 '''), 'intro': ( ' 新建/编辑字典项(键值必填;编码空自动生成、创建后只读;未被引用且无子项可换组;默认项禁停)。**原型 v2(20260908 拍板):`children[i].xxx` 非空即复合保存**——一级项与其多个二级项一次建出/一次改,子项按**全量替换**处理。', ' 新建/编辑字典项(编码空自动生成、创建后只读;未被引用且无子项可换组;默认项禁停;名称组内唯一 63007)。**原型 v2(20260908 拍板):`children[i].xxx` 非空即复合保存**——一级项与其多个二级项一次建出/一次改,子项按**全量替换**处理。**原型 v3(20260909 拍板):「字典键值」字段删除,载荷无 value;默认值不入本接口(isDefault 入参忽略),统一走「设为默认项」(set-default,最低级守卫 63012)。**'), 'bullet-key': ( ' - **键值**:复合新增的新建行(一级+子项)不传 `value`,服务端取字典名称;单项新增(children 为空)与一切编辑维持键值必填(空白 63001),编辑传了就改;存量行 value≠名称 不动。', ' - **键值(v3 已删除)**:字典键值字段不复存在,载荷不收 `value`;同组唯一由**名称**承接(63007),编码组内唯一照旧(63006)。'), 'bullet-default': ( ' - **是否默认值**:`isDefault=true` 一级行或任一 `children[i].isDefault` 均可携带,保存同事务写分组默认(自动取消同组原默认);**同一载荷最多一行 true**(多行报 63001)。', ' - **是否默认值(v3 已废除)**:本接口不再接受默认值标志,载荷中的 `isDefault` 一律忽略;默认值统一在分组维度经 set-default 设置(同事务自动取消同组原默认),并受**最低级守卫**约束(组内存在二级项时只能设二级项,63012)。'), 'row-name': (' | name | string | 是 | - | 字典项名称 |', ' | name | string | 是 | - | 字典项名称,同组内唯一(63007) |'), 'row-value': (' | value | string | 见说明 | - | 字典键值:**复合新增不传(取字典名称)**;单项新增与编辑必填(空白报 63001),同组内唯一 |\n', ''), 'row-isdefault': (' | isDefault | boolean | 否 | false | 是否设为分组默认项(同事务自动取消同组原默认);与 children[i].isDefault 合计最多一行 true |\n', ''), 'row-kid-id': (' | children[i].id | string | 更新必填 | - | 子项ID:带 id=更新(编码只读 63008;键值传了就改、不传保持现值);不带 id=新建 |', ' | children[i].id | string | 更新必填 | - | 子项ID:带 id=更新(编码只读 63008);不带 id=新建 |'), 'row-kid-name': (' | children[i].name | string | 是 | - | 子项字典名称(新建行键值取此名称) |', ' | children[i].name | string | 是 | - | 子项字典名称,组内唯一(63007) |'), 'row-kid-isdefault': (' | children[i].isDefault | boolean | 否 | false | 子项设为分组默认项 |\n', ''), 'ex-cap': (' 复合新增(一级+两个二级子项一次建出,键值由服务端取名称落值):', ' 复合新增(一级+两个二级子项一次建出):'), 'ex-edit': (' groupId=1&name=互联网&value=internet&sortNo=1&status=1&children[0].id=101&children[0].name=电商&children[0].code=elec&children[1].name=保险', ' groupId=1&name=互联网&sortNo=1&status=1&children[0].id=101&children[0].name=电商&children[0].code=elec&children[1].name=保险'), 'ex-single': (''' 单项新增(children 为空=现状口径,键值必填): POST /api/dict/item/saveOrUpdate groupId=1&name=展会&code=exhibition&value=exhibition&sortNo=1&status=1&description=展会渠道''', ''' 单项新增(children 为空): POST /api/dict/item/saveOrUpdate groupId=1&name=展会&code=exhibition&sortNo=1&status=1&description=展会渠道'''), } for base in (f'{MAIN}/字典项', MIRROR): patch(os.path.join(base, '新建编辑字典项.bru'), reps_save) # ---------- 字典项分页.bru ---------- reps_page = { 'row-value': (' | content[].value | string | 字典项值 |\n', ''), 'ex1': (' "value": "internet",\n', ''), 'ex2': (' "value": "elec",\n', ''), 'ex3': (' "value": "social",\n', ''), } for base in (f'{MAIN}/字典项', MIRROR): patch(os.path.join(base, '字典项分页.bru'), reps_page) # ---------- 启用项列表.bru ---------- reps_list = { 'row-value': (' | [].value | string | 字典项值 |\n', ''), 'ex1': (' "value": "exhibition",\n', ''), } for base in (f'{MAIN}/字典项', MIRROR): patch(os.path.join(base, '启用项列表.bru'), reps_list) # ---------- 启用项两级树.bru ---------- reps_tree = { 'row-value': (' | [].value | string | 字典项值 |\n', ''), 'ex1': (' "value": "online",\n', ''), 'ex2': (' "value": "ecom",\n', ''), } for base in (f'{MAIN}/字典项', MIRROR): patch(os.path.join(base, '启用项两级树.bru'), reps_tree) # ---------- 分组分页.bru ---------- reps_gpage = { 'intro': (' 分组分页(keyword 匹配名称/编码,status 筛选)。', ' 分组分页(keyword 匹配名称/编码,status 筛选)。**原型 v3(20260909):出参新增 defaultItemName 回显分组默认项**(默认值在分组列表经「设为默认项」设置,最低级守卫见该接口)。'), 'row': (' | content[].itemCount | int | 分组下未删除的字典项数量(含启用+停用) |', ''' | content[].itemCount | int | 分组下未删除的字典项数量(含启用+停用) | | content[].defaultItemName | string | 分组当前默认项名称(两级组显示「父名 / 子名」;未设置为空) |'''), 'ex': (' "itemCount": 30\n', ''' "itemCount": 30, "defaultItemName": "展会"'''), } for base in (f'{MAIN}/分组', MIRROR): patch(os.path.join(base, '分组分页.bru'), reps_gpage) # ---------- 设为默认项.bru ---------- reps_def = { 'intro': (' 设为分组默认项(同事务自动取消同组原默认)。', ' 设为分组默认项(同事务自动取消同组原默认)。**最低级守卫(20260909 原型 v3)**:分组内存在二级字典项时,itemId 必须为二级项,传一级项报 63012;仅一级分组设一级项。分组停用(63005)、项停用守卫照旧;默认项被停用仍由 63013 在启停/保存两路拦截。'), 'row': (' | itemId | string | 是 | - | 字典项ID |', ' | itemId | string | 是 | - | 字典项ID(须为该组最低级项:组内有二级项时必须是二级项,否则 63012) |'), } for base in (f'{MAIN}/字典项', MIRROR): p = os.path.join(base, '设为默认项.bru') if os.path.exists(p): patch(p, reps_def) else: print('SKIP (no file):', p) # ---------- 残留核对 ---------- print('\n== 残留核对(应只剩响应表 isDefault 出参行)==') for dirpath in (MAIN, MIRROR): for root, _, files in os.walk(dirpath): for fn in files: if not fn.endswith('.bru'): continue p = os.path.join(root, fn) txt = open(p, 'r', encoding='utf-8').read() for kw in ('"value"', '| [].value', 'content[].value', '键值', 'isDefault'): if kw in txt: lines = [f' L{i+1}: {l.strip()[:80]}' for i, l in enumerate(txt.splitlines()) if kw in l] print(f'{p} [{kw}]') print('\n'.join(lines[:4]))