1. 项目概述
最近在帮一家中小型贸易公司搭建客户关系管理系统,选择了Vue.js作为前端框架。这个决定不是拍脑袋定的——经过对市面上十几个CRM系统的试用和评估,发现现成产品要么功能冗余,要么定制成本太高。而用Vue从头搭建,既能精准匹配业务需求,又能保持技术栈的统一性。
这个系统主要解决三个痛点:客户信息碎片化(分散在Excel/微信/邮件里)、销售过程不透明(不知道跟单进度)、数据分析滞后(月底才能出报表)。现在开发完成上线三个月,客户信息集中度提升80%,销售转化周期缩短了1/3。
2. 技术架构设计
2.1 前端技术选型
选择Vue 3 + TypeScript的组合主要考虑三点:
- Composition API更适合复杂业务逻辑组织
- TypeScript的强类型检查能减少30%以上的低级错误
- 团队已有Vue 2经验,迁移成本可控
具体技术栈:
- UI库:Element Plus(商业项目首选,文档齐全)
- 状态管理:Pinia(比Vuex更轻量,TypeScript支持更好)
- 图表:ECharts(满足销售漏斗等复杂可视化需求)
- 地图:高德地图JS API(客户分布可视化)
踩坑提醒:Element Plus的按需引入需要额外配置babel-plugin-import,否则打包体积会大2-3倍
2.2 后端接口设计
采用RESTful规范,但做了两点特殊处理:
- 批量操作接口(如导出客户列表)使用POST而非GET
- 复杂查询条件用JSON格式放在query参数中
典型接口示例:
typescript复制// 获取客户列表
GET /api/customers?filter={"status":"active","region":"east"}
// 批量更新客户标签
PATCH /api/customers/tags
{
"ids": [101,102,103],
"action": "add",
"tags": ["VIP"]
}
3. 核心功能实现
3.1 客户360°视图
这个功能聚合了客户所有信息:
- 基础信息(名称、行业等)
- 联系记录(通话、拜访、邮件)
- 商机跟踪(报价单、合同)
- 服务记录(投诉、咨询)
关键技术点:
- 使用Vue动态组件实现标签页懒加载
- 采用IndexedDB缓存客户附件(合同扫描件等)
- 实现时间轴组件展示交互历史
vue复制<template>
<el-tabs v-model="activeTab" @tab-click="loadTabData">
<el-tab-pane v-for="tab in tabs" :key="tab.name" :label="tab.label">
<component :is="tab.component" :customerId="customerId" />
</el-tab-pane>
</el-tabs>
</template>
<script setup>
const loadTabData = (tab) => {
if(!loadedTabs.value.includes(tab.props.name)) {
// 调用API加载数据
loadedTabs.value.push(tab.props.name)
}
}
</script>
3.2 销售漏斗分析
用ECharts实现的动态漏斗图,特点:
- 支持多维度筛选(时间范围、产品线、销售团队)
- 点击每个阶段钻取详细客户列表
- 自动计算转化率和平均停留时长
配置技巧:
javascript复制// 关键配置项
option = {
series: [{
type: 'funnel',
sort: 'descending',
gap: 2,
label: {
formatter: '{b}: {c} ({d}%)'
},
data: [
{ value: 100, name: '线索' },
{ value: 80, name: '初步沟通' },
// ...
]
}]
}
4. 性能优化实践
4.1 前端缓存策略
- API响应缓存:使用axios拦截器+localStorage
javascript复制instance.interceptors.response.use(response => {
if(response.config.method === 'get') {
const key = generateCacheKey(response.config)
localStorage.setItem(key, JSON.stringify({
data: response.data,
timestamp: Date.now()
}))
}
return response
})
- 图片懒加载:自定义指令
vue复制<template>
<img v-lazy="customer.avatar" />
</template>
<script>
app.directive('lazy', {
mounted(el, binding) {
const observer = new IntersectionObserver((entries) => {
if(entries[0].isIntersecting) {
el.src = binding.value
observer.unobserve(el)
}
})
observer.observe(el)
}
})
</script>
4.2 打包优化
- 代码分割:按路由拆分chunk
javascript复制// vite.config.js
build: {
rollupOptions: {
output: {
manualChunks(id) {
if (id.includes('node_modules')) {
return 'vendor'
}
if (id.includes('src/views')) {
return id.split('views/')[1].split('/')[0]
}
}
}
}
}
- 开启Gzip压缩(节省60%体积)
bash复制# 安装插件
npm install vite-plugin-compression -D
# 配置
plugins: [
compression({
algorithm: 'gzip',
ext: '.gz'
})
]
5. 典型问题排查
5.1 内存泄漏问题
现象:长时间使用后浏览器卡顿
排查过程:
- 用Chrome Memory面板拍快照
- 发现被卸载的组件仍被EventBus引用
- 解决方案:改用provide/inject替代全局事件总线
5.2 大数据量渲染卡顿
客户列表超过500条时滚动卡顿
优化方案:
- 虚拟滚动(使用vue-virtual-scroller)
- 分页加载+滚动加载组合
- 表格列动态渲染(可视区域外的列不渲染)
vue复制<template>
<RecycleScroller
:items="customers"
:item-size="56"
key-field="id"
v-slot="{ item }"
>
<CustomerRow :data="item" />
</RecycleScroller>
</template>
6. 扩展功能建议
-
客户画像标签系统:
- 基于规则引擎自动打标
- 支持RFM模型自动计算
- 标签组合筛选
-
移动端适配方案:
- 单独构建移动端入口
- 使用vw/vh单位
- 手势操作支持(滑动删除等)
-
数据看板配置化:
- 拖拽布局
- 组件仓库
- 定时刷新
这个项目给我的最大启示是:CRM系统的核心不是技术复杂度,而是对业务场景的深度理解。比如我们最初设计的客户分类维度,在实际使用中发现需要完全重构。现在系统每周都会根据业务反馈做小步迭代,这种敏捷开发模式比追求一次性完美更有效。