📧 xc@xtocn.com

📞 020-28186541

← 返回文章列表

XTCRM:内置 AI 五层架构的智能客户关系管理平台

RM 1.0

雄韬 CRM 管理后台前端。Vue 3 + Vite + Ant Design Vue 4,配合 ThinkPHP 6.1 后端。

首页

客户页


架构概览

浏览器                            Nginx / Apache
  │                                   │
  ├── /crm/          ← SPA 入口       │ → public/crm/index.html
  ├── /crm/#/xxx     ← Hash 路由      │    Vue Router 接管
  ├── /crm/config.js ← 运行时配置     │ → public/crm/config.js
  └── /index.php     ← API 请求       │ → PHP (ThinkPHP 6.1)
                        s=/platform     → MppAutoload 路由 → Controller

前端和后端部署在同一域名下,index.php 走 PHP,其余 /crm/ 下的静态资源走 Nginx。

开发环境

Node.js

本项目需要 Node.js,推荐使用 nvm(Node Version Manager) 管理版本,避免多项目之间的版本冲突。

当前 Node 版本:v22.16.0

Windows 安装 nvm

下载 nvm-windows 安装包(nvm-setup.exe),安装后打开新的终端:

# 安装并使用 Node 22
nvm install 22
nvm use 22

# 验证
node -v   # v22.16.0
npm -v    # 10.x

macOS / Linux 安装 nvm

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
# 重启终端或 source ~/.bashrc

nvm install 22
nvm use 22

项目自带版本锁

进入 mpp/crm/frontend-v2/ 后,.nvmrc 文件会自动提示 nvm 切换版本:

nvm use        # 自动读取 .nvmrc,切换到 v22.16.0

PHP(宝塔面板)

后端基于 ThinkPHP 6.1,需要 PHP 7.4 + MySQL + Redis。推荐使用宝塔面板一键搭建环境。

宝塔安装 PHP 环境

  1. 安装宝塔面板(bt.cn),登录后台
  2. 进入 软件商店 → 搜索安装:
    • PHP 7.4(必须)
    • MySQL 5.7+
    • Redis
    • Nginx(推荐)
  3. PHP 7.4 → 设置 → 安装扩展,确保开启:
    • redisfileinfopdo_mysqlmbstringcurlopenssl

新建网站

  1. 网站 → 添加站点

  2. 填写域名(开发环境可用本地域名如 crm.dev.xtocn.com,或直接用 localhost

  3. 根目录指向项目的 public/ 目录,例:/www/wwwroot/xtcrm/public

  4. PHP 版本选择 PHP-74

  5. 数据库:勾选"创建数据库",记下数据库名、用户名、密码

伪静态(URL 重写)

网站 → 设置 → 伪静态,粘贴以下 Nginx 规则:

# 静态文件直接返回
location /crm/ {
    try_files $uri $uri/ /crm/index.html;
}

# API 请求全部转发到 index.php
location / {
    if (!-e $request_filename) {
        rewrite ^/index\.php(.*)$ /index.php?s=$1 last;
    }
}

配置 .env

在项目根目录复制 .env.example 为 .env,修改数据库和 Redis 配置:

[DATABASE]
TYPE = mysql
HOSTNAME = 127.0.0.1
DATABASE = xtcrm           # 宝塔创建的数据库名
USERNAME = xtcrm           # 数据库用户名
PASSWORD = your_password   # 数据库密码
HOSTPORT = 3306
PREFIX = tao_

[REDIS]
HOST = 127.0.0.1
PORT = 6379

导入数据库

在宝塔面板 数据库 → 找到对应库 → 导入,选择项目中的 /data/xtcrm_data.sql

或者命令行:

mysql -u xtcrm -p xtcrm < data/xtcrm_data.sql

导入后用宝塔 面板后台 → 数据库 确认 tao_ 开头的表已创建成功。

目录权限

宝塔默认运行用户是 www,确保以下目录可写:

chmod -R 755 runtime/
chmod -R 755 public/uploads/

快速开始

# 1. 克隆
git clone https://github.com/xtoyun/xtcrm.git
cd xtcrm

# 2. PHP 环境(宝塔面板)
# 参考上方「PHP(宝塔面板)」节,安装 PHP 7.4 / MySQL / Redis,
# 新建网站指向 public/,导入 data/xtcrm_data.sql,配置 .env

# 3. 前端 — 切换到正确的 Node 版本
cd mpp/crm/frontend-v2
nvm use

# 4. 安装依赖
npm install

# 5. 开发模式(Vite dev server,端口 9999)
npm run dev
# → http://localhost:9999
# Vite 自动代理 /index.php 到后端(见 vite.config.js 的 server.proxy)

# 6. 构建
npm run build
# → 输出到 public/crm/

管理员账号:admin/123123

开发时访问 http://localhost:9999,登录页 /#/passport/login

配置

运行时配置 (public/config.js)

window.publicConfig = {
  APP_NAME: '客户管理平台',
  BASE_API: '/index.php?s=/platform',   // API 前缀
  uploadImageSize: 2,                    // 图片上传限制 (MB)
  uploadVideoSize: 20,                   // 视频上传限制 (MB)
}

BASE_API 开发时用相对路径(Vite 代理),生产环境根据实际部署调整。

Vite 配置 (vite.config.js)

export default defineConfig({
  base: '/crm/',                         // 部署路径
  server: {
    port: 9999,
    proxy: {
      '/index.php': { target: 'http://crm.dev.xtocn.com', changeOrigin: true },
      '/uploads':   { target: 'http://crm.dev.xtocn.com', changeOrigin: true },
    },
  },
  build: {
    outDir: '../../../public/crm',       // 输出到 PHP 的 public 目录
  },
})

注意:改 proxy.target 指向你的后端地址。生产构建后,index.php 请求不走 Vite,直接由同域 Nginx 转发给 PHP。

开发注意事项

前后端通信

前端所有 API 请求走 index.php?s=/platform

import { axios as request } from '@/utils/request'

// GET 列表
request({ url: '/crm.customer/lists', method: 'get', params: { page: 1 } })
// POST 提交
request({ url: '/crm.customer/add', method: 'post', data: { name: 'xx' } })
// GET 详情
request({ url: '/crm.customer/detail', method: 'get', params: { id: 1 } })

路由规则:URL 用点号分隔 模块.控制器/方法。子目录也用点号:crm.admin.user/list

响应格式

拦截器已解包,res.data 直接是业务数据:

request({ url: '/crm.customer/lists' }).then(res => {
  // res.data = { list: [...], total: 100 }   ← 分页
  // res.data = { list: [...] }                ← 全量下拉
  // res.data = { detail: {...} }              ← 单条详情
})

陷阱:分页列表 res.data.list 是对象 {data: [...], total: N};全量下拉 res.data.list 是数组 [...]。使用前先确认后端是 paginate() 还是 select()

导入铁律

// ✅ 必须具名导入 — 模块没有 default 导出
import { axios as request } from '@/utils/request'

// ❌ 这行不通 — undefined
import request from '@/utils/request'

路由注意事项

// 带子菜单的父路由必须加 name,否则子菜单不显示
{ path: '/crm/customer', name: 'customer', component: RouteView, children: [...] }

// 隐藏路由:meta.hidden,不是顶层 hidden
{ path: '/crm/customer/detail', meta: { hidden: true } }

// 当前使用 hash mode:/#/passport/login

Skill(插件)集成

插件前端文件从 skills/{name}/views-v2/ 复制到 src/skills/{name}/

skills/invoice/views-v2/          →  src/skills/invoice/
    routes-v2.js                       routes-v2.js
    invoice/index.vue                  invoice/index.vue
    ...

宿主路由一行引入:

import invoiceRoutes from '@skills/invoice/routes-v2'
// children: [...invoiceRoutes]

权限控制

前端路由 meta.permission 控制菜单显隐,后端 checkAction() 做 API 级拦截:

// Controller
if (!$this->checkAction('/crm/customer/delete', '删除客户')) return;

多租户

这是最容易踩的坑。 所有数据必须归属 store_id

  • Model 查询自动带 store_id scope ✅
  • Db::name() 不自动带 — 必须手动 where('store_id', $storeId) ⚠️
  • Db::table() 禁止使用 — 硬编码前缀会炸 🔴
  • Service 方法必须接收 $storeId 参数

前端技术栈对比

项目 Vue 版本 UI 构建
frontend-v2(当前) Vue 3.5 Ant Design Vue 4 Vite 8

AI 架构(五层)

CRM 的 AI 不是单次 API 调用的"外挂",而是一套从数据采集 → 分析发现 → 建议生成 → 效果追踪 → 对话执行的完整闭环。五层自底向上:

┌──────────────────────────────────────────────────┐
│  ⑤ Agent 引擎   对话查数据 / 生成草稿 / 执行操作    │
├──────────────────────────────────────────────────┤
│  ④ 反馈闭环     采纳/拒绝 → 追踪 AI 建议效果       │
├──────────────────────────────────────────────────┤
│  ③ 洞察引擎     主动扫描 → 发现机会 → AI 增强文案  │
├──────────────────────────────────────────────────┤
│  ② Service 层   AI 可调用的业务接口(与人共用)     │
├──────────────────────────────────────────────────┤
│  ① 事件流       所有操作写入不可变 event_log       │
└──────────────────────────────────────────────────┘

① 事件流 — 不可变事实

所有业务操作写入 crm_event_log 表,作为 AI 系统的唯一数据源。事件与业务数据在同一个事务中写入,保证原子一致。

14 种事件类型customer_created/updated/claimed/releasedfollow_up_completedfunnel_stage_changedquotation_created/sent/confirmed/rejected/convertedorder_created/status_changedcontract_signedlead_converted

  • EventService::record() 不开启自己的事务,参与调用方事务
  • event_log 只追加不修改,任何 AI 分析都可以重放
  • 事务提交后 handleEvent() 实时失效已被解决的旧洞察

② Service 层 — 人与 AI 共用

Agent 工具调用的不是"AI 专用 API",而是与前端 Controller 完全相同的 Service 方法。Agent 调用 getCustomerDetail(42) 拿到的是和前端页面一模一样的数据。

// Service 统一返回格式
['success' => bool, 'data' => mixed, 'error' => string]

③ 洞察引擎 — 主动发现

每日凌晨自动扫描,规则先于 AI

A 级扫描(纯规则,零 API 成本):

规则 输出类型 检测逻辑
scanFollowupOverdue followup_overdue 报价 status=2,days_since > max(avg_reply, 7)
scanRepurchaseWindow repurchase_window ≥2 订单,days_since ≥ avg_interval × 0.8
scanPoolWarning pool_warning 公海客户滞留预警
scanChurnRisk churn_risk 上次跟进 > 历史间隔 × 1.5,30天无跟进
scanDormant dormant 90天无任何互动

B 级 AI 增强:仅对 A 级命中结果调 DeepSeek 生成 30 字跟进建议,存入 crm_ai_suggestion

事件驱动实时失效:客户被认领 → pool_warning resolved;订单创建 → repurchase_window + churn_risk + dormant resolved;报价成交 → followup_overdue + churn_risk resolved。

设计理念:5 条规则覆盖 80% 的销售管理需求,零 API 费用。只有真正命中的才调 AI。1000 客户的租户通常每天只产生 5-15 条洞察。

④ 反馈闭环

工作台以卡片展示洞察("需关注" / "机会发现"),每条附带 AI 建议。用户可采纳/拒绝,追踪采纳率。

  • 追踪指标:总建议数 / 采纳数 / 拒绝数 / 采纳率 / 转化率
  • 没有反馈闭环的 AI 是一锤子买卖——你不知道建议到底帮到销售没有

⑤ Agent 引擎

使用 OpenAI 兼容的 Function Calling 协议,最多 8 轮工具调用循环。

8 个内置工具searchCustomergetCustomerDetailgetOrderListgetQuotationListgetFollowupHistorygetMyStatsgetDashboardsearchProduct

技能包工具动态注入SkillPipeline::getAllSkillTools() 扫描已安装技能包,自动注册其 Function Calling 工具。安装新技能包后 Agent 自动获得新能力,无需改代码。

完整数据流

用户操作 → Controller → Service → [业务写入 + EventService::record()]
    │                                    ↓
    │                            crm_event_log(不可变)
    │                                    ↓
    │                     ┌──────────────┴──────────────┐
    │                     ↓                             ↓
    │             实时:handleEvent()          每日:CrmInsight Timer
    │             失效冲突洞察                    ↓
    │                                   InsightService::dailyScan()
    │                                     ├── A 规则扫描(5 条)
    │                                     ├── B AI 增强建议
    │                                     └── 通知生成
    │                                          ↓
    └──────────────────────────→ Dashboard::index()
                                     ├── insights(洞察卡片)
                                     ├── funnel(漏斗图)
                                     ├── kpi / ranking(投影数据)
                                     └── unreadCount(通知铃铛)

六张核心 AI 表

用途 特点
crm_event_log 事件流 只追加,不可变
crm_insight 洞察缓存 幂等键去重,30天过期
crm_projection 统计快照 每日刷新
crm_ai_suggestion AI 建议追踪 采纳/拒绝/忽略
crm_notification 站内通知 已读/未读
crm_agent_log Agent 会话日志 对话 + 工具调用记录

详细设计见 AGENTS.md 和 .claude/agents/crm.md

界面展示

登录页

登录页

工作台首页

仪表盘、洞察卡片、漏斗图、KPI 看板一站式呈现。

首页

客户管理

客户列表、详情、跟进记录、报价/订单关联。

客户页

销售管理

报价、订单、合同全流程。

销售页

知识库

产品知识、销售话术、竞品对比、成功案例。

知识库页

应用中心

已安装技能包(报价、发票、内容引擎等)。

应用页

系统设置

用户、角色、部门、菜单权限管理。

系统设置页

CRM 设置

租户级参数:公海规则、洞察阈值、跟进提醒等。

CRM设置页

AI 设置

内容引擎 Agent 配置、预设管理、变量定义。

AI设置页


联系与赞助

联系作者

扫描下方二维码添加微信,备注"雄韬CRM"。

联系二维码

赞助支持

如果这个项目对你有帮助,欢迎请作者喝杯咖啡 ☕

赞助二维码


目录结构

mpp/crm/frontend-v2/
├── public/
│   └── config.js              ← 运行时配置
├── src/
│   ├── api/                   ← axios 请求(按模块分文件)
│   ├── components/            ← 公共组件
│   ├── layouts/               ← BasicLayout / UserLayout
│   ├── router/                ← 路由(asyncRoutes + permission guard)
│   ├── skills/                ← 插件前端(从 skills/ 复制进来)
│   ├── stores/                ← Pinia(user, permission)
│   ├── utils/                 ← axios 封装、权限工具
│   └── views/                 ← 页面组件
│       ├── crm/               ← 客户 / 线索 / 报价 / 订单 / 合同
│       ├── passport/          ← 登录
│       ├── manage/            ← 用户 / 角色 / 部门 / 菜单
│       └── index/             ← 工作台
├── index.html
├── vite.config.js
└── package.json

常见问题

# 现象 原因 处理
1 API 返回 undefined import request from 用 import { axios as request } from
2 侧边栏菜单不显示子项 RouteView 缺 name 加 name: 'xxx'
3 列表搜索清空后无数据 空字符串 '' 进入 SQL 过滤 value !== ''
4 Modal 打开 editor 报错 编辑器在隐藏 DOM 中初始化 用 v-if 控制 Modal 内容挂载
5 a-modal width 不生效 scoped 样式穿不透 去掉 scoped,加 wrapClassName
6 按钮全白无样式 @ant-design/cssinjs 未装 npm install @ant-design/cssinjs
7 构建后资源 404 base 路径不匹配 确认 vite.config.js 的 base 值
8 路由跳转地址不对 hash/history mode 不一致 确认 router/index.js 的 mode

开源声明

产权与独立性

XTCRM 为个人原创作品,非任何公司或组织的职务作品。全部代码由项目作者(xtoyun)独立设计开发,知识产权完整且归属清晰。项目不包含任何第三方闭源代码或未经授权的内部代码。

许可证

本项目采用 Apache License 2.0 协议开源。完整协议文本见 LICENSE

Apache-2.0 是企业级开源最友好的协议之一,授予你:

  • ✅ 商业使用 — 无需额外授权,可用于商业产品和内部系统
  • ✅ 修改和分发 — 可自由修改源码,以源码或编译形式分发
  • ✅ 专利保护 — 协议明确授予专利权,防止贡献者后续发起专利诉讼
  • ✅ 私有使用 — 修改后的代码无需公开
  • ⚠️ 保留声明 — 分发时需保留原始版权声明和 LICENSE 文件

归属声明

分发或部署本软件时,需保留 NOTICE 文件中的归属信息。衍生作品可在 NOTICE 中添加你自己的归属,但不得删除原始声明。

社区治理

本项目采用 单一维护者 + 社区贡献 的治理模型。核心文档:

文档 用途
GOVERNANCE.md 角色定义、决策流程、晋升机制
CONTRIBUTING.md 如何参与贡献(编码规范、PR 流程)
SECURITY.md 安全漏洞报告、响应时效
CODE_OF_CONDUCT.md 社区行为准则(Contributor Covenant 2.0)
CHANGELOG.md 版本历史

License

Apache-2.0 © 2025 XiongTao Team

020-28186541 微信咨询 xc@xtocn.com

添加微信咨询

扫一扫二维码,直接沟通

微信二维码

微信号:13710429985