# -*- coding: utf-8 -*- """第4批:商机详情/主体(9 个)""" 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, req_form_example, req_query_example F = '商机模块/商机详情/主体' OPP_DETAIL_RESP = [ ('id','string','商机 ID'), ('createTime','string','创建时间'), ('updateTime','string','更新时间'), ('oppName','string','商机名称'), ('oppStatus','number','状态:1待领取 2推进中 3暂缓中 4已关闭 5已转项目'), ('oppSource','string','商机来源字典 code'), ('oppType','string','商机类型字典 code'), ('industryCode','string','行业字典 code'), ('industryName','string','行业名称(出参回显)'), ('bidForm','string','招标形式字典 code'), ('localityType','string','项目属地字典 code'), ('partyAClear','number','甲方是否明确'), ('partyA','string','甲方名称'), ('provinceCode','string','省份国标 code'), ('provinceName','string','省份名称(出参回显)'), ('cityCode','string','市/区国标 code'), ('cityName','string','市/区名称(出参回显)'), ('projectAmount','number','项目金额'), ('ownerUserId','string','负责人 ID'), ('ownerNameSnapshot','string','负责人姓名快照'), ('ownerDeptId','string','负责人部门 ID'), ('ownerDeptName','string','负责人部门名称(出参回显)'), ('currentStageId','string','当前阶段节点 ID'), ('currentStageName','string','当前阶段名称(出参回显)'), ('stageStayDays','number','节点停留天数(出参回显)'), ('nextStageName','string','下一节点名称(出参回显)'), ('sourceLeadId','string','来源线索 ID'), ('primaryCustomerId','string','主要意向客户 ID'), ('primaryCustomerNameSnapshot','string','主客户名快照'), ('lastFollowTime','string','最近跟进时间(出参回显)'), ('schemeCardStatus','number','方案卡状态(出参回显)'), ('schemeBudget','number','方案预算(出参回显)'), ('followed','boolean','当前用户是否已关注(出参回显)'), ('remark','string','备注'), ] OPP_DETAIL_JSON = env_json('''{ "id": "1", "createTime": "2024-01-01 12:00:00", "updateTime": "2024-01-01 12:00:00", "oppName": "示例商机", "oppStatus": 2, "oppSource": "source_01", "oppType": "type_01", "industryCode": "ind_01", "industryName": "示例行业", "projectAmount": 1000000, "ownerUserId": "1", "ownerNameSnapshot": "张三", "ownerDeptName": "华北大区", "currentStageName": "需求确认", "stageStayDays": 3, "nextStageName": "方案报价", "followed": true, "remark": "备注示例" }''') # 商机详情 docs = build_docs( '商机详情', 'GET', '/api/opportunity/detail', '详情页顶部主体信息。打开详情页时与「上报访问」同步调用(前端可并行发起)。', [('id','string','是','-','商机 ID')], req_query_example('GET', '/api/opportunity/detail', [('id','1')]), OPP_DETAIL_RESP, OPP_DETAIL_JSON, ) write_bru(F, '商机详情.bru', bru_form(1, '商机详情', 'get', '/api/opportunity/detail', [('id','1')], docs)) # 编辑商机 EDIT_PARAMS = [ ('id','string','是','-','商机 ID'), ('oppName','string','否','-','商机名称'), ('oppSource','string','否','-','商机来源字典 code'), ('oppType','string','否','-','商机类型字典 code'), ('industryCode','string','否','-','行业字典 code'), ('bidForm','string','否','-','招标形式字典 code'), ('localityType','string','否','-','项目属地字典 code'), ('partyAClear','number','否','-','甲方是否明确:1是 0否'), ('partyA','string','否','-','甲方名称'), ('provinceCode','string','否','-','省份国标 code'), ('cityCode','string','否','-','市/区国标 code'), ('projectAmount','number','否','-','项目金额'), ('primaryCustomerId','string','否','-','主要意向客户 ID'), ('remark','string','否','-','备注'), ] docs = build_docs( '编辑商机', 'POST', '/api/opportunity/edit', '详情页「编辑」保存。仅传需变更的字段(null 不更新),字段级 oplog 自动记录变更前后值。', EDIT_PARAMS, req_form_example('POST', '/api/opportunity/edit', [('id','1'),('oppName','更新后商机名称'),('projectAmount','1200000')]), None, env_json('null'), ) write_bru(F, '编辑商机.bru', bru_form(2, '编辑商机', 'post', '/api/opportunity/edit', [('id','1'),('oppName','更新后商机名称'),('projectAmount','1200000')], docs)) # 阶段推进指引 STAGE_NODE_RESP = [ ('oppId','string','商机 ID'), ('currentStageId','string','当前阶段节点 ID'), ('currentWorkGoal','string','当前节点工作目标(推进指引区展示)'), ('nodes','array','有序节点列表'), ('nodes[].nodeId','string','节点 ID'), ('nodes[].seqNo','number','阶段序号'), ('nodes[].stageDictCode','string','阶段字典值'), ('nodes[].customNodeName','string','自定义节点名称(空则用字典名)'), ('nodes[].workGoal','string','阶段工作目标'), ('nodes[].isFixed','number','固定节点:1已转项目固定节点 0普通'), ('nodes[].nodeState','string','进度:COMPLETED已完成 / CURRENT当前 / PENDING未到达'), ] STAGE_PROGRESS_JSON = env_json('''{ "oppId": "1", "currentStageId": "2", "currentWorkGoal": "确认客户预算与决策链", "nodes": [ { "nodeId": "1", "seqNo": 1, "stageDictCode": "stage_01", "customNodeName": null, "workGoal": "初步接触", "isFixed": 0, "nodeState": "COMPLETED" }, { "nodeId": "2", "seqNo": 2, "stageDictCode": "stage_02", "customNodeName": null, "workGoal": "确认客户预算与决策链", "isFixed": 0, "nodeState": "CURRENT" } ] }''') docs = build_docs( '阶段推进指引', 'GET', '/api/opportunity/stage/progress', '详情页阶段进度组件:展示三态(已完成/当前/未到达)+ 当前节点工作目标。按商机绑定的模板版本展开(锁版本,发新版不迁移)。', [('oppId','string','是','-','商机 ID')], req_query_example('GET', '/api/opportunity/stage/progress', [('oppId','1')]), STAGE_NODE_RESP, STAGE_PROGRESS_JSON, ) write_bru(F, '阶段推进指引.bru', bru_form(3, '阶段推进指引', 'get', '/api/opportunity/stage/progress', [('oppId','1')], docs)) # 阶段推进历史 STAGE_HIST_RESP = [ ('id','string','历史记录 ID'), ('oppId','string','商机 ID'), ('fromStageId','string','原阶段节点 ID'), ('toStageId','string','目标阶段节点 ID'), ('operatorUserId','string','操作人 ID(系统动作为 0)'), ('operateTime','string','操作时间'), ('remark','string','推进说明'), ] docs = build_docs( '阶段推进历史', 'GET', '/api/opportunity/stage/history', '按操作时间倒序返回该商机全部阶段推进记录(人工推进 + 系统动作合并展示)。', [('oppId','string','是','-','商机 ID')], req_query_example('GET', '/api/opportunity/stage/history', [('oppId','1')]), STAGE_HIST_RESP, env_json('[\n {\n "id":"1","oppId":"1","fromStageId":"1","toStageId":"2","operatorUserId":"1","operateTime":"2024-01-01 12:00:00","remark":"推进示例"\n }\n ]'), ) write_bru(F, '阶段推进历史.bru', bru_form(4, '阶段推进历史', 'get', '/api/opportunity/stage/history', [('oppId','1')], docs)) # 切换阶段 docs = build_docs( '切换阶段', 'POST', '/api/opportunity/stage/switch', '自由切换阶段:允许连跳/回退。「已转项目」固定节点不可手动切(由业务流程触发)。', [('oppId','string','是','-','商机 ID'), ('toStageId','string','是','-','目标阶段节点 ID(须属商机绑定的模板版本)'), ('remark','string','否','-','推进说明')], req_form_example('POST', '/api/opportunity/stage/switch', [('oppId','1'),('toStageId','3'),('remark','客户已确认预算')]), None, env_json('null'), ) write_bru(F, '切换阶段.bru', bru_form(5, '切换阶段', 'post', '/api/opportunity/stage/switch', [('oppId','1'),('toStageId','3'),('remark','客户已确认预算')], docs)) # 关注商机 docs = build_docs( '关注商机', 'POST', '/api/opportunity/focus', '当前登录人关注该商机(详情页/列表关注按钮)。已关注再次调用幂等无副作用。', [('oppId','string','是','-','商机 ID')], req_form_example('POST', '/api/opportunity/focus', [('oppId','1')]), None, env_json('null'), ) write_bru(F, '关注商机.bru', bru_form(6, '关注商机', 'post', '/api/opportunity/focus', [('oppId','1')], docs)) # 取关商机 docs = build_docs( '取关商机', 'POST', '/api/opportunity/unfocus', '取消关注。未关注时调用幂等。', [('oppId','string','是','-','商机 ID')], req_form_example('POST', '/api/opportunity/unfocus', [('oppId','1')]), None, env_json('null'), ) write_bru(F, '取关商机.bru', bru_form(7, '取关商机', 'post', '/api/opportunity/unfocus', [('oppId','1')], docs)) # 批量关注 docs = build_docs( '批量关注', 'POST', '/api/opportunity/focus-batch', '列表多选后批量关注,每条幂等。', [('ids','string','是','-','商机 ID 列表,逗号分隔')], req_form_example('POST', '/api/opportunity/focus-batch', [('ids','1,2,3')]), None, env_json('null'), ) write_bru(F, '批量关注.bru', bru_form(8, '批量关注', 'post', '/api/opportunity/focus-batch', [('ids','1,2,3')], docs)) # 上报访问 docs = build_docs( '上报访问', 'POST', '/api/opportunity/view-touch', '打开商机详情页时前端自动调用一次(与「商机详情」并行发起),写入访问记录用于「最近访问」子菜单排序。无需等待响应影响页面渲染。', [('oppId','string','是','-','商机 ID')], req_form_example('POST', '/api/opportunity/view-touch', [('oppId','1')]), None, env_json('null'), ) write_bru(F, '上报访问.bru', bru_form(9, '上报访问', 'post', '/api/opportunity/view-touch', [('oppId','1')], docs)) print('batch4 done')