04-商机管理API接口.md 24 KB

商机管理模块 - API接口文档

模块: 04-商机管理
版本: v1.0
日期: 2025-10-03
关联文档:

  • 需求文档: docs/04-商机管理模块需求.md
  • 原型图: yuanxing/04-商机管理原型图.md
  • 数据库: sql/crm/04-crm_opportunity.sql

📋 目录


1. 商机管理接口

1.1 查询商机列表(分页)

接口地址: GET /crm/opportunity/list

接口描述: 分页查询商机列表,支持多条件筛选

权限标识: crm:opportunity:list

请求参数: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | pageNum | Integer | 否 | 页码,默认1 | | pageSize | Integer | 否 | 每页条数,默认10 | | opportunityName | String | 否 | 商机名称(模糊查询) | | opportunityNo | String | 否 | 商机编号(模糊查询) | | customerId | Long | 否 | 客户ID | | customerName | String | 否 | 客户名称(模糊查询) | | stage | String | 否 | 商机阶段 | | status | String | 否 | 商机状态 | | ownerUserId | Long | 否 | 负责人ID | | minAmount | BigDecimal | 否 | 最小金额 | | maxAmount | BigDecimal | 否 | 最大金额 | | source | String | 否 | 商机来源 | | expectDealDateBegin | String | 否 | 预计成交日期开始 | | expectDealDateEnd | String | 否 | 预计成交日期结束 | | beginTime | String | 否 | 创建开始时间 | | endTime | String | 否 | 创建结束时间 |

返回示例:

{
  "code": 200,
  "msg": "查询成功",
  "rows": [
    {
      "id": 1,
      "opportunityNo": "OPP20250101001",
      "opportunityName": "华为CRM系统采购项目",
      "customerId": 1,
      "customerName": "华为技术有限公司",
      "contactId": 1,
      "contactName": "张伟",
      "amount": 150000.00,
      "stage": "quote",
      "stagePercent": 60,
      "status": "following",
      "winRate": 75.00,
      "expectDealDate": "2025-03-31",
      "actualDealDate": null,
      "ownerUserId": 1,
      "ownerUserName": "张三",
      "productCount": 2,
      "lastTime": "2025-01-02 10:30:00",
      "nextTime": "2025-01-05 14:00:00",
      "followCount": 8,
      "contractId": null,
      "source": "website",
      "createTime": "2024-12-01 09:00:00",
      "remark": ""
    }
  ],
  "total": 89
}

1.2 查询商机详情

接口地址: GET /crm/opportunity/{id}

接口描述: 根据ID查询商机详细信息

权限标识: crm:opportunity:query

请求参数: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | id | Long | 是 | 商机ID |

返回示例: 同1.1列表返回的单条数据,包含完整字段


1.3 新增商机

接口地址: POST /crm/opportunity

接口描述: 新增商机信息

权限标识: crm:opportunity:add

请求体:

{
  "opportunityNo": "OPP20250101001",
  "opportunityName": "华为CRM系统采购项目",
  "customerId": 1,
  "contactId": 1,
  "amount": 150000.00,
  "stage": "initial",
  "expectDealDate": "2025-03-31",
  "winRate": 50.00,
  "ownerUserId": 1,
  "source": "website",
  "nextTime": "2025-01-05 14:00:00",
  "remark": ""
}

请求参数说明: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | opportunityNo | String | 是 | 商机编号,唯一,格式:OPP+yyyyMMdd+4位流水号 | | opportunityName | String | 是 | 商机名称,最大200字符 | | customerId | Long | 是 | 客户ID | | contactId | Long | 否 | 联系人ID | | amount | BigDecimal | 是 | 商机金额,保留2位小数 | | stage | String | 否 | 商机阶段,默认initial | | expectDealDate | String | 否 | 预计成交日期,格式yyyy-MM-dd | | winRate | BigDecimal | 否 | 赢单率,百分比,默认50.00 | | ownerUserId | Long | 否 | 负责人ID,默认当前用户 | | source | String | 否 | 商机来源 | | nextTime | String | 否 | 下次联系时间 yyyy-MM-dd HH:mm:ss | | remark | String | 否 | 备注,最大500字符 |

校验规则:

  • 商机编号必须唯一
  • 商机金额必须大于0
  • 客户ID必须存在

返回示例:

{
  "code": 200,
  "msg": "操作成功"
}

1.4 修改商机

接口地址: PUT /crm/opportunity

接口描述: 修改商机信息

权限标识: crm:opportunity:edit

请求体: 同新增接口,但需要传入id

返回示例:

{
  "code": 200,
  "msg": "操作成功"
}

1.5 删除商机

接口地址: DELETE /crm/opportunity/{ids}

接口描述: 删除商机(支持批量)

权限标识: crm:opportunity:remove

请求参数: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | ids | Long[] | 是 | 商机ID数组 |

业务规则:

  • 已赢单的商机不允许删除
  • 关联了合同的商机不允许删除
  • 删除商机时同时删除关联的产品、跟进记录、阶段日志

返回示例:

{
  "code": 200,
  "msg": "操作成功"
}

1.6 修改商机阶段

接口地址: PUT /crm/opportunity/stage

接口描述: 修改商机阶段,记录阶段日志

权限标识: crm:opportunity:edit

请求体:

{
  "id": 1,
  "stage": "quote",
  "stagePercent": 60,
  "winRate": 75.00,
  "changeReason": "客户已确认需求,准备报价",
  "remark": ""
}

请求参数说明: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | id | Long | 是 | 商机ID | | stage | String | 是 | 新阶段:initial/requirement/solution/quote/negotiate/contract/won | | stagePercent | Integer | 是 | 阶段进度:10/20/40/60/80/90/100 | | winRate | BigDecimal | 否 | 赢单率 | | changeReason | String | 否 | 变更原因 | | remark | String | 否 | 备注 |

业务规则:

  • 自动记录阶段变更日志
  • 自动判断是前进还是后退
  • 赢单后状态自动变为won

返回示例:

{
  "code": 200,
  "msg": "操作成功"
}

1.7 赢单

接口地址: PUT /crm/opportunity/win

接口描述: 将商机标记为赢单

权限标识: crm:opportunity:edit

请求体:

{
  "id": 1,
  "actualDealDate": "2025-01-10",
  "actualAmount": 148000.00,
  "remark": "成功签约"
}

请求参数说明: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | id | Long | 是 | 商机ID | | actualDealDate | String | 是 | 实际成交日期 yyyy-MM-dd | | actualAmount | BigDecimal | 否 | 实际成交金额(如果与预估不同) | | remark | String | 否 | 备注说明 |

业务规则:

  • 商机状态变更为won
  • 阶段自动设置为won
  • 进度设置为100%
  • 可选择是否自动创建合同

返回示例:

{
  "code": 200,
  "msg": "操作成功"
}

1.8 输单

接口地址: PUT /crm/opportunity/lost

接口描述: 将商机标记为输单

权限标识: crm:opportunity:edit

请求体:

{
  "id": 1,
  "lostReason": "价格因素",
  "remark": "客户选择了竞争对手的产品"
}

请求参数说明: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | id | Long | 是 | 商机ID | | lostReason | String | 是 | 输单原因,最大500字符 | | remark | String | 否 | 备注说明 |

业务规则:

  • 商机状态变更为lost
  • 记录输单原因
  • 赢单率设置为0

返回示例:

{
  "code": 200,
  "msg": "操作成功"
}

1.9 批量分配商机

接口地址: PUT /crm/opportunity/assign

接口描述: 批量分配商机给指定负责人

权限标识: crm:opportunity:assign

请求体:

{
  "ids": [1, 2, 3],
  "ownerUserId": 5,
  "remark": "分配原因"
}

返回示例:

{
  "code": 200,
  "msg": "操作成功"
}

1.10 导出商机

接口地址: POST /crm/opportunity/export

接口描述: 导出商机数据到Excel

权限标识: crm:opportunity:export

请求体: 查询参数同1.1列表查询接口

返回: Excel文件流


2. 商机产品接口

2.1 查询商机产品列表

接口地址: GET /crm/opportunity/product/list

接口描述: 查询指定商机的产品列表

权限标识: crm:opportunity:query

请求参数: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | opportunityId | Long | 是 | 商机ID |

返回示例:

{
  "code": 200,
  "msg": "查询成功",
  "data": [
    {
      "id": 1,
      "opportunityId": 1,
      "productId": 1,
      "productName": "CRM系统标准版",
      "productNo": "PRD20250101001",
      "categoryId": 11,
      "categoryName": "CRM系统",
      "model": "V5.4.0",
      "unit": "套",
      "quantity": 1,
      "price": 12800.00,
      "discount": 10.00,
      "subtotal": 11520.00,
      "sort": 1,
      "remark": ""
    }
  ]
}

2.2 添加商机产品

接口地址: POST /crm/opportunity/product

接口描述: 向商机添加产品

权限标识: crm:opportunity:edit

请求体:

{
  "opportunityId": 1,
  "productId": 1,
  "quantity": 1,
  "price": 12800.00,
  "discount": 10.00,
  "remark": ""
}

请求参数说明: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | opportunityId | Long | 是 | 商机ID | | productId | Long | 是 | 产品ID | | quantity | Integer | 是 | 数量,必须大于0 | | price | BigDecimal | 是 | 单价,保留2位小数 | | discount | BigDecimal | 否 | 折扣百分比,默认0 | | remark | String | 否 | 备注 |

业务规则:

  • 自动计算小计金额:quantity * price * (1 - discount/100)
  • 添加产品后自动更新商机的productCount
  • 自动更新商机总金额

返回示例:

{
  "code": 200,
  "msg": "操作成功"
}

2.3 修改商机产品

接口地址: PUT /crm/opportunity/product

接口描述: 修改商机产品信息

权限标识: crm:opportunity:edit

请求体: 同添加接口,但需要传入id

返回示例:

{
  "code": 200,
  "msg": "操作成功"
}

2.4 删除商机产品

接口地址: DELETE /crm/opportunity/product/{ids}

接口描述: 删除商机产品(支持批量)

权限标识: crm:opportunity:edit

请求参数: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | ids | Long[] | 是 | 商机产品ID数组 |

业务规则:

  • 删除后自动更新商机的productCount
  • 自动更新商机总金额

返回示例:

{
  "code": 200,
  "msg": "操作成功"
}

3. 商机跟进记录接口

3.1 查询跟进记录列表

接口地址: GET /crm/opportunity/follow/list

接口描述: 查询指定商机的跟进记录列表

权限标识: crm:opportunity:query

请求参数: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | opportunityId | Long | 是 | 商机ID | | pageNum | Integer | 否 | 页码,默认1 | | pageSize | Integer | 否 | 每页条数,默认10 |

返回示例:

{
  "code": 200,
  "msg": "查询成功",
  "rows": [
    {
      "id": 1,
      "opportunityId": 1,
      "followType": "phone",
      "followContent": "电话沟通了客户需求,客户对CRM系统很感兴趣",
      "stage": "requirement",
      "stagePercent": 20,
      "nextTime": "2025-01-08 14:00:00",
      "nextContent": "下次需要进行产品演示",
      "attachments": "/upload/2025/01/file1.pdf",
      "contactId": 1,
      "contactName": "张伟",
      "location": null,
      "duration": 30,
      "createBy": 1,
      "createByName": "张三",
      "createTime": "2025-01-05 10:30:00",
      "remark": ""
    }
  ],
  "total": 8
}

3.2 新增跟进记录

接口地址: POST /crm/opportunity/follow

接口描述: 新增商机跟进记录

权限标识: crm:opportunity:follow

请求体:

{
  "opportunityId": 1,
  "followType": "phone",
  "followContent": "电话沟通了客户需求",
  "stage": "requirement",
  "stagePercent": 20,
  "nextTime": "2025-01-08 14:00:00",
  "nextContent": "下次需要进行产品演示",
  "attachments": "/upload/2025/01/file1.pdf",
  "contactId": 1,
  "duration": 30,
  "remark": ""
}

请求参数说明: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | opportunityId | Long | 是 | 商机ID | | followType | String | 是 | 跟进方式:phone/wechat/email/visit/meeting/other | | followContent | String | 是 | 跟进内容,文本类型 | | stage | String | 否 | 当前商机阶段 | | stagePercent | Integer | 否 | 阶段进度百分比 | | nextTime | String | 否 | 下次联系时间 yyyy-MM-dd HH:mm:ss | | nextContent | String | 否 | 下次联系计划,最大500字符 | | attachments | String | 否 | 附件路径,多个用逗号分隔 | | contactId | Long | 否 | 联系人ID | | location | String | 否 | 跟进地点(拜访时填写) | | duration | Integer | 否 | 跟进时长(分钟) | | remark | String | 否 | 备注 |

业务规则:

  • 新增跟进记录后,自动更新商机的lastTime和followCount
  • 如果设置了nextTime,同步更新商机的nextTime

返回示例:

{
  "code": 200,
  "msg": "操作成功"
}

3.3 修改跟进记录

接口地址: PUT /crm/opportunity/follow

接口描述: 修改跟进记录信息

权限标识: crm:opportunity:follow

请求体: 同新增接口,但需要传入id

业务规则:

  • 只能修改自己创建的跟进记录

返回示例:

{
  "code": 200,
  "msg": "操作成功"
}

3.4 删除跟进记录

接口地址: DELETE /crm/opportunity/follow/{ids}

接口描述: 删除跟进记录(支持批量)

权限标识: crm:opportunity:follow

请求参数: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | ids | Long[] | 是 | 跟进记录ID数组 |

业务规则:

  • 只能删除自己创建的跟进记录
  • 删除后需要重新计算商机的followCount

返回示例:

{
  "code": 200,
  "msg": "操作成功"
}

4. 商机阶段日志接口

4.1 查询阶段变更日志

接口地址: GET /crm/opportunity/stageLog/list

接口描述: 查询商机的阶段变更历史

权限标识: crm:opportunity:query

请求参数: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | opportunityId | Long | 是 | 商机ID |

返回示例:

{
  "code": 200,
  "msg": "查询成功",
  "data": [
    {
      "id": 1,
      "opportunityId": 1,
      "fromStage": "initial",
      "fromStageName": "初步接触",
      "fromPercent": 10,
      "toStage": "requirement",
      "toStageName": "需求分析",
      "toPercent": 20,
      "changeType": "forward",
      "changeReason": "客户明确了需求",
      "changeAmount": 150000.00,
      "createBy": 1,
      "createByName": "张三",
      "createTime": "2024-12-10 14:30:00",
      "remark": ""
    }
  ]
}

5. 统计分析接口

5.1 商机统计概览

接口地址: GET /crm/opportunity/statistics/overview

接口描述: 获取商机统计概览数据

权限标识: crm:opportunity:list

请求参数: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | ownerUserId | Long | 否 | 负责人ID,不传则查询当前用户 | | beginTime | String | 否 | 开始时间 | | endTime | String | 否 | 结束时间 |

返回示例:

{
  "code": 200,
  "msg": "查询成功",
  "data": {
    "totalCount": 89,
    "followingCount": 67,
    "wonCount": 15,
    "lostCount": 7,
    "totalAmount": 5680000.00,
    "wonAmount": 1250000.00,
    "avgAmount": 63820.22,
    "winRate": 68.18,
    "avgCycle": 45.5
  }
}

5.2 商机阶段分布

接口地址: GET /crm/opportunity/statistics/stage

接口描述: 按商机阶段统计分布情况

权限标识: crm:opportunity:list

请求参数: 无

返回示例:

{
  "code": 200,
  "msg": "查询成功",
  "data": [
    {
      "stage": "initial",
      "stageName": "初步接触",
      "count": 12,
      "amount": 560000.00,
      "percent": 13.48
    },
    {
      "stage": "requirement",
      "stageName": "需求分析",
      "count": 18,
      "amount": 980000.00,
      "percent": 20.22
    }
  ]
}

5.3 商机赢单率分析

接口地址: GET /crm/opportunity/statistics/winRate

接口描述: 分析商机赢单率趋势

权限标识: crm:opportunity:list

请求参数: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | type | String | 否 | 统计类型:month/quarter/year,默认month | | beginTime | String | 否 | 开始时间 | | endTime | String | 否 | 结束时间 |

返回示例:

{
  "code": 200,
  "msg": "查询成功",
  "data": [
    {
      "period": "2025-01",
      "totalCount": 23,
      "wonCount": 15,
      "lostCount": 8,
      "winRate": 65.22,
      "wonAmount": 1250000.00
    }
  ]
}

5.4 负责人商机统计

接口地址: GET /crm/opportunity/statistics/owner

接口描述: 按负责人统计商机数量和金额

权限标识: crm:opportunity:list

请求参数: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | beginTime | String | 否 | 开始时间 | | endTime | String | 否 | 结束时间 |

返回示例:

{
  "code": 200,
  "msg": "查询成功",
  "data": [
    {
      "ownerUserId": 1,
      "ownerUserName": "张三",
      "totalCount": 28,
      "followingCount": 20,
      "wonCount": 6,
      "lostCount": 2,
      "totalAmount": 1850000.00,
      "wonAmount": 650000.00,
      "winRate": 75.00
    }
  ]
}

6. 数据模型

6.1 OpportunityBo(商机业务对象)

public class CrmOpportunityBo extends BaseEntity {
    /** 主键ID */
    @NotNull(message = "主键不能为空", groups = { EditGroup.class })
    private Long id;

    /** 商机编号 */
    @NotBlank(message = "商机编号不能为空", groups = { AddGroup.class, EditGroup.class })
    private String opportunityNo;

    /** 商机名称 */
    @NotBlank(message = "商机名称不能为空", groups = { AddGroup.class, EditGroup.class })
    private String opportunityName;

    /** 客户ID */
    @NotNull(message = "客户ID不能为空", groups = { AddGroup.class, EditGroup.class })
    private Long customerId;

    /** 联系人ID */
    private Long contactId;

    /** 商机金额 */
    @NotNull(message = "商机金额不能为空", groups = { AddGroup.class, EditGroup.class })
    @Min(value = 0, message = "商机金额必须大于0")
    private BigDecimal amount;

    /** 商机阶段 */
    private String stage;

    /** 阶段进度百分比 */
    private Integer stagePercent;

    /** 赢单率 */
    private BigDecimal winRate;

    /** 预计成交日期 */
    private String expectDealDate;

    /** 负责人ID */
    private Long ownerUserId;

    /** 商机来源 */
    private String source;

    /** 下次联系时间 */
    private LocalDateTime nextTime;

    /** 备注 */
    private String remark;
}

6.2 OpportunityVo(商机视图对象)

public class CrmOpportunityVo implements Serializable {
    /** 主键ID */
    @ExcelProperty(value = "ID")
    private Long id;

    /** 商机编号 */
    @ExcelProperty(value = "商机编号")
    private String opportunityNo;

    /** 商机名称 */
    @ExcelProperty(value = "商机名称")
    private String opportunityName;

    /** 客户ID */
    private Long customerId;

    /** 客户名称 */
    @ExcelProperty(value = "客户名称")
    private String customerName;

    /** 联系人ID */
    private Long contactId;

    /** 联系人姓名 */
    @ExcelProperty(value = "联系人")
    private String contactName;

    /** 商机金额 */
    @ExcelProperty(value = "商机金额")
    private BigDecimal amount;

    /** 商机阶段 */
    @ExcelProperty(value = "商机阶段", converter = ExcelDictConvert.class)
    @ExcelDictFormat(dictType = "crm_opportunity_stage")
    private String stage;

    /** 阶段进度百分比 */
    @ExcelProperty(value = "阶段进度")
    private Integer stagePercent;

    /** 商机状态 */
    @ExcelProperty(value = "商机状态", converter = ExcelDictConvert.class)
    @ExcelDictFormat(dictType = "crm_opportunity_status")
    private String status;

    /** 赢单率 */
    @ExcelProperty(value = "赢单率")
    private BigDecimal winRate;

    /** 预计成交日期 */
    @ExcelProperty(value = "预计成交日期")
    private String expectDealDate;

    /** 实际成交日期 */
    @ExcelProperty(value = "实际成交日期")
    private String actualDealDate;

    /** 输单原因 */
    private String lostReason;

    /** 负责人ID */
    private Long ownerUserId;

    /** 负责人姓名 */
    @ExcelProperty(value = "负责人")
    private String ownerUserName;

    /** 产品数量 */
    @ExcelProperty(value = "产品数量")
    private Integer productCount;

    /** 最后跟进时间 */
    @ExcelProperty(value = "最后跟进时间")
    private LocalDateTime lastTime;

    /** 下次联系时间 */
    @ExcelProperty(value = "下次联系时间")
    private LocalDateTime nextTime;

    /** 跟进次数 */
    @ExcelProperty(value = "跟进次数")
    private Integer followCount;

    /** 关联合同ID */
    private Long contractId;

    /** 商机来源 */
    @ExcelProperty(value = "商机来源", converter = ExcelDictConvert.class)
    @ExcelDictFormat(dictType = "crm_clue_source")
    private String source;

    /** 创建时间 */
    @ExcelProperty(value = "创建时间")
    private LocalDateTime createTime;

    /** 备注 */
    @ExcelProperty(value = "备注")
    private String remark;
}

7. 数据字典

7.1 商机阶段 (crm_opportunity_stage)

字典值 字典标签 进度 说明
initial 初步接触 10% 初次接触客户
requirement 需求分析 20% 分析客户需求
solution 方案制定 40% 制定解决方案
quote 报价 60% 提供报价
negotiate 谈判审核 80% 商务谈判
contract 合同签订 90% 签订合同
won 赢单 100% 成功赢单

7.2 商机状态 (crm_opportunity_status)

字典值 字典标签 说明
following 跟进中 正在跟进
won 赢单 成功签约
lost 输单 失去商机
invalid 无效 无效商机

8. 权限标识汇总

权限标识 说明
crm:opportunity:list 商机列表查询
crm:opportunity:query 商机详情查询
crm:opportunity:add 商机新增
crm:opportunity:edit 商机修改
crm:opportunity:remove 商机删除
crm:opportunity:export 商机导出
crm:opportunity:assign 商机分配
crm:opportunity:follow 添加跟进记录

9. 注意事项

  1. 商机编号唯一性: 同一租户下商机编号必须唯一
  2. 数据权限: 需要根据负责人字段实现数据权限控制
  3. 阶段变更记录: 修改商机阶段时自动记录变更日志
  4. 金额自动计算: 添加/修改产品时自动计算商机总金额
  5. 跟进记录关联: 新增跟进记录时自动更新商机的跟进统计信息
  6. 赢单/输单限制: 已赢单或已输单的商机不允许修改关键信息
  7. 合同关联: 赢单后可自动创建合同
  8. 产品计数: 添加/删除产品时自动维护商机的productCount
  9. 批量操作: 批量操作需要注意事务一致性
  10. 阶段推进: 阶段推进有逻辑顺序,不能跳跃太大

文档结束