项目:ERP-CRM | 版本:v1.1 | 生成日期:2026-10-05 | 依据:源码分析(v1.1:2026-10-06 一致性回刷,与 16-20 篇对齐)
本项目(目录 erp/,含 erp-crm/ 后端与 erpcrm-ui/ 前端两个独立 git 仓库)是一套企业级 ERP + CRM 一体化 SaaS 系统,源自慕课网课程《SpringBoot+Vue3 打造企业级 ERP+CRM 一体化 SaaS 系统》,但在课程原码基础上做了大量工程化重构:后端由 Spring Boot 2.5.8 七模块(center/auth/system/common/saas/crm/erp)合并为单模块 Spring Boot 3.5.16(见 erp-crm/pom.xml,artifactId ec,version 3.9.2,<finalName>erpcrm</finalName>);前端由 Vue2 → Vue3(vite-vue3 分支)→ 2026-09 整体替换为 pure-admin 模板底座(当前 pure-admin 分支,业务代码保持 JS)。
项目的核心卖点是基于"独立数据库物理隔离"的多租户 SaaS 架构:每个租户(订阅企业)拥有一个独立的 MySQL 数据库,由主库 erp-crm-master 中的 master_tenant 表登记各租户库的连接信息,运行时按请求头 tenant 动态路由数据源。该结论在源码中的证据链非常完整:erp-crm/src/main/java/com/ec/auth/interceptor/TenantInterceptor.java(拦截请求头并注册数据源)、erp-crm/src/main/java/com/ec/auth/datasource/DynamicRoutingDataSource.java(动态路由数据源)、erp-crm/src/main/java/com/ec/auth/web/service/TenantRegisterService.java(注册时真实 CREATE DATABASE 建库)。
目标用户分两类:
system/tenant(SysTenantController)管理租户生命周期(改套餐、停用、删除),通过 saas/package(SaasPackageController)管理订阅套餐;TenantExpirationJob(erp-crm/src/main/java/com/ec/saas/job/TenantExpirationJob.java)每日 03:00 自动巡检租户到期并停用。两域业务并非并列的两座孤岛,而是首尾相接的一条价值链:销售在 CRM 侧从公海领取线索(POST /crm/pool/receive/{id}),跟进转化为客户,推进商机并在合同环节走 Flowable 审批流,签约回款后进入 ERP 侧生成销售订单,经仓库采购入库/零售出库改变库存,最终沉淀为财务侧的应收与库存资产总览。中间各环的数据口径(客户与订单的关联、产品与安全库存的联动)由《04-数据模型》承接。理解这条价值链后,功能清单里"CRM 七组 + ERP 十六组"Controller 的划分逻辑就一目了然:分组边界即业务域边界。在商业模型层面,SaaS 的"套餐-配额-到期"三件套把租户生命周期闭环:注册时选套餐计算有效期,租户内新增/导入用户前由 TenantQuotaService 校验套餐 maxUsers 上限,每日 03:00 的 TenantExpirationJob 巡检临期(默认提前 7 天提醒)并自动停用到期租户,运营方在主库侧可随时改套餐或手动停用。
| 功能域 | 模块 | 关键能力 | 主要后端入口 | 前端页面 |
|---|---|---|---|---|
| 租户 SaaS | 租户注册 | 校验名称唯一→真实建库建用户→跑租户模板 SQL→登记主库,支持选套餐计算有效期 | POST /register(SysRegisterController) | views/register.vue |
| 租户 SaaS | 租户管理/套餐 | 租户列表、改套餐(updateMasterTenant)、配额查询、三档套餐 | /system/tenant、/saas/package | views/system/tenant/list.vue |
| 租户 SaaS | 生命周期 | 临期提醒(默认 7 天)、到期自动停用、闲置数据源 30 分钟淘汰 | TenantExpirationJob、IdleDataSourceEvictor | — |
| 认证鉴权 | 登录/令牌 | JWT(HS512)120 分钟滑动续期、密码错 5 次锁 10 分钟、/login IP 限流 30 次/分 | SysLoginController、SysLoginService、TokenService | views/login/index.vue |
| 系统管理 | 用户/角色/菜单/部门/岗位/字典/参数/通知 | RuoYi 风格 RBAC,按钮级权限(@ss.hasPermi + 前端 v-hasPermi) | /system/user 等 9 组 Controller | views/system/*(86 页中约 20 页) |
| 系统管理 | 租户内配额 | 新增/导入用户前校验套餐 maxUsers | TenantQuotaService | — |
| 监控审计 | 日志/在线用户/服务监控 | 登录日志、操作日志(@Log 注解 + LogAspect)、在线用户强踢、服务监控(oshi 依赖闲置:/monitor/server 端点已随单模块消失,见 17 篇 3.1) | /monitor/*(仅 operlog/logininfor/online 三组) | views/monitor/* |
| 可观测性 | 指标 | Actuator + Micrometer Prometheus,独立端口 9091;业务指标 ErpMetrics | /actuator/prometheus | — |
| CRM | 线索管理 | 线索列表/个人线索、转移、转客户(PUT /crm/clues/to-customer) | CrmCluesController | views/crm/clues/* |
| CRM | 客户/公海 | 客户 CRUD、移入公海、转移、领取(POST /crm/pool/receive/{id})、跟进记录 | CrmCustomerController、CrmPoolControler、CrmCommentController | views/crm/customer/*、views/crm/pool/* |
| CRM | 商机/合同/回款 | 三张业务表 + 生成器产出(见下) | CrmOpportunityController 等 | views/crm/opportunity 等 |
| CRM | 合同审批 | Flowable 7.0.1 流程引擎,跨主库/租户库补偿式一致性 | CrmApprovalController、CrmApprovalServiceImpl | views/crm/approval/index.vue |
| CRM | 数据看板 | 首页指标面板、客户/线索分布、订单趋势、今日跟进 | /crm/index-data/info、/crm/index-data/stats | views/welcome/index.vue |
| ERP | 主数据 | 产品(含安全库存)、供应商、仓库、开票信息、标签、序列号 SN | /erp/product 等 7 组 | views/erp/* |
| ERP | 采购 | 采购单+明细、采购入库(CAS 认领防重复)、采购付款 | ErpStockOrderController、ErpPaymentController | views/erp/stock、views/erp/payment |
| ERP | 销售/零售 | 销售订单(关联客户/开票信息)、零售出库(扫 SN) | ErpOrderController、ErpRetailController | views/erp/order/*、views/erp/retail |
| ERP | 库存 | 库存流水(按仓库)、库存调拨(执行校验+负库存回滚)、盘点调整 | ErpStorageFlowController、ErpTransferOrderController、ErpStockAdjustmentController | views/erp/flow、views/erp/transfer、views/erp/adjustment |
| ERP | 财务 | 应收/库存资产总览、库存汇总 | ErpFinanceController | views/erp/finance |
| AI 辅助 | 知识库 | 知识条目 CRUD/导出(管理后台形态,无外部 AI 服务依赖) | /ai/knowledgeBase(KnowledgeBaseController) | — |
| 平台工具 | 代码生成/表单构建 | RuoYi 遗留页面保留(views/tool/gen、views/tool/build);后端生成器独立为 gen_business_modules.py | /tool/gen(前端页面保留,后端生成接口未随单模块迁移,为已知死页——13 篇 D19) | views/tool/* |
关于代码生成:
erp-crm/gen_business_modules.py是一个一次性 Python 脚本(451 行),按MODULES数组中的表定义批量生成 domain/mapper 接口/mapper XML/service 接口/service 实现/controller 共 6 个文件,已用其生成了商机(CrmOpportunity)、合同(CrmContract)、回款(CrmReceivable)三个 CRM 模块,生成产物已固化在erp-crm/src/main/java/com/ec/crm/下。它是开发期工具,不参与运行时。
erp-crm/pom.xml 与 erp-crm/src/main/resources/application.yml)| 技术 | 版本 | 用途 | 选型理由(依据源码注释/结构) |
|---|---|---|---|
| Java / Spring Boot | 17 / 3.5.16 | 运行时与框架基座 | 由 SB2.5.8 升级,包命名空间迁移到 jakarta.*(AGENTS.md 后端约定) |
| Spring Security | 6.x(随 BOM) | 认证/授权 | SecurityConfig 启用 @EnableMethodSecurity,方法级 @PreAuthorize("@ss.hasPermi(...)") |
| MyBatis + PageHelper | 3.0.3 / 2.1.0 | ORM 与分页 | XML mapper 全量手写/生成于 resources/mapper/**;分页经 PageUtils.startPage()(pageSize 钳制 ≤500) |
| Druid | 1.2.25(纯依赖,非 starter) | 连接池 | 需要编程式创建租户池:DruidProperties.dataSource()/tenantDataSource() 两档规格 |
| Flowable | 7.0.1 | 审批流程引擎 | processes/contract-approval.bpmn20.xml;引擎表落主库(application.yml flowable 段注释) |
| jjwt | 0.12.7 | JWT | HS512 硬性要求密钥 ≥64 字节(TokenService.getSecretKey()) |
| fastjson2 | 2.0.64 | JSON 序列化 | RuoYi 栈约定;FastJson2JsonRedisSerializer 用于 Redis 值序列化 |
| springdoc-openapi | 2.8.17 | 接口文档 | /swagger-ui/index.html;prod 由 EcProdConfigVerifier 强制关闭 |
| micrometer-prometheus | 随 BOM | 指标 | management.server.port: 9091 独立指标端口 |
| POI / oshi / UserAgentUtils | 5.3.0 / 6.4.8 / 1.21 | Excel 导入导出 / UA 解析 / 服务器监控(oshi 闲置:唯一引用方 Server.java 无调用方,可移除候选,见 17 篇 3.1) | ExcelUtil、Server 域对象等 |
| MySQL 8.4 / Redis 7 | — | 存储与缓存 | 主库+租户库;Redis 存 JWT 会话、验证计数、字典缓存 |
erpcrm-ui/package.json、erpcrm-ui/vite.config.ts)| 技术 | 版本 | 用途 | 选型理由 |
|---|---|---|---|
| Vue / TypeScript | 3.5 / 5.x(基座) | UI 框架 | pure-admin 底座为 TS;业务层(views/api/components)保持 JS,降低迁移成本 |
| Vite(rolldown) | 8.2.2(rolldown 锁 1.2.5) | 构建 | rolldown 提速;pnpm.overrides 钉死 1.2.5 规避 1.2.8 兼容问题(README 构建注意) |
| Element Plus | 2.14.5 | 组件库 | RuoYi 系页面原生依赖 |
| Pinia / vue-router | 4.0.3 / 5.2.0 | 状态/路由 | pure-admin 基座;路由历史模式为 hash(.env VITE_ROUTER_HISTORY=hash) |
| Tailwind CSS | 4.3.3 | 原子样式 | 与 Sass 并存,新页面可用工具类 |
| echarts | 5.6.0(按需注册) | 图表 | 强制从 src/plugins/echarts.ts 导入,防全量引入撑大 chunk(AGENTS.md 前端约定) |
| pnpm | 10.x(corepack 钉版本) | 包管理 | preinstall: npx only-allow pnpm 强制 |
application.yml)。/dev-api 代理到 127.0.0.1:9090(vite.config.ts server.proxy);生产以 nginx 托管,/prod-api 反代后端(erpcrm-ui/nginx.conf)。erp-crm-master;租户库按 ec_ 前缀 + 随机串建库(如 ryt_nelub7xr 为历史租户 tenant1 的库)。选型上有三处权衡值得展开。其一,七模块合并为单模块(2026-09,见 AGENTS.md):课程原码按 center/auth/system/common/saas/crm/erp 拆分 Maven 模块,但七者本就同进程构建发布,拆分只带来依赖管理的额外复杂度;合并后包结构 com.ec.{auth,common,saas,sys,web,crm,erp} 仍保留原边界,属于"用包边界替代模块边界"的务实收敛。其二,Flowable 引擎表落主库:审批流是平台级能力而非某个租户的业务数据,落主库避免每注册一个租户就复制一套 ACT_* 表的膨胀,代价是审批数据与租户业务数据分属两库,一致性靠跨库补偿式设计(见《05-核心流程》审批流一节)。其三,前端基座 TS、业务层 JS:pure-admin 底座保持 TS 以获得模板自身的类型收益,views/api/components 保持 JS 则把课程存量代码的迁移成本压到最低——两轮前端改造(Vue2 → Vue3 → pure-admin)都遵循"换底座不重写业务"的路线,旧实现保留在 vite-vue3 分支可随时对照。
erp/
├── AGENTS.md # AI 代理/新成员上下文说明(信息密度高,但个别描述滞后于源码,见 03 篇"待确认")
├── erp-crm/ # 后端仓库(Spring Boot 3 单模块)
│ ├── pom.xml # 全部依赖与 spring-boot-maven-plugin(mainClass=com.ec.ErpCrmApplication)
│ ├── gen_business_modules.py# 开发期代码生成器(Python,生成 CRM 三模块六件套)
│ ├── erpcrm.sh / erpcrm.bat # Linux/Mac、Windows 启停脚本(加载同目录 .env)
│ ├── Dockerfile # Maven 构建 + JRE17 运行 两阶段镜像
│ ├── .env / .env.example # 密钥外置(gitignored / 模板)
│ ├── config/ # 生产外置配置模板 application-prod.yml.example + 密钥说明
│ ├── ops/
│ │ ├── backup.sh # 主库+全部启用租户库 mysqldump→gzip→AES-256 加密→按天清理
│ │ ├── deploy/docker-compose.yml # MySQL8.4+Redis7+db-init+backend+frontend 一键栈
│ │ ├── prometheus/ grafana/ # 监控栈配置与看板
│ ├── sql/erp-crm-master.sql # 主库初始化(master_tenant/sys_logininfor/sys_oper_log/crm_approval/tenant_package)
│ ├── homework/ # 课程作业/简历资料(非代码)
│ └── src/
│ ├── main/java/com/ec/
│ │ ├── ErpCrmApplication.java # 启动类
│ │ ├── auth/ # 安全与数据源:SecurityConfig、JwtAuthenticationTokenFilter、TokenService、
│ │ │ # TenantInterceptor、DynamicRoutingDataSource、IdleDataSourceEvictor、
│ │ │ # DataSourceAspect、SysLoginService、TenantRegisterService、GlobalExceptionHandler
│ │ ├── common/ # 通用层:注解(@DataSource/@Log/@RateLimiter/@RepeatSubmit/@DataScope/@Excel)、
│ │ │ # AjaxResult/TableDataInfo/BaseController、RedisCache、ExcelUtil、XSS 过滤、ErpMetrics
│ │ ├── saas/ # SaaS 主库域:MasterTenant/TenantPackage 实体与 Mapper、租户口令 AES-GCM 加解密
│ │ │ # (TenantDbPasswordCipher、MasterTenantPasswordMigrator)、TenantExpirationJob
│ │ ├── sys/ # 系统域 service/mapper(用户/角色/菜单/部门/字典/日志/知识库等)
│ │ ├── web/ # center 层 Controller:system/*、monitor/*、common/*、ai/*,及 TenantQuotaService
│ │ ├── crm/ # CRM 业务:customer/clues/pool/comment/opportunity/contract/receivable/order/
│ │ │ # approval(Flowable)/index-data/owner 七组 controller+service+mapper
│ │ └── erp/ # ERP 业务:product/supplier/warehouse/stock/payment/order/retail/sn/flow/
│ │ # transfer/adjustment/client/tax/tags/map/finance 十六组
│ ├── main/resources/
│ │ ├── application.yml / application-druid.yml # 主配置与数据源配置(EC_* 环境变量占位)
│ │ ├── mapper/{sys,crm,erp,saas}/*.xml # MyBatis 映射
│ │ ├── init-sql-script/erp-crm-tenant-sample.sql # 租户库模板(40 张表+菜单/字典种子)
│ │ ├── processes/contract-approval.bpmn20.xml # Flowable 合同审批流程定义
│ │ └── logback.xml、i18n/、mybatis/mybatis-config.xml
│ └── test/java/com/ec/ # 13 个测试类(登录认证链、审批流、采购入库、调拨、租户注册、配额等集成测试)
├── erpcrm-ui/ # 前端仓库(pure-admin 底座)
│ ├── package.json / pnpm-lock.yaml / vite.config.ts / vitest.config.ts
│ ├── Dockerfile + nginx.conf # node:22 构建 → nginx 托管 + /prod-api 反代
│ └── src/
│ ├── main.ts / App.vue
│ ├── router/ # pure-admin 路由:modules/{home,remaining,error}.ts 静态路由 + utils.ts 动态装配
│ ├── store/modules/ # Pinia:user/permission/app/epTheme/multiTags/settings(均 TS)
│ ├── layout/ # 基座布局(侧边栏/多标签/导航)
│ ├── api/ # 业务接口封装:login.js、user.ts(登录适配层)、routes.ts(菜单转换)、
│ │ # crm/* 11 个、erp/* 17 个、system/*、monitor/*、tool/*
│ ├── views/ # 86 个页面:login/register/welcome + crm/* + erp/* + system/* + monitor/* + tool/*
│ ├── composables/ # useTable(表格 CRUD)、useModal、useDict(模块级缓存)、useAppContext
│ ├── components/ # RuoYi 系业务组件(RightToolbar/Pagination 等)+ Re* 基座组件
│ ├── directive/ # v-hasPermi/v-hasRole 按钮权限指令
│ ├── plugins/ # echarts 按需注册、download、auth、cache、tab、macarons 主题
│ └── utils/ # request.js(axios 封装)、auth.ts(token 存取)、errorHandler.js、svgSprite.js 等
├── db-backup/ # 手工备份与增量迁移
│ ├── ryt_nelub7xr_20260907.sql 等 # 租户库快照(大文件,仅抽样)
│ ├── upgrade_*.sql # 增量迁移脚本(业务模块/审批/供应链财务/调拨/盘点)——数据模型演进的权威线索
│ ├── legacy-sql/ # 历史库快照归档
│ └── *.enc # AES-256 加密备份(口令在本机,不在仓库)
└── 笔记/ # 开发笔记(多租户模式调研等,作背景线索)注意:erp/ 根目录没有项目级 README,erp/erp-crm/README.md 实际是后端仓库说明,erp/db-backup/README.md 是备份目录说明;本套文档即以源码为准补足全局视角。
前置条件:JDK 17、Maven 3.9+、Node ≥22.22.1(实测 v24 可用)+ pnpm 10、本机 MySQL 8.4 与 Redis 7(Redis 必须运行)、一个内容 ≥64 字节的 JWT 密钥。
# 1) 初始化数据库(主库 + 一个租户库)
mysql -uroot -p -e "CREATE DATABASE \`erp-crm-master\` DEFAULT CHARACTER SET utf8mb4;
CREATE DATABASE \`ryt_nelub7xr\` DEFAULT CHARACTER SET utf8mb4;"
mysql -uroot -p erp-crm-master < erp-crm/sql/erp-crm-master.sql
mysql -uroot -p ryt_nelub7xr < erp-crm/src/main/resources/init-sql-script/erp-crm-tenant-sample.sql
# 参照 erp-crm/.env.example 生成 erp-crm/.env(JWT 密钥/数据库凭据/Druid 账号等)
# 并将 master_tenant 中 tenant1 行的 url/username/password 修正为本机可用值(CI 脚本 backend.yml 第 70-81 行有同源示例)
# 2) 启动后端(端口 9090)
cd erp-crm && mvn package -DskipTests
java -jar target/erpcrm.jar # 或 ./erpcrm.sh start(Linux/Mac)/ erpcrm.bat(Windows)
# 3) 启动前端(端口 80,/dev-api → 9090)
cd ../erpcrm-ui && pnpm install && pnpm dev
# 4) 登录验证
# 浏览器打开 http://localhost ,租户 tenant1 / 账号 admin / 密码 admin123(CI 与 compose 均按此口径补种 admin)
# 5) 在线工具
# 接口文档 http://localhost:9090/swagger-ui/index.html
# Druid http://localhost:9090/druid/index.html(账号取 .env 的 EC_DRUID_USER/EC_DRUID_PASSWORD)
# 指标 http://localhost:9091/actuator/prometheus后端测试(依赖本机 MySQL/Redis 与 .env):cd erp-crm && mvn test(13 个测试类,覆盖登录认证链、审批流、采购入库、库存调拨、租户注册、租户到期巡检、配额、口令加密等)。前端质量门禁:pnpm lint && pnpm typecheck && pnpm test。Docker 一键栈见 erp-crm/ops/deploy/docker-compose.yml(细节在 06-部署运行篇展开)。
/crm/customer/list ↔ src/api/crm/customer.js)。db-backup/upgrade_*.sql 的幂等写法可直接复用),并记得同步改租户模板 init-sql-script/erp-crm-tenant-sample.sql,否则新注册租户会缺表。