# 客户模块接口汇总(票 13) > **载体**:本文为速查汇总;完整契约以 knife4j 在线文档为准(`http://:8080/doc.html`,`@Schema`/`@Operation` 注解齐全,与实现签名一致)。 > **范围**:crm-customer 全部 REST 端点 + 跨模块依赖(crm-rule 提醒配置 / crm-preference saved-view)。按原型界面分组(票 12 逐页对齐同源)。 > **状态**:票 12 对齐后同步版(含不符②③④⑤修复);「已知缺口」见 §5。 ## 0. 通用约定 - **认证**:`Authorization: Bearer `(网关注入用户上下文;`SecurityUtils.getRequiredUserId()`)。 - **统一响应**:`Result` = `{code, success, message, data}`;`code=0` 成功,非 0 业务错误(§2 错误码)。 - **分页**:请求继承 `BaseParam`(`current`/`size`,非 pageNo/pageSize);响应 `PageResult` = `{content, total, ...}`,取列表 `getContent()`。 - **ID 精度**:雪花 Long 在 JSON 中**序列化为字符串**(前端勿做 Number 运算)。 - **权限**: - RBAC 功能权限:`ApiPermissionInterceptor` 注册规则匹配;**未匹配规则 fail-open 放行**(新端点无需登记即生效)。 - 数据范围:`overview` 列表/看板等查询经 `@DataScope` 注入可见范围(我的客户=负责人或协同人;公海=无归属)。 - **脱敏现状**:查重相似命中 `CustomerSimilarHitDTO.masked`;详情敏感信息三档(手机号/证件等分档脱敏)**V1 未纳入**(issues-07 定稿划出,§5)。 - **时间**:`yyyy-MM-dd HH:mm:ss`;日志日期分组由前端按日渲染。 ## 1. 错误码总表(67xxx,`CustomerConstants`) | 码 | 常量 | 含义 | |---|---|---| | 67001 | CODE_CUST_INVALID | 客户入参非法(必填缺失/格式错误) | | 67002 | CODE_CUST_NOT_EXIST | 客户不存在或已被删除 | | 67003 | CODE_CREDIT_CODE_DUP | 统一社会信用代码已被占用(L3 硬拦) | | 67004 | CODE_STATUS_NOT_ALLOWED | 当前状态不允许此操作(归档/恢复/抛公海守卫) | | 67005 | CODE_CAS_FAIL | 乐观锁 CAS 冲突 | | 67006 | CODE_ARCHIVE_BLOCKED | 归档被阻断:存在进行中商机 | | 67007 | CODE_POOL_BLOCKED | 抛公海被阻断:存在进行中商机 | | 67008 | CODE_CONTACT_INVALID | 联系人入参非法/不属于该客户 | | 67009 | CODE_FOLLOW_INVALID | 跟进入参非法(内容缺失/下次跟进时间早于本次) | | 67010 | CODE_TRANSFER_DUP_RUNNING | 交割被阻断:存在未完成交接单(防重入) | | 67011 | CODE_TRANSFER_FORBIDDEN | 交割被阻断:无可交接客户/接收总监不合法/非本人发起 | | 67012 | CODE_ASSIGN_INVALID | 分配非法:明细已分配/对象越权/为发起人本人/为当前负责人 | | 67013 | CODE_IMPORT_PRECHECK_FAIL | 导入预校验失败(文件/表头/行数/模板版本) | | 67014 | CODE_IMPORT_STATUS_NOT_ALLOWED | 导入任务状态不允许此操作 | | 67015 | CODE_DEDUP_RULE_MISSING | 查重设置单例缺失 | | 67016 | CODE_MEMBER_INVALID | 成员管理非法:名单空/含负责人/重复加入/用户停用/成员不存在 | ## 2. 按原型界面接口清单 ### 2.1 A4-2-1 客户总览 / A4-2-2 我的客户(`CustomerWorkspaceController /api/customer/workspace`) | 方法 | 路径 | 说明 | 关键入参 | 主要错误码 | |---|---|---|---|---| | POST | `/{workspace}/page` | 列表分页(saved-view 过滤器接入,票 10) | workspace=`overview`/`mine`/`pool`;`CustomerPageParam`(viewType:ASSIGNED/COLLABORATING/FOCUSED…;BaseParam 分页) | 67002 | | POST | `/{workspace}/board/summary` | 看板三分组数量汇总(D20) | viewType、分组维度(stage/customerStar/relationStar) | — | | POST | `/{workspace}/board/cards` | 看板单组卡片 | 同上 + 分组键值 + 分页 | — | 出参 `CustomerListRowDTO`:主表快照 + 关联业务计数(opportunityCount 真算 / projectCount 恒 null 显 "--")。 ### 2.2 A4-1-1 客户公海列表(同上 Controller + `CustomerOwnershipController /api/customer`) | 方法 | 路径 | 说明 | 主要错误码 | |---|---|---|---| | POST | `/api/customer/workspace/pool/page` | 公海分页(检索:类型/行业;排序:进入公海时间 grill Q19) | — | | POST | `/api/customer/claim?id=` | 领取(幂等口径见实现) | 67002/67004 | | POST | `/api/customer/claim-batch?ids=` | 批量领取 → `BatchResult{successes,failures[]}` | 同上 | | POST | `/api/customer/assign?id=&userId=` | 分配(校验启用在职,口径同 validateTargetUser) | 67002/67012 | | POST | `/api/customer/assign-batch?ids=&userId=` | 批量分配 | 同上 | | POST | `/api/customer/release-pool?id=` | 抛公海(前置:无进行中商机;软删 team_member) | 67002/67007 | | POST | `/api/customer/release-pool-batch?ids=` | 批量抛公海(逐条独立事务,部分成功 → `BatchResult{successes,failures[]}`) | 67002/67007 | ### 2.3 A4-3-3-1 新增/编辑客户 + 查重(`CustomerController /api/customer`) | 方法 | 路径 | 说明 | 主要错误码 | |---|---|---|---| | POST | `/api/customer` | 新增(form 绑定 `CustomerCreateDTO`;三层查重内建;ownerUserId 空=进公海记 enter_pool_time) | 67001/67003/67015 | | PUT | `/api/customer/{id}` | 编辑(CAS:version 带回;归属字段不可改) | 67001/67002/67003/67005 | | GET | `/api/customer/{id}` | 详情(编辑页全字段回显,字典回显名) | 67002 | | POST | `/api/customer/page` | 基础分页(keyword/阶段/档案/类型;DataScope) | — | | GET | `/api/customer/check-name?name=&excludeId=` | 名称相似查重(L2,ngram 阈值 70/80/90;D21) | 67015 | | GET | `/api/customer/check-credit-code?creditCode=` | 信用代码查重(L3 硬拦预检) | 67003 | | GET | `/api/customer/company-lookup?keyword=` | 工商联想(企查查 seam,V1 可空实现) | — | **查重弹窗返回结构**:`CustomerSaveResultDTO{needConfirm=true, similarHits:[{customerId, customerName, ownerName, customerStage, archiveStatus, masked}]}`(未落库);确认后带 `confirmSimilar=true` 重发(完整 create 支持;quick-create 缺口见 §5)。 ### 2.4 商机弹窗快建 + 商机侧硬依赖(票 03,`/api/customer`) | 方法 | 路径 | 说明 | 主要错误码 | |---|---|---|---| | POST | `/api/customer/quick-create` | 快建(`CustomerQuickCreateDTO` 最小集;服务端默认 owner=当前用户、is_child=否、isBizNegotiated=否) | 67001/67003 | | POST | `/api/customer/search` | 商机侧客户搜索(名称/联系人/电话三维模糊 + 类型精确;DataScope) | — | | GET | `/api/customer/{customerId}/contacts` | 商机详情带出联系人(票 11 跨模块 port 消费方) | 67002 | ### 2.5 A4-4-1 客户详情:公共头部 + 8 页签(`CustomerDetailController /api/customer`) | 方法 | 路径 | 说明 | 主要错误码 | |---|---|---|---| | GET | `/{id}/detail-head` | 公共头部聚合(快照+跟进摘要+待跟进提醒+关联业务计数;**汇总卡 5 字段恒 null 显 "--"**:wonProjectAmount/planEstimateAmount/ongoingOpportunityAmount/contractAmount/paidAmount,grill Q18 契约=前端渲染 4 卡不显 0) | 67002 | | GET | `/{id}` | 页签 1 客户信息(=编辑页 detail) | 67002 | | GET | `/{customerId}/contacts` | 页签 2 联系人 | — | | GET | `/{id}/follow/page` | 页签 3 跟进记录(时间倒序+日期分组前端;过滤 follow_way/keyword/时间范围) | 67002 | | GET | `/{id}/opportunities` | 页签 4 关联商机(port 反查;失败前端显 "--") | 67002 | | — | 页签 5/6 | 关联项目/战略协议:V1 骨架显 "--"(A5/战略协议子域未建) | — | | GET | `/{id}/members` | 页签 7 团队成员(负责人+协同人,ROLE_OWNER 在前) | 67002 | | GET | `/{id}/oplog/page` | 页签 8 操作日志(§2.6) | 67002 | **写跟进**:`POST /{id}/follow`(`FollowCreateDTO`:followWay/followContent/nextFollowTime;append-only 不可改删;副作用刷新 `last_valid_follow_time` 超期锚点)——67002/67009。 ### 2.6 A4-4-8 操作日志(append-only,无限期保留 §5.5) `GET /api/customer/{id}/oplog/page`(`OplogPageParam`:startTime/endTime/**action**/keyword 匹配 detail)。 **action 值域(11 种)**:`CREATE/UPDATE/FOLLOW/ARCHIVE/RESTORE/TRANSFER/CLAIM/POOL/STAGE_CHANGE/MEMBER_ADD/MEMBER_REMOVE`;detail 叙事形态 `把 {字段} 从 {旧} 修改为 {新}`(D13);阶段变化 operator=系统;导入记 CREATE+UPDATE(§E 值域无 IMPORT)。 ### 2.7 团队成员管理(票 12 不符②补实现) | 方法 | 路径 | 说明 | 主要错误码 | |---|---|---|---| | POST | `/{id}/members` | 添加协同人(form `MemberAddDTO{memberUserIds[]}`;两阶段校验整批拒绝;批内幂等去重;姓名快照;oplog MEMBER_ADD) | 67002/67016 | | DELETE | `/{id}/members/{memberUserId}` | 移除协同人(软删 delete_key=id 可重复加入;oplog MEMBER_REMOVE) | 67002/67016 | ### 2.8 关注 / 重点客户标记(票 12 不符③补实现,`CustomerFocusController /api/customer`) | 方法 | 路径 | 说明 | 主要错误码 | |---|---|---|---| | POST | `/{id}/focus` | 关注(幂等;行存在性=关注态) | 67002 | | POST | `/{id}/unfocus` | 取关(物理删行,连带清重点标记) | — | | POST | `/{id}/star` | 标记重点客户(未关注自动建行 starred=1;幂等) | 67002 | | POST | `/{id}/unstar` | 取消重点标记(保留行仅置 starred=0;幂等) | — | | POST | `/focus-batch?ids=` | 批量关注(逐个幂等;对称商机) | 67002 | 一行两态语义:`customer_focus` 行存在=关注,`starred` 列=重点标记;均不写 oplog。 ### 2.9 归档 / 恢复(`CustomerOwnershipController /api/customer`) `POST /archive?id=`(前置无进行中商机;归档=删除语义 D19)、`POST /archive-batch?ids=`、`POST /restore?id=`——67002/67004/67006。 ### 2.10 A4-7-1 客户交割(`CustomerTransferController /api/customer/transfer`) | 方法 | 路径 | 说明 | 主要错误码 | |---|---|---|---| | GET | `/preview` | 待交接客户预览(离职总监名下有效客户) | — | | POST | `/initiate` | 发起交接(`TransferInitiateDTO`:reason 三选一 resign/transfer_post/region_adjust 必填;整批原子 @Transactional;owner 联动商机/项目 port;oplog TRANSFER 系统操作含交接编号) | 67010/67011/67012 | | GET | `/{id}` | 交接单详情(进度=assignedCount/totalCount) | — | | GET | `/page` | 交接单分页 | — | | GET | `/{id}/assignable` | 可分配销售列表 | — | | POST | `/{id}/assign` | 明细分配(`BatchResult` 行级部分成功) | 67012 | 状态:交接单 0 待分配→1 已完成(全分配自动置位 D23);明细 0/1。 ### 2.11 A4-3-2 客户导入(`CustomerImportController /api/customer/import`) | 方法 | 路径 | 说明 | 主要错误码 | |---|---|---|---| | POST | `/upload` | 上传预校验(MultipartFile + importMode:APPEND_ONLY/UPDATE_ONLY/UPSERT;DRAFT 落库待确认) | 67013 | | GET | `/template` | 下载模板(版本 V1 锚点) | — | | POST | `/{taskId}/confirm` | 确认执行(两段式) | 67014 | | GET | `/{taskId}` | 结果(行级部分成功:总数/成功/失败) | — | | GET | `/{taskId}/failures` | 失败明细 | 67014 | | GET | `/page` | 任务分页 | — | 状态机:0 DRAFT→1 RUNNING→2 DONE/3 FAILED(重复确认 67014)。 ### 2.12 A7-3-3-1 超期提醒配置(跨模块:crm-rule) | 方法 | 路径 | 说明 | |---|---|---| | GET | `/api/rule/customer/reminder` | 当前单例配置(总开关/首次 30 天/二次 7 天/独立开关) | | PUT | `/api/rule/customer/reminder` | 保存(**唯一 @RequestBody JSON 端点**) | ### 2.13 saved-view / 列偏好(跨模块:crm-preference,票 10) `/api/preference/view` CRUD(scope_key:`customer.overview`/`customer.mine`/`customer.pool`,三 workspace 互斥)+ `/api/preference` 列偏好。过滤器在 workspace/page 生效(saved-view 接入)。 ### 2.14 健康检查 `CustomerPingController /api/customer`:GET ping(联通性,无业务)。 ## 3. 状态/值域附录 - **archive_status**:1 有效 / 2 已归档(无合并态 D19);**customer_stage**:1 潜在 / 2 重潜(D20 seam 不触发)/ 3 已成交(三态只前进,CAS)。 - **编号**:客户 `KH+yyyyMMdd+4 位`;交割 `JG+yyyyMMdd+4 位`。 - **viewType**(workspace/mine):ASSIGNED 我负责的 / COLLABORATING 我协同的 / FOCUSED 我关注的(customer_focus EXISTS)等内置视图。 - **导入模式**:APPEND_ONLY / UPDATE_ONLY / UPSERT;任务状态 0/1/2/3。 - **通知**(票 09 内部):FOLLOW_OVERDUE;状态 0 待发/1 已发/2 已失效。 ## 4. 联调速查 - knife4j:`http://localhost:8080/doc.html`;token 放 `Authorization: Bearer`。 - 写端点均为 **form 绑定**(无 @RequestBody),除 crm-rule 提醒配置 PUT 为 JSON。 - 冒烟脚本范式:`tmp/smoke-t12m.py`(python urllib + pymysql autocommit 查库,坑㉕)。 ## 5. 已知缺口与范围外(如实记录,避免联调踩坑) 1. **QuickCreateDTO 无 confirmSimilar 字段**:商机弹窗快建命中相似客户时返回 needConfirm 但无法「仍要创建」(票 02/03 范围)。 2. **查重设置页(A7-3-3-2)无对外端点**:规则单例由服务端种子化 + 运维改库;前端设置页 V1 无接口支撑。 3. **详情页签 5/6**(关联项目/战略协议)恒显 "--";**汇总卡 5 字段恒 null**(进行中商机总额可经 port 扩展后切真值)。 4. **敏感信息三档脱敏 + 查看日志**、**合并客户**、**客户导出**:定稿划出(范围外)。 5. 联系人子表导入:原型 9.2-9 提及,按 REVIEW-HANDOFF 划出 V1。