Files
shanxia2.0/docs/superpowers/specs/2026-05-30-crm-migration-design.md
T
2026-07-13 20:26:43 +08:00

68 KiB
Raw Blame History

CRM 模块迁移设计文档

日期: 2026-05-30 状态: 待审核 决策: 方案 A+C — 统一规范重建 + 渐进式分迭代交付


1. 背景与目标

1.1 背景

山峡化工现有两套独立系统:

  • 一体化门户 (shanxia2.0): Python FastAPI + Vue 3,覆盖系统管理、细胞存储、工作流等
  • CRM 系统 (shanxia/crm): Java Spring Boot (若依框架) + Vue 3,覆盖线索/客户/商机/合同等

目标:将 CRM 核心业务模块迁移至一体化门户,统一技术栈和运行时。

1.2 迁移范围

迁移的模块(8 个业务域,~28 张表):

模块 CRM 表 页面数 优先级
产品分类 crm_product_category 1 P0
产品管理 crm_product, crm_product_price, crm_product_price_history, crm_product_stock_log, crm_product_tag, crm_product_tag_relation(附件复用 biz_attachment) 6 P0
客户管理 crm_customer, crm_customer_follow, crm_customer_pool, crm_customer_pool_rule, crm_customer_tag, crm_customer_tag_relation 12 P1
联系人 crm_contact 4 P1
线索管理 crm_clue, crm_clue_follow 9 P2
商机管理 crm_opportunity, crm_opportunity_follow, crm_opportunity_product, crm_opportunity_stage_log 8 P2
报价管理 crm_quote, crm_quote_product, crm_quote_approval, crm_quote_share_log 7 P3
合同管理 crm_contract, crm_contract_product, crm_contract_product_price_tier, crm_contract_approval, crm_contract_change, crm_contract_template 12 P3

不迁移:报销子系统 (bx_)、拜访管理、发票管理、回款管理、智慧校园 (xg_)

1.3 交付节奏(4 个迭代)

迭代 1(基础层): 产品分类 + 产品管理 + 字典数据迁移 SQL
迭代 2(核心客户): 客户管理 + 联系人 + 标签 + 公海池
迭代 3(销售漏斗): 线索管理 + 商机管理
迭代 4(成交闭环): 报价管理 + 合同管理(含工作流审批对接)

2. 设计决策

决策点 结论 理由
主键策略 VARCHAR(64),数据迁移 原样保留源 id 见 docs/data-migration/05-id-preservation-policy.md
租户字段 统一 tenant_no VARCHAR(64) 与一体化 sys_* 表一致
用户/部门引用 VARCHAR(64) 指向 sys_user/sys_dept 复用一体化用户体系
附件策略 新建 sys_oss(基于 CRM sys_oss 结构,id→str(oss_id) + 加 tenant_no + biz_type/biz_id),全系统共用 与 CRM 源表同名同字段,方便迁移;报销/地磅等也复用
字典策略 复用一体化 sys_dict_data/sys_dict_type,CRM 字典数据迁移 SQL 插入 字典功能相同,避免两套字典割裂
工作流 复用 wf_* 引擎 合同审批、报价审批走统一工作流
字典数据 编写迁移 SQL 脚本导入 sys_dict_data CRM 使用的行业/来源/等级等字典需导入
前端 UI 按 Fresh Mint 规范重写,参考现有模板页 与一体化 UI 一致
软删除 del_flag SMALLINT DEFAULT 0 与一体化一致
排序字段 order_num INTEGER 与一体化一致(列表/弹窗默认不展示)

3. 公共字段规范(shanxia2.0 标准)

每张 CRM 业务表 SHALL 在业务字段之后包含以下公共字段:

`tenant_no`      VARCHAR(64)   NOT NULL DEFAULT 'zkxw'  COMMENT '租户编号',
`order_num`      INT                    DEFAULT NULL    COMMENT '排序号',
`remark`         VARCHAR(512)           DEFAULT NULL    COMMENT '备注',
`create_by`      VARCHAR(64)            DEFAULT NULL    COMMENT '创建人id',
`create_dept_id` VARCHAR(64)   NOT NULL DEFAULT ''      COMMENT '创建人部门ID',
`create_time`    DATETIME      NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_by`      VARCHAR(64)            DEFAULT NULL    COMMENT '更新人id',
`update_time`    DATETIME      NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`del_flag`       SMALLINT      NOT NULL DEFAULT 0       COMMENT '删除标记:0-正常 1-已删除',

主键:id VARCHAR(64) NOT NULL;生产数据迁移时写入 str(源id)(见 05-id-preservation-policy)。


4. 表结构设计(按迭代)

4.1 迭代 1 — 产品分类 + 产品管理

已排除功能(用户确认):产品定价(crm_product_price)、价格历史(crm_product_price_history)、库存日志(crm_product_stock_log)、产品标签(crm_product_tag + crm_product_tag_relation)、复制产品 — 原因:用户确认无此业务需求。

crm_product_category(产品分类,树形)

CREATE TABLE `crm_product_category` (
  `id`            VARCHAR(64)   NOT NULL                  COMMENT '主键ID',
  `parent_id`     VARCHAR(64)   NOT NULL DEFAULT '0'      COMMENT '父级分类ID(0为顶级)',
  `category_name` VARCHAR(128)  NOT NULL                  COMMENT '分类名称',
  `category_code` VARCHAR(64)            DEFAULT NULL     COMMENT '分类编码',
  `level`         TINYINT       NOT NULL DEFAULT 1        COMMENT '层级',
  `status`        CHAR(1)       NOT NULL DEFAULT '1'      COMMENT '状态 1启用 0停用',
  -- 公共字段
  `tenant_no`      VARCHAR(64)  NOT NULL DEFAULT 'zkxw'   COMMENT '租户编号',
  `order_num`      INT                   DEFAULT NULL     COMMENT '排序号',
  `remark`         VARCHAR(512)          DEFAULT NULL     COMMENT '备注',
  `create_by`      VARCHAR(64)           DEFAULT NULL     COMMENT '创建人id',
  `create_dept_id` VARCHAR(64)  NOT NULL DEFAULT ''       COMMENT '创建人部门ID',
  `create_time`    DATETIME     NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_by`      VARCHAR(64)           DEFAULT NULL     COMMENT '更新人id',
  `update_time`    DATETIME     NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `del_flag`       SMALLINT     NOT NULL DEFAULT 0        COMMENT '删除标记',
  PRIMARY KEY (`id`),
  KEY `idx_parent_id` (`parent_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CRM-产品分类';

crm_product(产品主表)

CREATE TABLE `crm_product` (
  `id`              VARCHAR(64)  NOT NULL                  COMMENT '主键ID',
  `product_no`      VARCHAR(50)  NOT NULL                  COMMENT '产品编号',
  `product_name`    VARCHAR(200) NOT NULL                  COMMENT '产品名称',
  `category_id`     VARCHAR(64)           DEFAULT NULL     COMMENT '分类ID',
  `category_name`   VARCHAR(100)          DEFAULT NULL     COMMENT '分类名称(冗余)',
  `model`           VARCHAR(100)          DEFAULT NULL     COMMENT '规格型号',
  `unit`            VARCHAR(20)  NOT NULL DEFAULT '件'     COMMENT '单位',
  `price`           DECIMAL(15,2) NOT NULL DEFAULT 0.00    COMMENT '标准单价',
  `cost_price`      DECIMAL(15,2)          DEFAULT 0.00    COMMENT '成本价',
  `status`          CHAR(1)      NOT NULL DEFAULT '1'      COMMENT '状态 1上架 0下架',
  `description`     TEXT                   DEFAULT NULL    COMMENT '产品描述',
  `package_spec`    VARCHAR(200)          DEFAULT NULL     COMMENT '包装规格',
  -- 公共字段
  `tenant_no`      VARCHAR(64)  NOT NULL DEFAULT 'zkxw'    COMMENT '租户编号',
  `order_num`      INT                   DEFAULT NULL      COMMENT '排序号',
  `remark`         VARCHAR(512)          DEFAULT NULL      COMMENT '备注',
  `create_by`      VARCHAR(64)           DEFAULT NULL      COMMENT '创建人id',
  `create_dept_id` VARCHAR(64)  NOT NULL DEFAULT ''        COMMENT '创建人部门ID',
  `create_time`    DATETIME     NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_by`      VARCHAR(64)           DEFAULT NULL      COMMENT '更新人id',
  `update_time`    DATETIME     NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `del_flag`       SMALLINT     NOT NULL DEFAULT 0         COMMENT '删除标记',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_product_no` (`product_no`, `del_flag`),
  KEY `idx_category_id` (`category_id`),
  KEY `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CRM-产品主表';

crm_product_price(产品定价)

CREATE TABLE `crm_product_price` (
  `id`              VARCHAR(64)  NOT NULL                  COMMENT '主键ID',
  `product_id`      VARCHAR(64)  NOT NULL                  COMMENT '产品ID',
  `price_type`      VARCHAR(20)  NOT NULL DEFAULT 'standard' COMMENT '价格类型 standard-标准价 wholesale-批发价 retail-零售价',
  `price`           DECIMAL(15,2) NOT NULL DEFAULT 0.00    COMMENT '价格',
  `min_quantity`    DECIMAL(20,4)          DEFAULT 1.0000  COMMENT '最低起订量',
  `effective_date`  DATE                   DEFAULT NULL    COMMENT '生效日期',
  `expiry_date`     DATE                   DEFAULT NULL    COMMENT '失效日期',
  `status`          CHAR(1)      NOT NULL DEFAULT '1'      COMMENT '状态 1有效 0无效',
  -- 公共字段
  `tenant_no`      VARCHAR(64)  NOT NULL DEFAULT 'zkxw'    COMMENT '租户编号',
  `order_num`      INT                   DEFAULT NULL      COMMENT '排序号',
  `remark`         VARCHAR(512)          DEFAULT NULL      COMMENT '备注',
  `create_by`      VARCHAR(64)           DEFAULT NULL      COMMENT '创建人id',
  `create_dept_id` VARCHAR(64)  NOT NULL DEFAULT ''        COMMENT '创建人部门ID',
  `create_time`    DATETIME     NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_by`      VARCHAR(64)           DEFAULT NULL      COMMENT '更新人id',
  `update_time`    DATETIME     NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `del_flag`       SMALLINT     NOT NULL DEFAULT 0         COMMENT '删除标记',
  PRIMARY KEY (`id`),
  KEY `idx_product_id` (`product_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CRM-产品定价';

crm_product_price_history(价格变更历史)

CREATE TABLE `crm_product_price_history` (
  `id`              VARCHAR(64)  NOT NULL                  COMMENT '主键ID',
  `product_id`      VARCHAR(64)  NOT NULL                  COMMENT '产品ID',
  `old_price`       DECIMAL(15,2) NOT NULL DEFAULT 0.00    COMMENT '变更前价格',
  `new_price`       DECIMAL(15,2) NOT NULL DEFAULT 0.00    COMMENT '变更后价格',
  `change_reason`   VARCHAR(500)          DEFAULT NULL     COMMENT '变更原因',
  -- 公共字段
  `tenant_no`      VARCHAR(64)  NOT NULL DEFAULT 'zkxw'    COMMENT '租户编号',
  `order_num`      INT                   DEFAULT NULL      COMMENT '排序号',
  `remark`         VARCHAR(512)          DEFAULT NULL      COMMENT '备注',
  `create_by`      VARCHAR(64)           DEFAULT NULL      COMMENT '创建人id',
  `create_dept_id` VARCHAR(64)  NOT NULL DEFAULT ''        COMMENT '创建人部门ID',
  `create_time`    DATETIME     NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_by`      VARCHAR(64)           DEFAULT NULL      COMMENT '更新人id',
  `update_time`    DATETIME     NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `del_flag`       SMALLINT     NOT NULL DEFAULT 0         COMMENT '删除标记',
  PRIMARY KEY (`id`),
  KEY `idx_product_id` (`product_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CRM-产品价格历史';

crm_product_stock_log(库存变动日志)

CREATE TABLE `crm_product_stock_log` (
  `id`              VARCHAR(64)  NOT NULL                  COMMENT '主键ID',
  `product_id`      VARCHAR(64)  NOT NULL                  COMMENT '产品ID',
  `change_type`     VARCHAR(20)  NOT NULL                  COMMENT '变动类型 in-入库 out-出库 adjust-调整',
  `quantity`        DECIMAL(20,4) NOT NULL DEFAULT 0.0000  COMMENT '变动数量',
  `before_qty`      DECIMAL(20,4) NOT NULL DEFAULT 0.0000  COMMENT '变动前库存',
  `after_qty`       DECIMAL(20,4) NOT NULL DEFAULT 0.0000  COMMENT '变动后库存',
  `biz_type`        VARCHAR(32)           DEFAULT NULL     COMMENT '关联业务类型 contract-合同 deliver-发货',
  `biz_id`          VARCHAR(64)           DEFAULT NULL     COMMENT '关联业务ID',
  -- 公共字段
  `tenant_no`      VARCHAR(64)  NOT NULL DEFAULT 'zkxw'    COMMENT '租户编号',
  `order_num`      INT                   DEFAULT NULL      COMMENT '排序号',
  `remark`         VARCHAR(512)          DEFAULT NULL      COMMENT '备注',
  `create_by`      VARCHAR(64)           DEFAULT NULL      COMMENT '创建人id',
  `create_dept_id` VARCHAR(64)  NOT NULL DEFAULT ''        COMMENT '创建人部门ID',
  `create_time`    DATETIME     NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_by`      VARCHAR(64)           DEFAULT NULL      COMMENT '更新人id',
  `update_time`    DATETIME     NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `del_flag`       SMALLINT     NOT NULL DEFAULT 0         COMMENT '删除标记',
  PRIMARY KEY (`id`),
  KEY `idx_product_id` (`product_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CRM-产品库存日志';

crm_product_tag(产品标签)

CREATE TABLE `crm_product_tag` (
  `id`            VARCHAR(64)  NOT NULL                   COMMENT '主键ID',
  `tag_name`      VARCHAR(64)  NOT NULL                   COMMENT '标签名称',
  `color`         VARCHAR(20)           DEFAULT NULL      COMMENT '标签颜色',
  -- 公共字段
  `tenant_no`      VARCHAR(64) NOT NULL DEFAULT 'zkxw'    COMMENT '租户编号',
  `order_num`      INT                  DEFAULT NULL      COMMENT '排序号',
  `remark`         VARCHAR(512)         DEFAULT NULL      COMMENT '备注',
  `create_by`      VARCHAR(64)          DEFAULT NULL      COMMENT '创建人id',
  `create_dept_id` VARCHAR(64) NOT NULL DEFAULT ''        COMMENT '创建人部门ID',
  `create_time`    DATETIME    NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_by`      VARCHAR(64)          DEFAULT NULL      COMMENT '更新人id',
  `update_time`    DATETIME    NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `del_flag`       SMALLINT    NOT NULL DEFAULT 0         COMMENT '删除标记',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CRM-产品标签';

crm_product_tag_relation(产品-标签关联)

CREATE TABLE `crm_product_tag_relation` (
  `id`            VARCHAR(64)  NOT NULL                   COMMENT '主键ID',
  `product_id`    VARCHAR(64)  NOT NULL                   COMMENT '产品ID',
  `tag_id`        VARCHAR(64)  NOT NULL                   COMMENT '标签ID',
  -- 公共字段
  `tenant_no`      VARCHAR(64) NOT NULL DEFAULT 'zkxw'    COMMENT '租户编号',
  `order_num`      INT                  DEFAULT NULL      COMMENT '排序号',
  `remark`         VARCHAR(512)         DEFAULT NULL      COMMENT '备注',
  `create_by`      VARCHAR(64)          DEFAULT NULL      COMMENT '创建人id',
  `create_dept_id` VARCHAR(64) NOT NULL DEFAULT ''        COMMENT '创建人部门ID',
  `create_time`    DATETIME    NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_by`      VARCHAR(64)          DEFAULT NULL      COMMENT '更新人id',
  `update_time`    DATETIME    NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `del_flag`       SMALLINT    NOT NULL DEFAULT 0         COMMENT '删除标记',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_product_tag` (`product_id`, `tag_id`),
  KEY `idx_tag_id` (`tag_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CRM-产品标签关联';

注意:crm_product_attachment 不再建独立表。产品附件统一使用 sys_oss,biz_type = 'crm_product',biz_id = 产品ID。


sys_oss(统一附件表,基于 CRM sys_oss 结构,全系统共用)

采用 CRM 系统 sys_oss 的字段模型,仅将 oss_id(bigint)改为 id(str(oss_id)),新增 tenant_no,新增 biz_type/biz_id 关联字段。 此表为 CRM、报销、地磅等所有子系统的统一附件存储,通过 biz_type 区分业务归属。 方便后续从 CRM 直接迁移 sys_oss 数据(字段名完全一致,仅 id 类型转换)。

CREATE TABLE `sys_oss` (
  `id`              VARCHAR(64)  NOT NULL                  COMMENT '主键ID(原 CRM sys_oss.oss_id)',
  `tenant_no`      VARCHAR(64)  NOT NULL DEFAULT 'zkxw'    COMMENT '租户编号(原 CRM sys_oss.tenant_id)',
  `biz_type`        VARCHAR(50)           DEFAULT NULL     COMMENT '业务类型(crm_product/crm_customer/crm_contract/bx_advance/bx_reimburse/dibang_weigh 等)',
  `biz_id`          VARCHAR(64)           DEFAULT NULL     COMMENT '业务主键ID',
  `file_name`       VARCHAR(255) NOT NULL DEFAULT ''       COMMENT '文件名(原 sys_oss.file_name)',
  `original_name`   VARCHAR(255) NOT NULL DEFAULT ''       COMMENT '原始文件名(原 sys_oss.original_name)',
  `file_suffix`     VARCHAR(10)  NOT NULL DEFAULT ''       COMMENT '文件后缀名(原 sys_oss.file_suffix)',
  `url`             VARCHAR(500) NOT NULL                  COMMENT '文件URL地址(原 sys_oss.url)',
  `file_size`       BIGINT                DEFAULT NULL     COMMENT '文件大小(字节)',
  `file_type`       VARCHAR(200)          DEFAULT NULL     COMMENT 'MIME类型',
  `attach_type`     VARCHAR(32)           DEFAULT 'attachment' COMMENT '附件类型 attachment-普通附件 invoice-发票 image-图片 issue_proof-发放截图',
  `sort_order`      INT          NOT NULL DEFAULT 0        COMMENT '排序号',
  `service`         VARCHAR(20)  NOT NULL DEFAULT 'minio'  COMMENT '存储服务商(原 sys_oss.service)',
  `ext1`            TEXT                   DEFAULT NULL    COMMENT '扩展字段(原 sys_oss.ext1)',
  -- 公共字段
  `order_num`       INT                   DEFAULT NULL     COMMENT '排序号',
  `remark`          VARCHAR(512)          DEFAULT NULL     COMMENT '备注',
  `create_by`       VARCHAR(64)           DEFAULT NULL     COMMENT '创建人id(经 user_mapping)',
  `create_dept_id`  VARCHAR(64)  NOT NULL DEFAULT ''       COMMENT '创建人部门ID',
  `create_time`     DATETIME     NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_by`       VARCHAR(64)           DEFAULT NULL     COMMENT '更新人id(经 user_mapping)',
  `update_time`     DATETIME     NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `del_flag`        SMALLINT     NOT NULL DEFAULT 0        COMMENT '删除标记:0-正常 1-已删除',
  PRIMARY KEY (`id`),
  KEY `idx_biz` (`biz_type`, `biz_id`),
  KEY `idx_tenant` (`tenant_no`, `del_flag`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='统一附件表(全系统共用,基于CRM sys_oss结构)';

4.2 迭代 2 — 客户管理 + 联系人 + 标签 + 公海池

crm_customer(客户主表)

CREATE TABLE `crm_customer` (
  `id`                VARCHAR(64)  NOT NULL                COMMENT '主键ID',
  `customer_no`       VARCHAR(50)  NOT NULL                COMMENT '客户编号',
  `customer_name`     VARCHAR(200) NOT NULL                COMMENT '客户名称',
  `short_name`        VARCHAR(100)          DEFAULT NULL   COMMENT '客户简称',
  `customer_type`     VARCHAR(20)  NOT NULL DEFAULT 'company' COMMENT '客户类型 company-企业 person-个人',
  `mobile`            VARCHAR(20)           DEFAULT NULL   COMMENT '手机号',
  `telephone`         VARCHAR(30)           DEFAULT NULL   COMMENT '固定电话',
  `email`             VARCHAR(100)          DEFAULT NULL   COMMENT '邮箱',
  `website`           VARCHAR(500)          DEFAULT NULL   COMMENT '客户网站',
  `level`             VARCHAR(20)  NOT NULL DEFAULT 'normal' COMMENT '客户级别 key-重点 normal-普通 potential-潜在',
  `source`            VARCHAR(20)           DEFAULT NULL   COMMENT '客户来源',
  `industry`          VARCHAR(50)           DEFAULT NULL   COMMENT '所属行业',
  `park_area`         VARCHAR(100)          DEFAULT NULL   COMMENT '所在园区',
  `payment_terms`     VARCHAR(500)          DEFAULT NULL   COMMENT '收付款条件',
  `scale`             VARCHAR(20)           DEFAULT NULL   COMMENT '企业规模',
  `province`          VARCHAR(50)           DEFAULT NULL   COMMENT '省',
  `city`              VARCHAR(50)           DEFAULT NULL   COMMENT '市',
  `district`          VARCHAR(50)           DEFAULT NULL   COMMENT '区',
  `address`           VARCHAR(255)          DEFAULT NULL   COMMENT '详细地址',
  `status`            VARCHAR(20)  NOT NULL DEFAULT 'normal' COMMENT '客户状态 normal-正常 pool-公海 invalid-无效',
  `deal_status`       VARCHAR(20)  NOT NULL DEFAULT 'not_deal' COMMENT '成交状态 not_deal-未成交 dealed-已成交 lost-已流失',
  `owner_user_id`     VARCHAR(64)           DEFAULT NULL   COMMENT '负责人ID',
  `owner_user_name`   VARCHAR(50)           DEFAULT NULL   COMMENT '负责人姓名(冗余)',
  `last_time`         DATETIME              DEFAULT NULL   COMMENT '最后跟进时间',
  `next_time`         DATETIME              DEFAULT NULL   COMMENT '下次联系时间',
  `follow_count`      INT          NOT NULL DEFAULT 0     COMMENT '跟进次数',
  `deal_time`         DATETIME              DEFAULT NULL   COMMENT '成交时间',
  `deal_amount`       DECIMAL(15,2)         DEFAULT 0.00   COMMENT '累计成交金额',
  `contact_count`     INT          NOT NULL DEFAULT 0     COMMENT '联系人数量',
  `opportunity_count` INT          NOT NULL DEFAULT 0     COMMENT '商机数量',
  `contract_count`    INT          NOT NULL DEFAULT 0     COMMENT '合同数量',
  `into_pool_time`    DATETIME              DEFAULT NULL   COMMENT '进入公海时间',
  `into_pool_by`      VARCHAR(64)           DEFAULT NULL   COMMENT '进入公海操作人ID',
  `into_pool_reason`  VARCHAR(500)          DEFAULT NULL   COMMENT '进入公海原因',
  `claim_time`        DATETIME              DEFAULT NULL   COMMENT '领取时间',
  `assign_time`       DATETIME              DEFAULT NULL   COMMENT '分配时间',
  `assign_by`         VARCHAR(64)           DEFAULT NULL   COMMENT '分配人ID',
  `protect_time`      DATETIME              DEFAULT NULL   COMMENT '保护到期时间',
  `clue_id`           VARCHAR(64)           DEFAULT NULL   COMMENT '关联线索ID',
  `business_license_images` VARCHAR(1000)   DEFAULT NULL   COMMENT '营业执照图片(逗号分隔附件ID)',
  `business_permit_images`  VARCHAR(1000)   DEFAULT NULL   COMMENT '经营许可证图片(逗号分隔附件ID)',
  `other_cert_images`       VARCHAR(1000)   DEFAULT NULL   COMMENT '其他证件图片(逗号分隔附件ID)',
  -- 公共字段
  `tenant_no`      VARCHAR(64) NOT NULL DEFAULT 'zkxw'     COMMENT '租户编号',
  `order_num`      INT                  DEFAULT NULL       COMMENT '排序号',
  `remark`         VARCHAR(512)         DEFAULT NULL       COMMENT '备注',
  `create_by`      VARCHAR(64)          DEFAULT NULL       COMMENT '创建人id',
  `create_dept_id` VARCHAR(64) NOT NULL DEFAULT ''         COMMENT '创建人部门ID',
  `create_time`    DATETIME    NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_by`      VARCHAR(64)          DEFAULT NULL       COMMENT '更新人id',
  `update_time`    DATETIME    NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `del_flag`       SMALLINT    NOT NULL DEFAULT 0          COMMENT '删除标记',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_customer_no` (`customer_no`, `del_flag`),
  KEY `idx_owner` (`owner_user_id`),
  KEY `idx_status` (`status`),
  KEY `idx_deal_status` (`deal_status`),
  KEY `idx_level` (`level`),
  KEY `idx_source` (`source`),
  KEY `idx_clue` (`clue_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CRM-客户主表';

crm_customer_follow(客户跟进记录)

CREATE TABLE `crm_customer_follow` (
  `id`              VARCHAR(64)  NOT NULL                  COMMENT '主键ID',
  `customer_id`     VARCHAR(64)  NOT NULL                  COMMENT '客户ID',
  `customer_name`   VARCHAR(200)          DEFAULT NULL     COMMENT '客户名称(冗余)',
  `contact_id`      VARCHAR(64)           DEFAULT NULL     COMMENT '联系人ID',
  `contact_name`    VARCHAR(100)          DEFAULT NULL     COMMENT '联系人姓名(冗余)',
  `follow_type`     VARCHAR(20)  NOT NULL                  COMMENT '跟进方式 电话/微信/邮件/拜访/其他',
  `follow_content`  TEXT         NOT NULL                  COMMENT '跟进内容',
  `next_time`       DATETIME              DEFAULT NULL     COMMENT '下次联系时间',
  -- 公共字段
  `tenant_no`      VARCHAR(64) NOT NULL DEFAULT 'zkxw'     COMMENT '租户编号',
  `order_num`      INT                  DEFAULT NULL       COMMENT '排序号',
  `remark`         VARCHAR(512)         DEFAULT NULL       COMMENT '备注',
  `create_by`      VARCHAR(64)          DEFAULT NULL       COMMENT '创建人id(跟进人)',
  `create_dept_id` VARCHAR(64) NOT NULL DEFAULT ''         COMMENT '创建人部门ID',
  `create_time`    DATETIME    NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '跟进时间',
  `update_by`      VARCHAR(64)          DEFAULT NULL       COMMENT '更新人id',
  `update_time`    DATETIME    NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `del_flag`       SMALLINT    NOT NULL DEFAULT 0          COMMENT '删除标记',
  PRIMARY KEY (`id`),
  KEY `idx_customer_id` (`customer_id`),
  KEY `idx_create_time` (`create_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CRM-客户跟进记录';

crm_customer_pool(公海池操作记录)

CREATE TABLE `crm_customer_pool` (
  `id`              VARCHAR(64)  NOT NULL                  COMMENT '主键ID',
  `customer_id`     VARCHAR(64)  NOT NULL                  COMMENT '客户ID',
  `customer_name`   VARCHAR(200)          DEFAULT NULL     COMMENT '客户名称(冗余)',
  `operation_type`  VARCHAR(20)  NOT NULL                  COMMENT '操作类型 into-进入公海 claim-领取 assign-分配 recycle-回收',
  `from_user_id`    VARCHAR(64)           DEFAULT NULL     COMMENT '原负责人ID',
  `from_user_name`  VARCHAR(50)           DEFAULT NULL     COMMENT '原负责人姓名(冗余)',
  `to_user_id`      VARCHAR(64)           DEFAULT NULL     COMMENT '新负责人ID',
  `to_user_name`    VARCHAR(50)           DEFAULT NULL     COMMENT '新负责人姓名(冗余)',
  `reason`          VARCHAR(500)          DEFAULT NULL     COMMENT '操作原因',
  -- 公共字段
  `tenant_no`      VARCHAR(64) NOT NULL DEFAULT 'zkxw'     COMMENT '租户编号',
  `order_num`      INT                  DEFAULT NULL       COMMENT '排序号',
  `remark`         VARCHAR(512)         DEFAULT NULL       COMMENT '备注',
  `create_by`      VARCHAR(64)          DEFAULT NULL       COMMENT '创建人id',
  `create_dept_id` VARCHAR(64) NOT NULL DEFAULT ''         COMMENT '创建人部门ID',
  `create_time`    DATETIME    NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '操作时间',
  `update_by`      VARCHAR(64)          DEFAULT NULL       COMMENT '更新人id',
  `update_time`    DATETIME    NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `del_flag`       SMALLINT    NOT NULL DEFAULT 0          COMMENT '删除标记',
  PRIMARY KEY (`id`),
  KEY `idx_customer_id` (`customer_id`),
  KEY `idx_operation_type` (`operation_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CRM-公海池操作记录';

crm_customer_pool_rule(公海池规则)

CREATE TABLE `crm_customer_pool_rule` (
  `id`              VARCHAR(64)  NOT NULL                  COMMENT '主键ID',
  `pool_name`       VARCHAR(100) NOT NULL                  COMMENT '规则名称',
  `rule_type`       VARCHAR(20)  NOT NULL                  COMMENT '规则类型 no_follow-未跟进 no_deal-未成交',
  `timeout_days`    INT          NOT NULL                  COMMENT '超时天数',
  `protect_days`    INT          NOT NULL DEFAULT 0        COMMENT '保护期天数',
  `status`          VARCHAR(20)  NOT NULL DEFAULT 'enable' COMMENT '状态 enable-启用 disable-禁用',
  -- 公共字段
  `tenant_no`      VARCHAR(64) NOT NULL DEFAULT 'zkxw'     COMMENT '租户编号',
  `order_num`      INT                  DEFAULT NULL       COMMENT '排序号',
  `remark`         VARCHAR(512)         DEFAULT NULL       COMMENT '备注',
  `create_by`      VARCHAR(64)          DEFAULT NULL       COMMENT '创建人id',
  `create_dept_id` VARCHAR(64) NOT NULL DEFAULT ''         COMMENT '创建人部门ID',
  `create_time`    DATETIME    NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_by`      VARCHAR(64)          DEFAULT NULL       COMMENT '更新人id',
  `update_time`    DATETIME    NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `del_flag`       SMALLINT    NOT NULL DEFAULT 0          COMMENT '删除标记',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CRM-公海池规则';

crm_customer_tag(客户标签)

CREATE TABLE `crm_customer_tag` (
  `id`            VARCHAR(64)  NOT NULL                   COMMENT '主键ID',
  `tag_name`      VARCHAR(64)  NOT NULL                   COMMENT '标签名称',
  `color`         VARCHAR(20)           DEFAULT NULL      COMMENT '标签颜色',
  -- 公共字段
  `tenant_no`      VARCHAR(64) NOT NULL DEFAULT 'zkxw'    COMMENT '租户编号',
  `order_num`      INT                  DEFAULT NULL      COMMENT '排序号',
  `remark`         VARCHAR(512)         DEFAULT NULL      COMMENT '备注',
  `create_by`      VARCHAR(64)          DEFAULT NULL      COMMENT '创建人id',
  `create_dept_id` VARCHAR(64) NOT NULL DEFAULT ''        COMMENT '创建人部门ID',
  `create_time`    DATETIME    NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_by`      VARCHAR(64)          DEFAULT NULL      COMMENT '更新人id',
  `update_time`    DATETIME    NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `del_flag`       SMALLINT    NOT NULL DEFAULT 0         COMMENT '删除标记',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CRM-客户标签';

crm_customer_tag_relation(客户-标签关联)

CREATE TABLE `crm_customer_tag_relation` (
  `id`            VARCHAR(64)  NOT NULL                   COMMENT '主键ID',
  `customer_id`   VARCHAR(64)  NOT NULL                   COMMENT '客户ID',
  `tag_id`        VARCHAR(64)  NOT NULL                   COMMENT '标签ID',
  -- 公共字段
  `tenant_no`      VARCHAR(64) NOT NULL DEFAULT 'zkxw'    COMMENT '租户编号',
  `order_num`      INT                  DEFAULT NULL      COMMENT '排序号',
  `remark`         VARCHAR(512)         DEFAULT NULL      COMMENT '备注',
  `create_by`      VARCHAR(64)          DEFAULT NULL      COMMENT '创建人id',
  `create_dept_id` VARCHAR(64) NOT NULL DEFAULT ''        COMMENT '创建人部门ID',
  `create_time`    DATETIME    NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_by`      VARCHAR(64)          DEFAULT NULL      COMMENT '更新人id',
  `update_time`    DATETIME    NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `del_flag`       SMALLINT    NOT NULL DEFAULT 0         COMMENT '删除标记',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_customer_tag` (`customer_id`, `tag_id`),
  KEY `idx_tag_id` (`tag_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CRM-客户标签关联';

crm_contact(联系人)

CREATE TABLE `crm_contact` (
  `id`              VARCHAR(64)  NOT NULL                  COMMENT '主键ID',
  `customer_id`     VARCHAR(64)  NOT NULL                  COMMENT '客户ID',
  `customer_name`   VARCHAR(200)          DEFAULT NULL     COMMENT '客户名称(冗余)',
  `contact_name`    VARCHAR(100) NOT NULL                  COMMENT '联系人姓名',
  `gender`          VARCHAR(10)           DEFAULT NULL     COMMENT '性别 male-男 female-女',
  `mobile`          VARCHAR(20)           DEFAULT NULL     COMMENT '手机号',
  `telephone`       VARCHAR(30)           DEFAULT NULL     COMMENT '固定电话',
  `email`           VARCHAR(100)          DEFAULT NULL     COMMENT '邮箱',
  `wechat`          VARCHAR(100)          DEFAULT NULL     COMMENT '微信号',
  `qq`              VARCHAR(20)           DEFAULT NULL     COMMENT 'QQ号',
  `department`      VARCHAR(100)          DEFAULT NULL     COMMENT '部门',
  `position`        VARCHAR(50)           DEFAULT NULL     COMMENT '职位',
  `role`            VARCHAR(20)           DEFAULT NULL     COMMENT '角色 decision-决策人 manager-管理者 user-使用者 other-其他',
  `birthday`        DATE                  DEFAULT NULL     COMMENT '生日',
  `address`         VARCHAR(255)          DEFAULT NULL     COMMENT '住址',
  `is_key`          TINYINT     NOT NULL DEFAULT 0         COMMENT '是否关键决策人 0否 1是',
  `is_primary`      TINYINT     NOT NULL DEFAULT 0         COMMENT '是否主要联系人 0否 1是',
  `status`          VARCHAR(20) NOT NULL DEFAULT 'active'  COMMENT '状态 active-在职 leave-离职',
  -- 公共字段
  `tenant_no`      VARCHAR(64) NOT NULL DEFAULT 'zkxw'     COMMENT '租户编号',
  `order_num`      INT                  DEFAULT NULL       COMMENT '排序号',
  `remark`         VARCHAR(512)         DEFAULT NULL       COMMENT '备注',
  `create_by`      VARCHAR(64)          DEFAULT NULL       COMMENT '创建人id',
  `create_dept_id` VARCHAR(64) NOT NULL DEFAULT ''         COMMENT '创建人部门ID',
  `create_time`    DATETIME    NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_by`      VARCHAR(64)          DEFAULT NULL       COMMENT '更新人id',
  `update_time`    DATETIME    NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `del_flag`       SMALLINT    NOT NULL DEFAULT 0          COMMENT '删除标记',
  PRIMARY KEY (`id`),
  KEY `idx_customer_id` (`customer_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CRM-联系人';

4.3 迭代 3 — 线索管理 + 商机管理

crm_clue(线索主表)

CREATE TABLE `crm_clue` (
  `id`              VARCHAR(64)  NOT NULL                  COMMENT '主键ID',
  `clue_name`       VARCHAR(100) NOT NULL                  COMMENT '线索姓名',
  `mobile`          VARCHAR(20)  NOT NULL                  COMMENT '手机号',
  `company`         VARCHAR(200)          DEFAULT NULL     COMMENT '公司名称',
  `customer_type`   VARCHAR(20)           DEFAULT NULL     COMMENT '客户类型 company-企业 person-个人',
  `telephone`       VARCHAR(30)           DEFAULT NULL     COMMENT '固定电话',
  `email`           VARCHAR(100)          DEFAULT NULL     COMMENT '邮箱',
  `title`           VARCHAR(10)           DEFAULT NULL     COMMENT '称呼 先生/女士/其他',
  `position`        VARCHAR(50)           DEFAULT NULL     COMMENT '职位',
  `source`          VARCHAR(20)  NOT NULL                  COMMENT '线索来源',
  `level`           VARCHAR(10)  NOT NULL DEFAULT 'unrated' COMMENT '线索等级 A/B/C/unrated',
  `industry`        VARCHAR(50)           DEFAULT NULL     COMMENT '所属行业',
  `park_area`       VARCHAR(100)          DEFAULT NULL     COMMENT '所在园区',
  `province`        VARCHAR(50)           DEFAULT NULL     COMMENT '省',
  `city`            VARCHAR(50)           DEFAULT NULL     COMMENT '市',
  `district`        VARCHAR(50)           DEFAULT NULL     COMMENT '区',
  `address`         VARCHAR(255)          DEFAULT NULL     COMMENT '详细地址',
  `website`         VARCHAR(500)          DEFAULT NULL     COMMENT '客户网站',
  `intent_products` VARCHAR(500)          DEFAULT NULL     COMMENT '意向产品(逗号分隔)',
  `expect_time`     DATE                  DEFAULT NULL     COMMENT '预计购买时间',
  `budget`          VARCHAR(20)           DEFAULT NULL     COMMENT '预算范围',
  `requirement`     TEXT                  DEFAULT NULL     COMMENT '需求描述',
  `status`          VARCHAR(20)  NOT NULL DEFAULT 'new'    COMMENT '线索状态 new-新线索 follow-跟进中 invalid-无效 converted-已转化',
  `owner_user_id`   VARCHAR(64)           DEFAULT NULL     COMMENT '负责人ID',
  `owner_user_name` VARCHAR(50)           DEFAULT NULL     COMMENT '负责人姓名(冗余)',
  `last_time`       DATETIME              DEFAULT NULL     COMMENT '最后跟进时间',
  `next_time`       DATETIME              DEFAULT NULL     COMMENT '下次联系时间',
  `follow_count`    INT          NOT NULL DEFAULT 0        COMMENT '跟进次数',
  `is_converted`    TINYINT     NOT NULL DEFAULT 0         COMMENT '是否已转化 0否 1是',
  `converted_time`  DATETIME              DEFAULT NULL     COMMENT '转化时间',
  `customer_id`     VARCHAR(64)           DEFAULT NULL     COMMENT '转化的客户ID',
  `converted_by`    VARCHAR(64)           DEFAULT NULL     COMMENT '转化操作人',
  `assign_time`     DATETIME              DEFAULT NULL     COMMENT '分配时间',
  `assign_by`       VARCHAR(64)           DEFAULT NULL     COMMENT '分配人',
  -- 公共字段
  `tenant_no`      VARCHAR(64) NOT NULL DEFAULT 'zkxw'     COMMENT '租户编号',
  `order_num`      INT                  DEFAULT NULL       COMMENT '排序号',
  `remark`         VARCHAR(512)         DEFAULT NULL       COMMENT '备注',
  `create_by`      VARCHAR(64)          DEFAULT NULL       COMMENT '创建人id',
  `create_dept_id` VARCHAR(64) NOT NULL DEFAULT ''         COMMENT '创建人部门ID',
  `create_time`    DATETIME    NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_by`      VARCHAR(64)          DEFAULT NULL       COMMENT '更新人id',
  `update_time`    DATETIME    NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `del_flag`       SMALLINT    NOT NULL DEFAULT 0          COMMENT '删除标记',
  PRIMARY KEY (`id`),
  KEY `idx_mobile` (`mobile`),
  KEY `idx_owner` (`owner_user_id`),
  KEY `idx_status` (`status`),
  KEY `idx_level` (`level`),
  KEY `idx_source` (`source`),
  KEY `idx_customer` (`customer_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CRM-线索主表';

crm_clue_follow(线索跟进记录)

结构与 crm_customer_follow 类似,关联 clue_id 而非 customer_id。省略重复 SQL,实现时参照 crm_customer_follow 创建。

crm_opportunity(商机主表)

CREATE TABLE `crm_opportunity` (
  `id`                VARCHAR(64)  NOT NULL                COMMENT '主键ID',
  `opportunity_name`  VARCHAR(200) NOT NULL                COMMENT '商机名称',
  `customer_id`       VARCHAR(64)  NOT NULL                COMMENT '客户ID',
  `customer_name`     VARCHAR(200)          DEFAULT NULL   COMMENT '客户名称(冗余)',
  `contact_id`        VARCHAR(64)           DEFAULT NULL   COMMENT '联系人ID',
  `contact_name`      VARCHAR(100)          DEFAULT NULL   COMMENT '联系人姓名(冗余)',
  `amount`            DECIMAL(15,2)         DEFAULT 0.00   COMMENT '预计金额',
  `stage`             VARCHAR(20)  NOT NULL DEFAULT 'initial' COMMENT '商机阶段 initial-初步接洽/qualify-需求确认/proposal-方案报价/negotiation-商务谈判/won-赢单/lost-输单',
  `probability`       INT          NOT NULL DEFAULT 0      COMMENT '成交概率(%)',
  `expected_date`     DATE                  DEFAULT NULL   COMMENT '预计成交日期',
  `source`            VARCHAR(20)           DEFAULT NULL   COMMENT '商机来源',
  `status`            VARCHAR(20)  NOT NULL DEFAULT 'active' COMMENT '状态 active-进行中 won-已赢 lost-已输',
  `owner_user_id`     VARCHAR(64)           DEFAULT NULL   COMMENT '负责人ID',
  `owner_user_name`   VARCHAR(50)           DEFAULT NULL   COMMENT '负责人姓名(冗余)',
  `last_time`         DATETIME              DEFAULT NULL   COMMENT '最后跟进时间',
  `next_time`         DATETIME              DEFAULT NULL   COMMENT '下次联系时间',
  `follow_count`      INT          NOT NULL DEFAULT 0     COMMENT '跟进次数',
  `clue_id`           VARCHAR(64)           DEFAULT NULL   COMMENT '关联线索ID',
  `lose_reason`       VARCHAR(500)          DEFAULT NULL   COMMENT '输单原因',
  -- 公共字段
  `tenant_no`      VARCHAR(64) NOT NULL DEFAULT 'zkxw'     COMMENT '租户编号',
  `order_num`      INT                  DEFAULT NULL       COMMENT '排序号',
  `remark`         VARCHAR(512)         DEFAULT NULL       COMMENT '备注',
  `create_by`      VARCHAR(64)          DEFAULT NULL       COMMENT '创建人id',
  `create_dept_id` VARCHAR(64) NOT NULL DEFAULT ''         COMMENT '创建人部门ID',
  `create_time`    DATETIME    NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_by`      VARCHAR(64)          DEFAULT NULL       COMMENT '更新人id',
  `update_time`    DATETIME    NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `del_flag`       SMALLINT    NOT NULL DEFAULT 0          COMMENT '删除标记',
  PRIMARY KEY (`id`),
  KEY `idx_customer_id` (`customer_id`),
  KEY `idx_owner` (`owner_user_id`),
  KEY `idx_stage` (`stage`),
  KEY `idx_status` (`status`),
  KEY `idx_clue` (`clue_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CRM-商机主表';

crm_opportunity_follow / crm_opportunity_product / crm_opportunity_stage_log

结构与 crm_customer_follow 类似,分别关联 opportunity_id。实现时参照创建。


4.4 迭代 4 — 报价管理 + 合同管理

crm_quote(报价单)

CREATE TABLE `crm_quote` (
  `id`                VARCHAR(64)  NOT NULL                COMMENT '主键ID',
  `quote_no`          VARCHAR(50)  NOT NULL                COMMENT '报价单号',
  `quote_name`        VARCHAR(200) NOT NULL                COMMENT '报价名称',
  `customer_id`       VARCHAR(64)  NOT NULL                COMMENT '客户ID',
  `customer_name`     VARCHAR(200)          DEFAULT NULL   COMMENT '客户名称(冗余)',
  `opportunity_id`    VARCHAR(64)           DEFAULT NULL   COMMENT '商机ID',
  `contact_id`        VARCHAR(64)           DEFAULT NULL   COMMENT '联系人ID',
  `contact_name`      VARCHAR(100)          DEFAULT NULL   COMMENT '联系人姓名(冗余)',
  `amount`            DECIMAL(15,2) NOT NULL DEFAULT 0.00  COMMENT '报价金额',
  `discount_amount`   DECIMAL(15,2)          DEFAULT 0.00  COMMENT '优惠金额',
  `final_amount`      DECIMAL(15,2) NOT NULL DEFAULT 0.00  COMMENT '最终金额',
  `status`            VARCHAR(20)  NOT NULL DEFAULT 'draft' COMMENT '状态 draft-草稿 pending-待审批 approved-已通过 rejected-已驳回',
  `valid_until`       DATE                  DEFAULT NULL   COMMENT '报价有效期',
  `wf_instance_id`    VARCHAR(64)           DEFAULT NULL   COMMENT '工作流实例ID',
  `owner_user_id`     VARCHAR(64)           DEFAULT NULL   COMMENT '负责人ID',
  `owner_user_name`   VARCHAR(50)           DEFAULT NULL   COMMENT '负责人姓名(冗余)',
  `contract_id`       VARCHAR(64)           DEFAULT NULL   COMMENT '转化的合同ID',
  -- 公共字段
  `tenant_no`      VARCHAR(64) NOT NULL DEFAULT 'zkxw'     COMMENT '租户编号',
  `order_num`      INT                  DEFAULT NULL       COMMENT '排序号',
  `remark`         VARCHAR(512)         DEFAULT NULL       COMMENT '备注',
  `create_by`      VARCHAR(64)          DEFAULT NULL       COMMENT '创建人id',
  `create_dept_id` VARCHAR(64) NOT NULL DEFAULT ''         COMMENT '创建人部门ID',
  `create_time`    DATETIME    NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_by`      VARCHAR(64)          DEFAULT NULL       COMMENT '更新人id',
  `update_time`    DATETIME    NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `del_flag`       SMALLINT    NOT NULL DEFAULT 0          COMMENT '删除标记',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_quote_no` (`quote_no`, `del_flag`),
  KEY `idx_customer_id` (`customer_id`),
  KEY `idx_opportunity_id` (`opportunity_id`),
  KEY `idx_status` (`status`),
  KEY `idx_owner` (`owner_user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CRM-报价单';

crm_quote_product / crm_quote_approval / crm_quote_share_log

参照 CRM 原始表结构,外键类型改为 VARCHAR(64)。实现时参照创建。

crm_contract(合同主表)

CREATE TABLE `crm_contract` (
  `id`                    VARCHAR(64)  NOT NULL              COMMENT '主键ID',
  `contract_no`           VARCHAR(50)  NOT NULL              COMMENT '合同编号',
  `contract_name`         VARCHAR(200) NOT NULL              COMMENT '合同名称',
  `customer_id`           VARCHAR(64)  NOT NULL              COMMENT '客户ID',
  `customer_name`         VARCHAR(200)          DEFAULT NULL COMMENT '客户名称(冗余)',
  `opportunity_id`        VARCHAR(64)           DEFAULT NULL COMMENT '商机ID',
  `quote_id`              VARCHAR(64)           DEFAULT NULL COMMENT '报价单ID',
  `parent_contract_id`    VARCHAR(64)           DEFAULT NULL COMMENT '原合同ID(续签)',
  `renewal_count`         INT          NOT NULL DEFAULT 0    COMMENT '续签次数',
  `template_id`           VARCHAR(64)           DEFAULT NULL COMMENT '合同模板ID',
  `contract_template`     VARCHAR(50)  NOT NULL DEFAULT 'shanxia' COMMENT '合同模版 shanxia-山峡 customer-客户',
  `contact_id`            VARCHAR(64)           DEFAULT NULL COMMENT '联系人ID',
  `contact_name`          VARCHAR(50)           DEFAULT NULL COMMENT '联系人姓名(冗余)',
  `contact_mobile`        VARCHAR(20)           DEFAULT NULL COMMENT '联系人手机(冗余)',
  `contract_type`         VARCHAR(20)  NOT NULL DEFAULT 'sale' COMMENT '合同类型 sale-销售 service-服务 lease-租赁 other-其他',
  `contract_nature`       VARCHAR(20)  NOT NULL DEFAULT 'new' COMMENT '合同性质 new-新签 renewal-续签 change-变更',
  `amount`                DECIMAL(15,2) NOT NULL DEFAULT 0.00 COMMENT '合同金额',
  `currency`              VARCHAR(10)  NOT NULL DEFAULT 'CNY' COMMENT '币种',
  `tax_rate`              DECIMAL(5,2)          DEFAULT 6.00 COMMENT '税率(%)',
  `amount_with_tax`       DECIMAL(15,2)         DEFAULT 0.00 COMMENT '含税金额',
  `sign_date`             DATE                  DEFAULT NULL COMMENT '签订日期',
  `actual_sign_date`      DATE                  DEFAULT NULL COMMENT '实际签订日期',
  `start_date`            DATE                  DEFAULT NULL COMMENT '开始日期',
  `end_date`              DATE                  DEFAULT NULL COMMENT '结束日期',
  `contract_period`       INT                   DEFAULT NULL COMMENT '合同期限(月)',
  `status`                VARCHAR(20)  NOT NULL DEFAULT 'draft' COMMENT '合同状态 draft-草稿 approving-审批中 approved-已审批 executing-执行中 finished-已完成 invalid-已作废',
  `performance_status`    VARCHAR(20)  NOT NULL DEFAULT 'normal' COMMENT '履约状态 normal-正常 delayed-延期 abnormal-异常 completed-已完成',
  `performance_rate`      DECIMAL(5,2)          DEFAULT 0.00 COMMENT '履约完成度(%)',
  `approval_status`       VARCHAR(20)           DEFAULT NULL COMMENT '审批状态 pending-待审批 approved-已通过 rejected-已驳回',
  `wf_instance_id`        VARCHAR(64)           DEFAULT NULL COMMENT '工作流实例ID',
  `contract_file`         VARCHAR(500)          DEFAULT NULL COMMENT '合同文件路径',
  `attachment_files`      VARCHAR(1000)         DEFAULT NULL COMMENT '附件(逗号分隔附件ID)',
  `owner_user_id`         VARCHAR(64)  NOT NULL              COMMENT '负责人ID',
  `owner_user_name`       VARCHAR(50)           DEFAULT NULL COMMENT '负责人姓名(冗余)',
  `received_amount`       DECIMAL(15,2)         DEFAULT 0.00 COMMENT '已回款金额',
  `unreceived_amount`     DECIMAL(15,2)         DEFAULT 0.00 COMMENT '未回款金额',
  `invoice_amount`        DECIMAL(15,2)         DEFAULT 0.00 COMMENT '已开票金额',
  `uninvoice_amount`      DECIMAL(15,2)         DEFAULT 0.00 COMMENT '未开票金额',
  -- 甲方信息
  `party_a`               VARCHAR(200)          DEFAULT NULL COMMENT '甲方(客户方)',
  `party_a_address`       VARCHAR(255)          DEFAULT NULL COMMENT '甲方地址',
  `party_a_contact`       VARCHAR(50)           DEFAULT NULL COMMENT '甲方联系人',
  `party_a_mobile`        VARCHAR(20)           DEFAULT NULL COMMENT '甲方联系电话',
  `party_a_legal_person`  VARCHAR(50)           DEFAULT NULL COMMENT '甲方法定代表人',
  `party_a_bank`          VARCHAR(100)          DEFAULT NULL COMMENT '甲方开户银行',
  `party_a_account`       VARCHAR(50)           DEFAULT NULL COMMENT '甲方银行账号',
  -- 乙方信息
  `party_b`               VARCHAR(200)          DEFAULT NULL COMMENT '乙方(我方)',
  `party_b_address`       VARCHAR(255)          DEFAULT NULL COMMENT '乙方地址',
  `party_b_contact`       VARCHAR(50)           DEFAULT NULL COMMENT '乙方联系人',
  `party_b_mobile`        VARCHAR(20)           DEFAULT NULL COMMENT '乙方联系电话',
  `party_b_legal_person`  VARCHAR(100)          DEFAULT NULL COMMENT '乙方法定代表人',
  `party_b_bank`          VARCHAR(200)          DEFAULT NULL COMMENT '乙方开户银行',
  `party_b_account`       VARCHAR(100)          DEFAULT NULL COMMENT '乙方银行账号',
  -- 条款
  `payment_terms`         TEXT                  DEFAULT NULL COMMENT '付款条款',
  `delivery_terms`        TEXT                  DEFAULT NULL COMMENT '交付条款',
  `contract_terms`        TEXT                  DEFAULT NULL COMMENT '合同条款',
  -- 其他
  `supplier_id`           VARCHAR(64)           DEFAULT NULL COMMENT '供方主体ID',
  `settlement_method`     VARCHAR(50)           DEFAULT NULL COMMENT '结算方式 arrive_payment-货到付款 advance_payment-款到发货',
  `invalid_reason`        VARCHAR(500)          DEFAULT NULL COMMENT '作废原因',
  `invalid_time`          DATETIME              DEFAULT NULL COMMENT '作废时间',
  `template_content`      LONGTEXT              DEFAULT NULL COMMENT '合同模板内容(富文本HTML)',
  `settlement_clause_drafts` LONGTEXT           DEFAULT NULL COMMENT '结算方式草稿(JSON)',
  -- 公共字段
  `tenant_no`      VARCHAR(64) NOT NULL DEFAULT 'zkxw'     COMMENT '租户编号',
  `order_num`      INT                  DEFAULT NULL       COMMENT '排序号',
  `remark`         VARCHAR(512)         DEFAULT NULL       COMMENT '备注',
  `create_by`      VARCHAR(64)          DEFAULT NULL       COMMENT '创建人id',
  `create_dept_id` VARCHAR(64) NOT NULL DEFAULT ''         COMMENT '创建人部门ID',
  `create_time`    DATETIME    NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_by`      VARCHAR(64)          DEFAULT NULL       COMMENT '更新人id',
  `update_time`    DATETIME    NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `del_flag`       SMALLINT    NOT NULL DEFAULT 0          COMMENT '删除标记',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_contract_no` (`contract_no`, `del_flag`),
  KEY `idx_customer_id` (`customer_id`),
  KEY `idx_opportunity_id` (`opportunity_id`),
  KEY `idx_quote_id` (`quote_id`),
  KEY `idx_owner` (`owner_user_id`),
  KEY `idx_status` (`status`),
  KEY `idx_approval_status` (`approval_status`),
  KEY `idx_sign_date` (`sign_date`),
  KEY `idx_end_date` (`end_date`),
  KEY `idx_parent_contract_id` (`parent_contract_id`),
  KEY `idx_supplier_id` (`supplier_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CRM-合同主表';

crm_contract_product / crm_contract_product_price_tier / crm_contract_approval / crm_contract_change / crm_contract_template

参照 CRM 原始表结构,外键类型改为 VARCHAR(64),公共字段统一。实现时参照创建。


5. 后端架构设计

5.1 目录结构

backend/
├── app/
│   ├── models/
│   │   └── crm_models.py          — CRM 所有 SQLAlchemy 模型(~20 个类)
│   ├── schemas/
│   │   └── crm/
│   │       ├── product.py         — 产品/分类 Pydantic schemas
│   │       ├── customer.py        — 客户/联系人 schemas
│   │       ├── clue.py            — 线索 schemas
│   │       ├── opportunity.py     — 商机 schemas
│   │       ├── quote.py           — 报价 schemas
│   │       └── contract.py        — 合同 schemas
│   ├── crud/
│   │   └── crm/
│   │       ├── product.py         — 产品 CRUD
│   │       ├── customer.py        — 客户 CRUD
│   │       ├── clue.py            — 线索 CRUD
│   │       ├── opportunity.py     — 商机 CRUD
│   │       ├── quote.py           — 报价 CRUD
│   │       └── contract.py        — 合同 CRUD
│   ├── api/
│   │   └── crm.py                 — CRM 所有 API 路由(注册到 main.py)
│   └── services/
│       └── crm/
│           ├── customer_pool.py   — 公海池逻辑(定时回收等)
│           └── biz_no_generator.py — 业务编号生成(客户编号、合同编号等)

5.2 API 路由设计

/api/crm/                           — CRM 模块统一前缀

# 产品分类
GET    /api/crm/product-categories          — 列表(树形)
POST   /api/crm/product-categories          — 新增
PUT    /api/crm/product-categories/{id}     — 修改
DELETE /api/crm/product-categories/{id}     — 删除

# 产品管理
GET    /api/crm/products                    — 列表(分页)
GET    /api/crm/products/{id}               — 详情
POST   /api/crm/products                    — 新增
PUT    /api/crm/products/{id}               — 修改
DELETE /api/crm/products/{id}               — 删除
GET    /api/crm/products/select-options     — 下拉选项

# 客户管理
GET    /api/crm/customers                   — 列表(分页)
GET    /api/crm/customers/{id}              — 详情
POST   /api/crm/customers                   — 新增
PUT    /api/crm/customers/{id}              — 修改
DELETE /api/crm/customers/{id}              — 删除
POST   /api/crm/customers/{id}/follow       — 添加跟进
GET    /api/crm/customers/{id}/follows      — 跟进列表

# 公海池
GET    /api/crm/customer-pool               — 公海池列表
POST   /api/crm/customer-pool/{id}/claim    — 领取
POST   /api/crm/customer-pool/assign        — 分配
GET    /api/crm/customer-pool/rules         — 规则列表
PUT    /api/crm/customer-pool/rules/{id}    — 修改规则

# 联系人
GET    /api/crm/contacts                    — 列表
POST   /api/crm/contacts                    — 新增
PUT    /api/crm/contacts/{id}               — 修改
DELETE /api/crm/contacts/{id}               — 删除

# 线索管理
GET    /api/crm/clues                       — 列表(分页)
GET    /api/crm/clues/{id}                  — 详情
POST   /api/crm/clues                       — 新增
PUT    /api/crm/clues/{id}                  — 修改
DELETE /api/crm/clues/{id}                  — 删除
POST   /api/crm/clues/{id}/follow           — 添加跟进
POST   /api/crm/clues/{id}/convert          — 转化为客户
POST   /api/crm/clues/{id}/invalid          — 标记无效
POST   /api/crm/clues/{id}/assign           — 分配

# 商机管理
GET    /api/crm/opportunities               — 列表(分页)
GET    /api/crm/opportunities/{id}          — 详情
POST   /api/crm/opportunities               — 新增
PUT    /api/crm/opportunities/{id}          — 修改
DELETE /api/crm/opportunities/{id}          — 删除
POST   /api/crm/opportunities/{id}/follow   — 添加跟进
POST   /api/crm/opportunities/{id}/stage    — 推进阶段(赢单/输单)

# 报价管理
GET    /api/crm/quotes                      — 列表(分页)
GET    /api/crm/quotes/{id}                 — 详情
POST   /api/crm/quotes                      — 新增
PUT    /api/crm/quotes/{id}                 — 修改
DELETE /api/crm/quotes/{id}                 — 删除
POST   /api/crm/quotes/{id}/submit          — 提交审批
POST   /api/crm/quotes/{id}/to-contract     — 转合同

# 合同管理
GET    /api/crm/contracts                   — 列表(分页)
GET    /api/crm/contracts/{id}              — 详情
POST   /api/crm/contracts                   — 新增
PUT    /api/crm/contracts/{id}              — 修改
DELETE /api/crm/contracts/{id}              — 删除
POST   /api/crm/contracts/{id}/submit       — 提交审批
POST   /api/crm/contracts/{id}/invalid      — 作废
POST   /api/crm/contracts/{id}/change       — 变更
GET    /api/crm/contracts/templates         — 模板列表
GET    /api/crm/contracts/templates/{id}    — 模板详情

5.3 编码约定

  • CRUD:继承 CRUDBase,遵循驼峰/蛇形自动映射
  • 模型:所有模型继承 Base,公共字段与一体化一致
  • 路由注册:CRM 路由注册在 app/api/__init__.py 和 app/main.py
  • 权限守卫:使用 require_admin_or_super_admin + require_menu_code("crm:xxx:list")
  • 租户隔离:所有查询过滤 tenant_no == current_user.tenant_no
  • 数据权限:使用 apply_data_scope() 叠加角色数据权限
  • 附件:通过 sys_oss(统一附件表,基于 CRM sys_oss 结构),biz_type 命名规则 crm_{entity}
  • 工作流:审批通过 wf_instance_id 关联 wf_process_instance

6. 前端架构设计

6.1 目录结构

web-admin/src/
├── api/
│   └── crm/
│       ├── product.ts             — 产品/分类 API
│       ├── customer.ts            — 客户 API
│       ├── contact.ts             — 联系人 API
│       ├── clue.ts                — 线索 API
│       ├── opportunity.ts         — 商机 API
│       ├── quote.ts               — 报价 API
│       └── contract.ts            — 合同 API
├── views/
│   └── crm/
│       ├── product/
│       │   ├── index.vue          — 产品列表(参考 product/index.vue 模板)
│       │   ├── ProductFormDialog.vue
│       │   ├── ProductViewDialog.vue
│       │   └── PriceDialog.vue
│       ├── product-category/
│       │   └── index.vue          — 产品分类(树形,参考 category/index.vue)
│       ├── customer/
│       │   ├── index.vue          — 客户列表
│       │   ├── CustomerFormDialog.vue
│       │   ├── CustomerViewDialog.vue
│       │   ├── FollowDialog.vue
│       │   └── PoolPanel.vue
│       ├── contact/
│       │   ├── index.vue
│       │   └── ContactFormDialog.vue
│       ├── clue/
│       │   ├── index.vue
│       │   ├── ClueFormDialog.vue
│       │   ├── ConvertDialog.vue
│       │   └── FollowDialog.vue
│       ├── opportunity/
│       │   ├── index.vue
│       │   ├── OpportunityFormDialog.vue
│       │   ├── OpportunityViewDialog.vue
│       │   └── StageDialog.vue
│       ├── quote/
│       │   ├── index.vue
│       │   ├── QuoteFormDialog.vue
│       │   └── QuoteViewDialog.vue
│       └── contract/
│           ├── index.vue
│           ├── ContractFormDialog.vue
│           ├── ContractViewDialog.vue
│           └── TemplateDialog.vue

6.2 UI 规范

  • 色彩:Fresh Mint (--primary #10b981),不使用 CRM 的色板
  • 表单弹窗:label-position="top",.dialog-form-layout + .form-grid-2
  • 表格:el-table-column 用 min-width(不用 width),操作列 fixed="right" min-width ≥ 260px
  • 状态/类型字段:使用 <el-tag> + 语义色
  • 按钮图标:所有 el-button 带 <el-icon>
  • 附件上传:使用 sys_oss 统一附件表(基于 CRM sys_oss 接口模式),卡片化布局
  • 模板页参考:
    • 树形:category/index.vue
    • 标准列表:unit/index.vue
    • 复杂列表:order/index.vue
    • 产品+查看弹窗:product/index.vue

6.3 菜单注册

在 sqxp.ts 和 menu.py 中新增「CRM 管理」一级菜单:

CRM 管理
├── 产品分类
├── 产品管理
├── 客户管理
│   (公海池作为客户列表的 tab 或筛选条件)
├── 联系人
├── 线索管理
├── 商机管理
├── 报价管理
└── 合同管理

7. 数据迁移注意事项

本节记录数据迁移时需要特别注意的映射关系和风险点。 数据迁移方案将在后续单独编写。

7.1 主键映射

修订(2026-07-12):生产数据同步以 docs/data-migration/05-id-preservation-policy.md 为准——业务主键原样保留(bigint → 同值 VARCHAR 字符串),不再统一生成 UUID。用户外键仍经 user_mapping 转换。

CRM (bigint) 一体化 (VARCHAR) 说明
id (AUTO_INCREMENT) id (str(id)) 恒等映射;crm_id_mapping 用于审计
owner_user_id (bigint) owner_user_id (VARCHAR) 例外:映射到 sys_user.id(门户 UUID)
customer_id (bigint) customer_id (VARCHAR) str(customer_id);先迁客户再迁子表
create_by (bigint) create_by (VARCHAR) 例外:映射到 sys_user.id

7.2 租户字段

-- CRM: tenant_id (VARCHAR(20), DEFAULT '000000')
-- 一体化: tenant_no (VARCHAR(64), DEFAULT 'zkxw')
-- 迁移时: UPDATE SET tenant_no = 'zkxw' (或对应租户编号)

7.3 附件迁移

CRM 附件: sys_oss 表
  oss_id (bigint) → 主键
  url → 完整文件 URL
  file_name / original_name / file_suffix → 文件信息
  create_by (bigint) → 上传人
  service → 存储服务商(minio)

目标: sys_oss 统一附件表(与 CRM 源表同名同结构)
  id (VARCHAR) ← str(oss_id),原样保留
  tenant_no ← tenant_id 改名
  biz_type / biz_id ← 业务关联字段(需根据 CRM 中的附件关联逻辑补充)
  file_name / original_name / file_suffix / url ← 字段名完全一致,直接复制
  create_by (VARCHAR) ← create_by (bigint) 经 user_mapping
  create_dept_id (VARCHAR) ← create_dept (bigint) 经 dept_mapping(若有)
  service ← 字段完全一致,直接复制

迁移优势:
  1. 字段名完全一致(file_name/original_name/file_suffix/url/service),直接 INSERT
  2. 只需 oss_id→str(oss_id)、tenant_id→tenant_no、create_by/create_dept 的用户 UUID 映射
  3. 未来报销系统(bx_*)、地磅系统的附件同样写入此表,用 biz_type 区分
  4. 报销迁移时 bx_attachment 的数据也可映射到此表

7.4 字典数据迁移

CRM 字典来源: sys_dict_data (sx 库)
目标: sys_dict_data (shanxia2.0 库)

需迁移的字典类型:
  - crm_customer_industry (行业)
  - crm_customer_source (客户来源)
  - crm_customer_level (客户级别)
  - crm_clue_source (线索来源)
  - crm_clue_level (线索等级)
  - crm_opportunity_stage (商机阶段)
  - crm_contract_type (合同类型)
  - crm_contract_nature (合同性质)
  - crm_follow_type (跟进方式)
  - crm_budget_range (预算范围)
  - crm_payment_terms (付款条件)
  ... (实现时从 CRM 数据库中导出完整列表)

7.5 部门映射

CRM: create_dept (bigint) → CRM 的 sys_dept
一体化: create_dept_id (VARCHAR(64)) → sys_dept

需先确认:
  1. CRM 中的部门是否与一体化 sys_dept 一致
  2. 如不一致,需导入部门数据并建立映射

7.6 迁移顺序(依赖关系)

1. 字典数据 (sys_dict_data)
2. 部门数据 (sys_dept) — 如需导入
3. 用户数据 (sys_user) — 如需导入
4. 产品分类 (crm_product_category)
5. 产品 (crm_product)
6. 产品附件 (→ biz_attachment)
7. 客户标签 (crm_customer_tag)
8. 客户 (crm_customer)
9. 联系人 (crm_contact)
10. 客户附件 (→ biz_attachment)
11. 客户跟进 (crm_customer_follow)
12. 公海池记录 (crm_customer_pool)
13. 线索 (crm_clue)
14. 线索跟进 (crm_clue_follow)
15. 商机 (crm_opportunity)
16. 商机产品/跟进/阶段日志
17. 报价单 + 产品
18. 合同 + 产品 + 审批记录

8. 定时任务

8.1 公海池自动回收

在 app/tasks/ 中实现:

规则: 
  - 未跟进超过 N 天的客户 → 自动进入公海池
  - 未成交超过 N 天的客户 → 自动进入公海池
  - 领取后保护 M 天内不回收

实现:
  - 使用 APScheduler (一体化已有依赖)
  - 每日定时扫描 crm_customer + crm_customer_pool_rule
  - 符合条件的客户: status → 'pool',写入 crm_customer_pool 记录

9. 附录

A. CRM 原始表 → 新表对照清单

CRM 原始表 新表 变更说明
crm_product_category crm_product_category 主键原样保留 str(id),公共字段统一
crm_product crm_product 主键原样保留 str(id),category_id 改 VARCHAR
crm_product_price crm_product_price 主键原样保留 str(id),product_id 改 VARCHAR
crm_product_price_history crm_product_price_history 主键原样保留 str(id)
crm_product_stock_log crm_product_stock_log 主键原样保留 str(id)
crm_product_tag crm_product_tag 主键原样保留 str(id)
crm_product_tag_relation crm_product_tag_relation 主键原样保留 str(id),关联 ID 改 VARCHAR
crm_product_attachment 删除 → 复用 sys_oss biz_type='crm_product'
crm_customer crm_customer 主键原样保留 str(id),owner/create 用户外键经 mapping
crm_customer_follow crm_customer_follow 主键原样保留 str(id)
crm_customer_pool crm_customer_pool 主键原样保留 str(id)
crm_customer_pool_rule crm_customer_pool_rule 主键原样保留 str(id)
crm_customer_tag crm_customer_tag 主键原样保留 str(id)
crm_customer_tag_relation crm_customer_tag_relation 主键原样保留 str(id)
crm_contact crm_contact 主键原样保留 str(id)
crm_clue crm_clue 主键原样保留 str(id)
crm_clue_follow crm_clue_follow 主键原样保留 str(id)
crm_opportunity crm_opportunity 主键原样保留 str(id)
crm_opportunity_follow crm_opportunity_follow 主键原样保留 str(id)
crm_opportunity_product crm_opportunity_product 主键原样保留 str(id)
crm_opportunity_stage_log crm_opportunity_stage_log 主键原样保留 str(id)
crm_quote crm_quote 主键原样保留 str(id)
crm_quote_product crm_quote_product 主键原样保留 str(id)
crm_quote_approval crm_quote_approval 主键原样保留 str(id)
crm_quote_share_log crm_quote_share_log 主键原样保留 str(id)
crm_contract crm_contract 主键原样保留 str(id)
crm_contract_product crm_contract_product 主键原样保留 str(id)
crm_contract_product_price_tier crm_contract_product_price_tier 主键原样保留 str(id)
crm_contract_approval crm_contract_approval 主键原样保留 str(id)
crm_contract_change crm_contract_change 主键原样保留 str(id)
crm_contract_template crm_contract_template 主键原样保留 str(id)

B. 参考文件清单

用途 路径
CRM DDL docs/sql/sx.sql
一体化 DDL docs/sql/shanxia2.0.sql
CRM 后端 (Java) /Users/zlwu/work/00code/shanxia/crm/backend/
CRM 前端 (Vue) /Users/zlwu/work/00code/shanxia/crm/web/
一体化后端模型 backend/app/models/models.py
一体化 CRUD 基类 backend/app/crud/base.py
一体化 API 示例 backend/app/api/admin.py
前端模板页-标准列表 web-admin/src/views/system/unit/index.vue
前端模板页-复杂列表 web-admin/src/views/system/order/index.vue
前端模板页-树形 web-admin/src/views/system/category/index.vue
前端模板页-产品 web-admin/src/views/system/product/index.vue
工程规范 openspec/changes/zkxw-engineering-standards/specs/
UI 规范 docs/web-admin-ui-spec-fresh-mint.md