You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

77 lines
5.3 KiB

4 days ago
## Answer
**Status: resolved**
### A. 实体 `customer_contact`(crm-customer,独立表)
| Java 字段 | 列名 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
| id | id | bigint | | 主键 ASSIGN_ID |
| customerId | customer_id | bigint | ✅ | 所属客户;NOT NULL,无孤立联系人 |
| name | name | varchar(50) | ✅ | 联系人姓名 |
| jobTitleName | job_title_name | varchar(100) | ✅ | 职务名称(文本,始终存) |
| jobTitleId | job_title_id | bigint | | 标准职务 id(字典/预置表),自定义职务时为 NULL |
| jobTitleCategory | job_title_category | varchar(50) | | 职务类别(高层管理/采购/…),自定义职务时为 NULL |
| jobTitleLevel | job_title_level | int | | 职务层级(图谱用),自定义职务时为 NULL |
| phone | phone | varchar(20) | | 联系电话;手机号格式校验 |
| isKeyContact | is_key_contact | tinyint | | 是否关键联系人(是1/否0) |
| isInternal | is_internal | tinyint | | 是否内线(是1/否0) |
| giftRemark | gift_remark | varchar(500) | | 礼品备注 |
| source | source | varchar(20) | | 来源字典 `contact_source`:组会/组局/转介绍/其他 |
| createBy / createTime / updateBy / updateTime | — | — | | BaseEntity |
| deleted | deleted | tinyint default 0 | | 逻辑删除 |
> ⚠ **孤立单大写字母检查**(AGENTS.md):`isKeyContact`→`is_key_contact`、`isInternal`→`is_internal`、`jobTitleName`/`jobTitleId`/`jobTitleCategory`/`jobTitleLevel`——均为「完整词 + 完整词」,**无需 `@Column(name=...)`**。
**索引**:
- `idx_contact_customer` (customer_id, deleted)
- ~~`uk_contact_phone` (phone) 全局唯一~~ **已撤销(D26 第三轮翻案,20260902 用户拍板 A)**:不建电话唯一索引。电话查重=可配置软提示(跟随 crm-rule 客户查重设置「联系电话」开关,默认开),命中只提示疑似重复、不禁止创建。仅保留**同一客户内**两个联系人电话不重复的表单级校验(票 04 B4 内联查重)
- `idx_contact_name` (name) — 全局搜索
**权限模型(定稿,原型明文「联系人不设独立 ACL,继承客户权限」)**:
- 无独立 `@DataScope` 注解;服务层显式按 customer 校验(对客户有读权限 → 对其全部联系人有读权限)。
- 无客户读写权限时隐藏联系人新增/编辑/删除入口;服务端仍校验。
### B. 契约(对齐商机硬依赖,promote 自 opp-customer-dependency 分析报告)
| 优先级 | 接口 | 说明 |
|---|---|---|
| P0 | `POST /api/customer/search` | 客户搜索(名称/联系人/电话/类型 四维模糊 + 分页),商机新增关联客户数据源 |
| P0 | `GET /api/customer/{id}/contacts` | 按客户查联系人列表 |
| P0 | `GET /api/customer/{id}` | 客户基础信息带出 |
| P1 | `GET /api/customer/contact/search` | 联系人全局搜索(带出所属公司名),商机「商机关键联系人」数据源 |
| P1 | `POST /api/customer/quick-create` | 快速创建客户(最小必填集),商机弹窗入口 |
| P2 | `GET /api/customer/{id}/detail` | 客户详情(新窗口跳转),复用票 07 详情页 |
### C. 联系人 CRUD 契约(定稿)
```
POST /api/customer/contact 新增联系人(可指定 customer_id 或独立新增后关联)
PUT /api/customer/contact/{id} 编辑
DELETE /api/customer/contact/{id} 删除(软删)
GET /api/customer/contact/{id} 详情
GET /api/customer/contact/page 顶级联系人列表(A4-5-1,跨客户,按 DataScope)
POST /api/customer/contact/import 批量导入(划出本图 → 随图谱 effort,本图只留接口占位)
```
### D. 随客户新增的内嵌明细(定稿)
- 新增客户表单「联系人」Tab = 明细表数组,**客户保存成功后**与客户建立关联(原型 3.5 §1)。
- 电话内联查重:**同一客户内**两行电话相同禁止提交(表单级硬校验);跨客户电话精确命中=**软提示疑似重复、不阻断**(跟随查重设置「联系电话」开关,D26 翻案后口径,票 04 B4 同步收敛为提示)。
- 删除仅移除本次未保存行;已输入内容行删除前确认。
### E. 产品确认项 — 已随 grill 全部销号
| # | 问题 | 影响 |
|---|---|---|
| P0-1 | ~~联系人电话唯一约束(grill Q16=B 全局唯一)~~ **已翻案(D26 第三轮复核,20260902 用户拍板 A)**:不建 `uk_contact_phone` 唯一索引;电话查重=可配置软提示(跟随查重设置「联系电话」开关),命中只提示不阻断;仅同客户内联系人电话不重复为表单级校验 | 撤销唯一索引;软提示走查重设置开关 |
| P1-1 | ~~「来源」字典完整值~~ **已拍板(grill Q17)**:种子 = 组会/组局/转介绍/其他 4 项,后续在字典补 | crm-dict 种子 |
### F. 回填 / 下游
- **票 02**:无主表字段变化(联系人是子表)。
- **票 04**:联系人内联查重(B4)已回填。
- **票 07**:客户详情「联系人」页签复用 `GET /api/customer/{id}/contacts`
- **票 01**:CONTEXT.md 术语「联系人」「关键联系人」。
- **crm-dict**:新增 `contact_source` 分组 + `job_title` 标准职务预置(图谱 effort 用它,本图只留 jobTitleId 引用位)。