# -*- coding: utf-8 -*- """第2批:菜单列表页(分页 × 3 + 看板 × 3 × 2)""" import io, sys sys.path.insert(0, 'D:/code/crm-backend-matt/.scratch') sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') from bru_lib import write_bru, bru_form, build_docs, env_json, page_json, req_form_example, req_query_example # ── 商机分页公共结构 ──────────────────────────────────────────────── PAGE_PARAMS = [ ('current', 'number', '否', '1', '当前页码,从 1 开始'), ('size', 'number', '否', '10', '每页条数,上限 500'), ('viewType', 'string', '是', '-', '子菜单/展示形态:RECENT 最近访问 / MINE 我负责的 / PARTICIPATED 我参与的 / FOLLOWED 我关注的 / MANAGE 商机管理 / PUBLIC_POOL 商机公海'), ('keyword', 'string', '否', '-', '模糊搜索关键字(商机名称 / 客户名 / 负责人)'), ('orderBy', 'string', '否', '-', '排序字段(驼峰)'), ('asc', 'boolean','否', 'false', '是否升序'), ('savedViewId', 'string', '否', '-', '自定义视图 id(仅销售机会菜单支持,非空时叠加该视图检索条件)'), ('statusIn', 'string', '否', '-', '商机状态筛选,多值逗号分隔,如 1,2'), ('oppSource', 'string', '否', '-', '商机来源字典 code'), ('oppType', 'string', '否', '-', '商机类型字典 code'), ('industryCode', 'string', '否', '-', '行业字典 code'), ('bidForm', 'string', '否', '-', '招标形式字典 code'), ('localityType', 'string', '否', '-', '项目属地字典 code'), ('provinceCode', 'string', '否', '-', '省份国标 code'), ('cityCode', 'string', '否', '-', '市/区国标 code'), ('ownerDeptId', 'string', '否', '-', '归属部门 ID'), ('ownerUserId', 'string', '否', '-', '负责人 ID'), ('currentStageId','string', '否', '-', '当前阶段节点 ID'), ('poolReason', 'string', '否', '-', '进入公海原因字典 code(公海菜单专属)'), ] OPP_DTO_RESP = [ ('content', 'array', 'PageResult.content 商机列表'), ('content[].id', 'string', '商机 ID(Long 序列化为 string)'), ('content[].oppName', 'string', '商机名称'), ('content[].oppStatus', 'number', '状态:1待领取 2推进中 3暂缓中 4已关闭 5已转项目'), ('content[].primaryCustomerNameSnapshot','string','主要意向客户名快照'), ('content[].projectAmount', 'number', '项目金额'), ('content[].ownerNameSnapshot', 'string', '负责人姓名快照'), ('content[].ownerDeptName', 'string', '负责人部门名称(出参回显)'), ('content[].currentStageName', 'string', '当前阶段节点名称(出参回显)'), ('content[].stageStayDays', 'number', '节点停留天数(出参回显)'), ('content[].nextStageName', 'string', '下一节点名称(出参回显)'), ('content[].lastFollowTime', 'string', '最近跟进时间(出参回显)'), ('content[].schemeCardStatus', 'number', '方案卡状态(出参回显)'), ('content[].followed', 'boolean', '当前用户是否已关注(出参回显)'), ('content[].poolStageNameSnapshot','string', '入池前节点名称(公海视图专属)'), ('total', 'number', '总条数'), ('size', 'number', '每页条数'), ('current', 'number', '当前页码'), ('pages', 'number', '总页数'), ('empty', 'boolean', '是否为空'), ] OPP_ELEM = '''{ "id": "1", "oppName": "示例商机", "oppStatus": 2, "primaryCustomerNameSnapshot": "示例客户", "projectAmount": 1000000, "ownerNameSnapshot": "张三", "ownerDeptName": "华北大区", "currentStageName": "需求确认", "stageStayDays": 3, "nextStageName": "方案报价", "lastFollowTime": "2024-01-02 10:00:00", "schemeCardStatus": 1, "followed": true, "poolStageNameSnapshot": null }''' PAGE_RESP_JSON = env_json('{\n "content": [\n' + OPP_ELEM + '\n ],\n "total": 1,\n "size": 10,\n "current": 1,\n "pages": 1,\n "empty": false\n }') # 三个菜单的分页配置 menus = [ ('商机模块/销售机会', 1, 'RECENT/MINE/PARTICIPATED/FOLLOWED', '销售机会菜单:4 个子菜单(最近访问/我负责的/我参与的/我关注的)共用此接口,由 `viewType` 区分。\n' '普通列表与分屏列表均调此接口(分屏右侧预览走「商机详情/主体」接口)。\n' '此菜单支持自定义检索(`savedViewId` 参数);商机管理/商机公海不支持。\n' '数据隔离:个人四视图叠加团队成员白名单;`@DataScope` 部门天花板。'), ('商机模块/商机管理', 1, 'MANAGE', '商机管理菜单:`viewType=MANAGE`,按 `@DataScope` 部门天花板可见全部商机(不叠团队白名单)。\n' '普通列表与分屏列表共用此接口。不支持自定义检索(`savedViewId` 忽略)。'), ('商机模块/商机公海', 1, 'PUBLIC_POOL', '商机公海菜单:`viewType=PUBLIC_POOL`,部门天花板下 `oppStatus=1 待领取` 的公海池商机。\n' '普通列表与分屏列表共用此接口。'), ] for folder, seq, vt_hint, desc in menus: kv = [('viewType', vt_hint.split('/')[0]), ('current','1'), ('size','10')] docs = build_docs( '商机分页', 'POST', '/api/opportunity/page', desc, PAGE_PARAMS, req_form_example('POST', '/api/opportunity/page', kv), OPP_DTO_RESP, PAGE_RESP_JSON, ) write_bru(folder, '商机分页.bru', bru_form(seq, '商机分页', 'post', '/api/opportunity/page', kv, docs)) # ── 看板接口(3 菜单各一份副本)────────────────────────────────────── BOARD_MENUS = [ '商机模块/销售机会/看板列表', '商机模块/商机管理/看板列表', '商机模块/商机公海/看板列表', ] SUMMARY_PARAMS = [('stageTemplateId','string','否','-','阶段模板版本 ID(不传则按默认模板)')] SUMMARY_RESP = [ ('stageId', 'string', '阶段节点 ID'), ('stageName', 'string', '阶段名称'), ('count', 'number', '该阶段商机数量'), ('totalAmount', 'number', '该阶段项目金额合计'), ] SUMMARY_JSON = env_json('[\n {\n "stageId": "1",\n "stageName": "需求确认",\n "count": 3,\n "totalAmount": 3000000\n }\n ]') CARDS_PARAMS = [ ('stageId','string','是','-','阶段节点 ID'), ('offset', 'number','否','0', '偏移量(滚动翻页用,非页码)'), ('limit', 'number','否','20','每次拉取条数'), ] CARDS_RESP = [ ('id', 'string', '商机 ID'), ('oppName', 'string', '商机名称'), ('primaryCustomerNameSnapshot','string', '主要意向客户名'), ('projectAmount', 'number', '项目金额'), ('ownerNameSnapshot', 'string', '负责人姓名'), ('stageStayDays', 'number', '当前阶段停留天数'), ('lastFollowTime', 'string', '最近跟进时间'), ] CARDS_JSON = env_json('[\n {\n "id": "1",\n "oppName": "示例商机",\n "primaryCustomerNameSnapshot": "示例客户",\n "projectAmount": 1000000,\n "ownerNameSnapshot": "张三",\n "stageStayDays": 3,\n "lastFollowTime": "2024-01-02 10:00:00"\n }\n ]') for folder in BOARD_MENUS: # 看板阶段汇总 docs = build_docs( '看板阶段汇总', 'POST', '/api/opportunity/board/stage-summary', '看板视图:按阶段模板展开泳道头汇总(商机数量 + 项目金额合计)。', SUMMARY_PARAMS, req_form_example('POST', '/api/opportunity/board/stage-summary', [('stageTemplateId','1')]), SUMMARY_RESP, SUMMARY_JSON, ) write_bru(folder, '看板阶段汇总.bru', bru_form(1, '看板阶段汇总', 'post', '/api/opportunity/board/stage-summary', [('stageTemplateId','1')], docs)) # 看板阶段卡片 kv = [('stageId','1'),('offset','0'),('limit','20')] docs = build_docs( '看板阶段卡片', 'POST', '/api/opportunity/board/cards', '看板视图:拉取指定阶段泳道的商机卡片列表(offset+limit 滚动翻页)。', CARDS_PARAMS, req_form_example('POST', '/api/opportunity/board/cards', kv), CARDS_RESP, CARDS_JSON, ) write_bru(folder, '看板阶段卡片.bru', bru_form(2, '看板阶段卡片', 'post', '/api/opportunity/board/cards', kv, docs)) print('batch2 done')