# -*- coding: utf-8 -*- """票 10-N3g 回填:①详情公共头部.bru 示例刷新(doc-cust 新快照 projectCount=0) ②图谱全量读.bru 示例重写(isInternal/giftRemark 真值快照 + id 同步) ③新建 关联项目\\关联项目页签.bru(project/page 真值 specimen)。""" import io, json, sys from pathlib import Path sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') BASE = Path(r'D:\code\crm-api-docs\A4 客户管理\客户详情') SP = json.loads(Path('.scratch/customer-integration-ready/specimens-proj-truth.json').read_text(encoding='utf-8')) def patch(path, pairs): txt = path.read_text(encoding='utf-8') for old, new in pairs: if old not in txt: print(f'[MISS] {path.name} :: {old[:44]}...') return for old, new in pairs: txt = txt.replace(old, new, 1) path.write_text(txt, encoding='utf-8', newline='') print(f'[OK] {path.name} ({len(pairs)} patches)') # ---------- 1) 详情公共头部.bru:示例三处漂移字段刷新(其余与旧快照逐字一致) ---------- patch(BASE / '详情公共头部.bru', [ (' "lastFollowTime": "2026-09-03 23:06:01",', ' "lastFollowTime": "2026-09-11 11:45:33",'), (' "nextFollowTime": "2026-09-10 22:56:59",', ' "nextFollowTime": "2026-09-12 22:34:06",'), (' "projectCount": null,', ' "projectCount": "0",'), ]) # ---------- 2) 图谱全量读.bru:id 三处同步 + 响应示例重写为真值快照 ---------- gcid = SP['GET /api/customer/contact/graph/detail']['request']['customerId'] graph_resp = SP['GET /api/customer/contact/graph/detail']['response']['data'] graph_json = json.dumps({'code': SP['GET /api/customer/contact/graph/detail']['response']['code'], 'success': True, 'message': 'success', 'data': graph_resp}, ensure_ascii=False, indent=2) graph_json = '\n'.join(' ' + ln if ln else ln for ln in graph_json.split('\n')) old_graph = """ ```json { "code": 0, "success": true, "message": "success", "data": { "version": 2, "nodes": [ { "contactId": "753612172667387904", "name": "张顶层", "jobTitleName": "其他职务", "jobTitleCategory": "其他", "level": 10, "levelSource": 2, "phoneMasked": "138****0101", "isKeyContact": 1 }, { "contactId": "753612172839354368", "name": "李中层", "jobTitleName": "其他职务", "jobTitleCategory": "其他", "level": 6, "levelSource": 2, "phoneMasked": "138****0102", "isKeyContact": 0 }, { "contactId": "753612172973572096", "name": "王基层", "jobTitleName": "其他职务", "jobTitleCategory": "其他", "level": 3, "levelSource": 2, "phoneMasked": "138****0103", "isKeyContact": 0 } ], "edges": [ { "parentId": "753612172667387904", "childId": "753612172839354368" }, { "parentId": "753612172839354368", "childId": "753612172973572096" } ] } } ```""" new_graph = ' ```json\n' + graph_json + '\n ```' patch(BASE / '联系人图谱' / '图谱全量读.bru', [ ('url: {{baseUrl}}/api/customer/contact/graph/detail?customerId=753314901191032832', f'url: {{{{baseUrl}}}}/api/customer/contact/graph/detail?customerId={gcid}'), (' customerId: 753314901191032832', f' customerId: {gcid}'), (' GET /api/customer/contact/graph/detail?customerId=753314901191032832', f' GET /api/customer/contact/graph/detail?customerId={gcid}'), (old_graph, new_graph), ]) # ---------- 3) 新建 关联项目\关联项目页签.bru ---------- proj = SP['GET /api/customer/project/page'] proj_resp = proj['response'] rows = proj_resp['data']['content'] first = rows[0] if rows else {} req_id = proj['request']['id'] proj_doc = f"""meta {{ name: 关联项目页签 type: http seq: 7 tags: [ generated ] }} get {{ url: {{{{baseUrl}}}}/api/customer/project/page?id={req_id} body: none auth: inherit }} params:query {{ id: {req_id} current: 1 size: 10 keyword: 恒信达 orderBy: 1 }} docs {{ # 关联项目页签 `GET /api/customer/project/page`(本行兼作对账钥匙,勿手改) 只读反查 crm-project(port seam,票 10-N3 切真值);port 失败前端显 "--" 不显 0。 阶段名走别名→字典名→枚举名回退链(项目侧票 13 口径);排序 update_time 倒序。 ## 请求参数 | 参数 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | id | string | 是 | 客户 id(查询参数) | | current | number | 否 | 页码,默认 1(BaseParam) | | size | number | 否 | 每页条数,默认 10(BaseParam) | | keyword | string | 否 | 关键字模糊匹配(BaseParam;列表页按名称/编号等业务列匹配) | | orderBy | string | 否 | 排序列(BaseParam,可空);asc=false 默认倒序 | ## 请求示例 请求头:Authorization: Bearer {{{{token}}}} GET /api/customer/project/page?id={req_id}¤t=1&size=10&keyword=恒信达 ## 响应 data 结构 | 字段 | 类型 | 说明 | | --- | --- | --- | | content[] | array | 分页内容,元素结构如下 | | content[].id | Long | 项目ID | | content[].projectName | String | 项目名称 | | content[].stageName | String | 项目阶段名(别名→字典名→枚举名回退链) | | content[].statusName | String | 横切状态名(1进行中/2已关闭/3已结项) | | content[].filingStatusName | String | 报备状态名(0未报备/1审核中/2通过/3驳回) | | content[].projectAmount | BigDecimal | 项目金额 | | content[].ownerUserId | Long | 负责人ID | | content[].ownerNameSnapshot | String | 负责人姓名快照 | | content[].updateTime | LocalDateTime | 最近更新时间 | | total | Long | 总条数 | | size | Long | 每页条数 | | current | Long | 当前页 | | pages | Long | 总页数 | | empty | Boolean | 是否为空 | ## 错误码 - 67002 客户不存在 ## 响应示例 // 示例数据(E2E 实测真值),字段结构以上表为准 ```json {json.dumps(proj_resp, ensure_ascii=False, indent=2)} ``` }} """ outdir = BASE / '关联项目' outdir.mkdir(exist_ok=True) (outdir / '关联项目页签.bru').write_text(proj_doc, encoding='utf-8', newline='') print(f'[OK] 关联项目页签.bru 新建(rows={len(rows)})') print('DONE')