大数跨境

SpringBoot3+Vue3+UniApp CRM:线索转客户、商机推进、合同回款怎么一条链落地

SpringBoot3+Vue3+UniApp CRM:线索转客户、商机推进、合同回款怎么一条链落地 企业软件源码
2026-09-14
5
导读:销售链断在「转了客户跟进丢了、合同过了回款还能超」。RuoYi Office CRM 用客户当主数据:线索转化复制跟进,商机自己推阶段,合同走 crm-contract-audit,回款累计不超过合同

SpringBoot3+Vue3+UniApp CRM:线索转客户、商机推进、合同回款怎么一条链落地

🌐 文档地址:https://ruoyioffice.com
 📦 源码1·GitHub:https://github.com/yuqing2026/ruoyi-office
 📦 源码2·GitCode:https://gitcode.com/zhouzhongyan/ruoyi-office
 📦 源码3·Gitee:https://gitee.com/yqzy1688/ruoyi-office
 💬 微信:17156169080(备注「RuoYi Office」)

两个销售同时打一家公司,跟进写在微信里,合同过了回款还能超。根因不是少一张客户表,是线索、商机、合同、回款各写各的。RuoYi Office 把客户当成主数据:转化带着跟进走,金额逐级校验,审批通过才算合同,回款加总不能超过合同额。PC 管理端和 UniApp 移动端读同一套接口、同一条客户 id,不是两套台账。

▲ 演示客户 id=17。左边 PC /crm/customer/detail/17,右边手机「客户详情」。跟进、商机、合同、回款是同一组 Tab,不是各写各的

▲ 线索转客户 → 商机推进 → 合同审批 → 回款核销。客户是主数据,审批才认合同,回款不能超


引言:CRM 难在「链断了,表还在」

缺的不是客户字段,是对象之间谁改谁、什么时候改

现场
配错之后
线索直接当客户
未验证的需求污染客户库,公海规则失效
转化后跟进还在线索上
客户页是空的,主管以为没人跟
商机赢单自动当合同
没走审批,财务不认
回款手填、不挂合同
超额没人拦,业绩对不上
客户永久归个人
躺尸占坑,别人领不走

本文只讲这一条链:线索 → 客户 → 商机 → 合同 → 回款。产品目录、漏斗统计、公海 Job 细则是旁边的能力,这里只点到和链有关的规则。

菜单:CRM → 线索 / 客户 / 商机 / 合同 / 回款。合同流程 key:crm-contract-audit。回款流程 key:crm-receivable-audit


一、产品能力:客户是主数据,别的都挂上去

销售、主管、财务看的不是五张孤立列表,而是同一个客户身上发生了什么

能力
谁用
和「只做一张客户表」差在哪
线索
市场 / 电销
未验证先放线索;转化才建客户,跟进一起复制
客户
销售
负责人唯一;成交 / 锁定影响能不能掉公海
联系人
销售
一客户多人,决策链记在客户下
商机
销售 / 主管
自定义阶段 + 赢单率;赢单自动建合同
合同
销售 / 财务
必须审批;通过后才允许建回款
回款 / 计划
财务
累计(已通过 + 审批中)≤ 合同总额
团队权限
全员
OWNER / WRITE / READ,不是靠部门猜
公海
主管
owner_user_id
 为空才是公海;锁定、成交不收

列表上三个视图:我负责的 / 我参与的 / 下属负责的。同一份数据,不用复制三套表。

详情页才是工作台。客户详情把跟进、联系人、商机、合同、回款收在一组 Tab,不要让销售在五个菜单之间来回切。PC 是宽屏 Tab,手机是顶栏滑动 Tab,字段和审批状态对得上。


二、业务怎么走:转化、推进、审批、核销

开发库可以对照这几条:线索 演示线索(id=8)已转到客户 16;客户 演示客户(id=17)下有合同 HT20240225000001、回款 HK20240225000017 全额 16016。

1. 线索:未验证,不要进客户库

/crm/clue 录的是还没确认的需求。负责人、下次跟进时间和客户一样,但没有公海。线索不进公海,避免市场名单被回收规则误伤。

转化按钮只给 OWNER。点「转化为客户」后:用线索字段建客户、写 OWNER 权限、线索打上 transformStatus=true 和 customerId。线索上的跟进记录复制一份到客户,bizType 从线索改成客户。已经转化过的再点,直接报错。

▲ /crm/clue/detail/8 基本信息。名称「演示线索」,最后跟进已写回。已转化后顶栏不再露出「转化为客户」

转化不是改个状态那么简单。客户页必须立刻能看见上次聊了什么,否则主管打开客户会以为没人跟。

2. 客户:中枢页,跟进写回最后联系时间

/crm/customer/detail/:id 顶栏是负责人、成交、距公海天数。下面 Tab 才是链:跟进、联系人、商机、合同、回款。

写一条跟进,服务会回写 contactLastTimecontactLastContentcontactNextTime,并把 followUpStatus 置真。公海的「未跟进天数」读的是这几个字段,不是看有没有打开过详情。

公海页 /crm/customer/pool 看到的是 owner_user_id 为空的客户。领取 / 分配走同一套:必须没负责人、没锁定、没成交,新负责人不能超领取上限。放入公海则清空负责人,并删掉 OWNER 权限。

锁定和成交是豁免:占着不跟也不该被收回。这是产品规则,不是 Job 写漏了。

▲ PC /crm/customer/detail/17 基本信息。负责人、成交、锁定都在这张卡上;商机 / 合同 / 回款是同一页的 Tab

▲ UniApp #/pages-crm/customer/detail/index?id=17。名称、来源、手机、负责人与 PC 一致;底部是编辑 / 删除,Tab 滑到合同、回款

3. 商机:阶段自己推,赢单不等于合同

商机挂在客户上,创建时落到状态组的第一阶段,并算产品明细总额。推进阶段走 updateBusinessStatus:已经有终态(赢单 / 输单 / 无效)就不能再改。

前端「变更商机状态」弹窗:正数 statusId 是阶段;负数取反后当 endStatus。赢单是销售过程的结论,审批通过的合同才是财务认的单。创建合同时可以带 businessId,回调里不会自动把商机改成赢单——两件事不要绑死,避免「赢了但合同被拒」或「合同过了商机还停在谈判」。

4. 合同:草稿才能提交,通过才能收钱

合同挂客户,可选挂商机。提交时必须是草稿,流程 key crm-contract-audit,状态改成审批中。只有审批中的单允许回写审批结果。通过后 onContractApproved:有合同中心就可选推送正式合同,没有就写主数据台账。

开发库 HT20240225000001(id=13)已是审核通过,金额 16016,客户 17。详情 Tab「回款」能同时看到计划和实收。

▲ PC /crm/contract/detail/13 基本信息。客户「演示客户」、金额 16016、审核通过。未通过的合同建回款会被拦

▲ UniApp #/pages-crm/contract/detail/index?id=13。编号 HT20240225000001,审批通过,已回款 16016。外勤看的是同一张单

5. 回款:加总不能超过合同

回款必须挂已通过的合同。金额校验把「已通过 + 审批中」都算进去,编辑时扣掉自己,剩余额度不够就抛错。审批中的回款也占额度,防止两张单同时超。

HK20240225000017(id=29)金额 16016,刚好等于合同额,审批已通过。再录一笔就会被拦。

▲ PC /crm/receivable/detail/29。编号 HK20240225000017,审批通过。超额在保存时拦,不是对账时才发现

▲ UniApp #/pages-crm/receivable/detail/index?id=29。合同 HT20240225000001、金额 16016、审批通过。手机上改金额,后端额度校验一样拦

回款也走 crm-receivable-audit。计划占用:一个计划期只能挂一张回款,避免两笔核销同一期。


三、设计怎么落地

设计思路

决策点
方案
理由
谁是主数据
客户
线索、商机、合同、回款都挂 customer_id
线索何时变客户
OWNER 点转化,复制跟进
未验证不进库;过程不丢
商机赢单是否建合同
不自动建
合同必须再走审批
何时能建回款
合同 auditStatus=20
财务只认审过的额
回款怎么防超
已通过 + 审批中一起加
两张在途单不能同时超
谁能改这条
crm_permission
 + AOP
OWNER 转化 / 转移,WRITE 改,READ 看

客户负责人空着就是公海。权限表和业务表并行,不要只靠 owner_user_id 判断能不能编辑——参与人走 WRITE / READ。

转化先建客户再改线索,避免半转化。回款保存时就算额度,审批中也占坑。

// 线索转化:只能一次;建客户后回写 customerId,并复制跟进public void transformClue(Long id, Long userId) {    CrmClueDO clue = validateClueExists(id);    if (clue.getTransformStatus()) {        throw exception(CLUE_TRANSFORM_FAIL_ALREADY);    }    Long customerId = customerService.createCustomer(            BeanUtils.toBean(clue, CrmCustomerCreateReqBO.class), userId);    clueMapper.updateById(new CrmClueDO().setId(id)            .setTransformStatus(Boolean.TRUE).setCustomerId(customerId));    // 跟进 bizType 从线索改成客户,bizId 换成 customerId}

合同提交只接受草稿。通过回调才改 20,驳回 / 取消不会打开回款入口。

public void submitContract(Long id, Long userId) {    CrmContractDO contract = validateContractExists(id);    if (ObjUtil.notEqual(contract.getAuditStatus(), DRAFT)) {        throw exception(CONTRACT_SUBMIT_FAIL_NOT_DRAFT);    }    String processInstanceId = bpmProcessInstanceApi.createProcessInstance(            userId, new BpmProcessInstanceCreateReqDTO()                    .setProcessDefinitionKey("crm-contract-audit")                    .setBusinessKey(String.valueOf(id)))            .getCheckedData();    contractMapper.updateById(new CrmContractDO().setId(id)            .setProcessInstanceId(processInstanceId).setAuditStatus(PROCESS));}

回款超额在保存时拦。审批中的回款也算占用,避免两张单同时过。

private void validateReceivablePriceExceedsLimit(CrmReceivableSaveReqVO reqVO) {    CrmContractDO contract = contractService.validateContract(reqVO.getContractId());    List<CrmReceivableDO> receivables = receivableMapper            .selectListByContractIdAndStatus(reqVO.getContractId(),                    Arrays.asList(APPROVE, PROCESS));    BigDecimal remain = contract.getTotalPrice().subtract(            sum(receivables, CrmReceivableDO::getPrice));    if (reqVO.getPrice().compareTo(remain) > 0) {        throw exception(RECEIVABLE_CREATE_FAIL_PRICE_EXCEEDS_LIMIT, remain);    }}

权限切面:CRM 管理员放行;无团队成员时公海允许 READ;OWNER 拥有全部操作;WRITE 才能改。转化、转移要求 OWNER,避免参与人把别人的客户转走。


四、和「Excel + 微信」差在哪

设计要点
落地
对业务的价值
客户唯一归属
owner_user_id
 + OWNER 权限
撞单能说清谁主责
跟进写回时间
跟进服务回写 last/next
公海按真实跟进算,不是按打开页
线索隔离
转化才建客户
客户库不被名单污染
商机与合同解耦
赢单不建合同
过程结论和财务单据分开
合同审批
crm-contract-audit
没过的额不能收
回款上限
已通过 + 在途加总
超额当场失败
三级权限
AOP + crm_permission
协作不用复制客户
公海
负责人为空
躺尸能被领走

合同中心是可选下游。CRM 合同过了,可以推正式合同草稿,不是必须上第二套合同模块才能收钱。


五、快速体验

PC:https://ruoyioffice.com/web/
 移动端 H5:https://ruoyioffice.com/app/
 账号 admin / admin123,两端看同一条客户。

菜单
看什么
1
CRM → 线索
打开已转化线索,看客户编号是否回写
2
CRM → 客户
进详情,切跟进 / 商机 / 合同 / 回款
3
客户详情 → 合同
点进审核通过的合同
4
合同 → 回款 Tab
计划和实收是否挂在同一张合同
5
CRM → 回款
打开已通过回款,对照合同额
6
试建一笔超额回款
应被剩余额度拦住
7
CRM → 客户公海
负责人为空的才能领;锁定 / 成交不应出现
8
打开 /app 同一客户
手机详情字段、审批状态是否和 PC 对得上

源码仓库:GitHub:https://github.com/yuqing2026/ruoyi-office | GitCode:https://gitcode.com/zhouzhongyan/ruoyi-office | Gitee:https://gitee.com/yqzy1688/ruoyi-office


常见问题

线索转化后,原来的跟进还在吗?

在。服务按线索 id 查出跟进,批量改成客户 bizType / bizId。线索页仍能看历史,客户页也能看,不是挪走一条。

商机赢单会不会自动生成合同?

不会。合同要销售自己建,再走 crm-contract-audit。赢单只是商机终态,避免「过程赢了、合同被拒」两边状态打架。

为什么审批中的回款也算额度?

两张回款同时审批,如果只算已通过,两张都能过,加总超合同。审批中先占坑,驳回后再释放。

没负责人的客户谁能看?

公海客户没有团队成员时,READ 放行,才能打开详情点领取。WRITE / 转化仍要权限,避免路人改资料。

CRM 合同和合同中心是不是同一张单?

不是。CRM 合同是销售链上的金额单据。通过后可以推送到合同中心补全用印、履约。只上 CRM 也能回款,不必绑第二套模块。


结语

这条链能跑住,靠的是三句话:客户是主数据,审批才认合同,回款不能超。 线索转化带着跟进走,商机自己推阶段,合同和回款各走一条 Flowable。PC 详情和 UniApp 详情读同一条 id,外勤改金额也会被额度拦住。权限按单据成员拦,公海只收没人跟、没锁定、没成交的卡。

同一套「主数据 + 过程单 + 金额单」还可以用在项目台账对合同、进销存对客户出货。先把销售链走通,再谈漏斗图和排行榜——图是结果,链才是产品。


💡 想要体验 RuoYi Office 的强大功能?

🌐 在线演示:https://ruoyioffice.com/web/(账号 admin / admin123)

📦 源码仓库:GitHub:https://github.com/yuqing2026/ruoyi-office | GitCode:https://gitcode.com/zhouzhongyan/ruoyi-office | Gitee:https://gitee.com/yqzy1688/ruoyi-office

💬 技术咨询:添加微信 17156169080,备注「RuoYi Office」

⭐ 如果觉得不错,请给个 Star 支持一下!

【声明】内容源于网络
0
0
企业软件源码
RuoyiOffice 是一套基于 Spring Boot + Vue3 +Uniapp 的企业一体化管理平台,集 OA、CRM、ERP、工作流、HR、资产、合同、项目、AI应用等业务于一体,帮助企业用一个系统协同管理多类核心业务。
内容 125
粉丝 0
企业软件源码 RuoyiOffice 是一套基于 Spring Boot + Vue3 +Uniapp 的企业一体化管理平台,集 OA、CRM、ERP、工作流、HR、资产、合同、项目、AI应用等业务于一体,帮助企业用一个系统协同管理多类核心业务。
总阅读1.5k
粉丝0
内容125