by-crm/docs/README.md
2026-01-29 14:37:41 +08:00

770 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 泊云智销通
## 项目简介
泊云智销通是一款面向企业渠道管理的 CRM 系统,旨在解决渠道管理中的核心问题——**客户报备冲突**与**保护期归属**。系统通过唯一有效报备机制与自动到期释放机制,确保同一客户在同一时间只能被一个经销商跟进,并在保护期结束后自动回归可报备池,避免长期占坑,提升渠道效率与公平性。
### 核心价值
- **防撞单机制**:同一客户同一时间只能有一个有效报备
- **保护期管理**:自动计算和跟踪保护期,保护期到期自动释放
- **公平竞争**:避免经销商长期占用客户资源
- **全程可追溯**:所有报备记录永久保留,支持审计
---
## 技术架构
### 后端技术栈
- **框架**: Spring Boot 2.7
- **ORM**: MyBatis
- **数据库**: MySQL 8
- **安全**: Spring Security + JWT + BCrypt
- **API 文档**: Swagger
- **构建工具**: Maven
### 前端技术栈
- **框架**: Vue 3 + TypeScript
- **UI 组件**: Element Plus
- **路由**: Vue Router
- **状态管理**: Pinia
- **HTTP 客户端**: Axios
- **构建工具**: Vite
- **代码规范**: ESLint + Prettier
### 架构模式
- **前后端分离**: RESTful API 架构
- **MVC 分层**: Controller → Service → Mapper → Entity
- **数据库设计**: 遵循范式,合理使用索引
- **安全设计**: 前端 SHA-256 哈希 + 后端 BCrypt 双重加密
---
## 用户角色与权限
### 1. 管理员
**角色标识**: `role = 0`
**权限范围**:
- ✅ 客户管理(全部客户的查看、新增、编辑、删除)
- ✅ 报备管理(全部报备的查看、审核、撤回)
- ✅ 经销商管理(经销商的增删改查、重置密码)
- ✅ 系统配置(保护期天数等参数配置)
- ✅ 数据报表(经销商活跃度、客户转化率等)
- ✅ 查看所有运营数据
**主要职责**:
- 维护客户信息
- 审核报备申请
- 管理经销商账号
- 配置系统参数
- 监控渠道数据
### 2. 经销商用户
**角色标识**: `role = 1`
**权限范围**:
- ✅ 查看自己的客户列表
- ✅ 提交报备申请(选择客户进行报备)
- ✅ 查看自己的报备记录
- ✅ 撤回待审核的报备
- ✅ 查看报备审核状态
- ✅ 修改个人密码
**主要职责**:
- 报备意向客户
- 跟进保护期内的客户
- 维护客户信息
- 管理报备记录
### 权限矩阵
| 功能模块 | 管理员 | 经销商 |
|---------|--------|--------|
| 客户管理 | ✅ 全部 | ✅ 仅查看 |
| 报备管理 | ✅ 全部 | ✅ 自己的报备 |
| 报备审核 | ✅ | ❌ |
| 经销商管理 | ✅ | ❌ |
| 系统配置 | ✅ | ❌ |
| 数据报表 | ✅ | ❌ |
| 密码管理 | ✅ 自己的 | ✅ 自己的 |
---
## 功能清单
### 1. 认证与授权
#### 1.1 用户登录
- **路径**: `POST /api/auth/login`
- **描述**: 用户登录系统,获取 JWT Token
- **安全**: 前端 SHA-256 哈希 + 后端 BCrypt 加密
- **返回**: Token + 用户基本信息
**默认账号**:
- 管理员: `admin` / `admin123`
- 经销商1: `user001` / `admin123`
- 经销商2: `user002` / `admin123`
- 经销商3: `user003` / `admin123`
#### 1.2 修改密码
- **路径**: `POST /api/auth/change-password`
- **权限**: 所有用户
- **功能**: 用户修改自己的登录密码
- **验证**: 需要输入原密码验证
- **安全**: 密码 6-20 位,传输前哈希加密
#### 1.3 重置密码
- **路径**: `POST /api/auth/reset-password`
- **权限**: 仅管理员
- **功能**: 管理员重置经销商用户的密码
- **限制**: 不能重置管理员账号的密码
#### 1.4 退出登录
- **路径**: `POST /api/auth/logout`
- **功能**: 清除客户端 Token
---
### 2. 客户管理
#### 2.1 客户列表
- **路径**: `GET /api/customer/page`
- **权限**: 管理员查看全部,经销商查看全部
- **功能**: 分页查询客户信息
- **搜索字段**: 客户名称、所属行业、状态
- **状态说明**:
- `0 - 可报备`: 未被保护,可报备
- `1 - 保护中`: 正在保护期内
- `2 - 已失效`: 保护期已过
#### 2.2 新增客户
- **路径**: `POST /api/customer`
- **权限**: 仅管理员
- **功能**: 创建新客户信息
- **必填字段**: 客户名称
- **可选字段**: 联系电话、地址、所属行业
- **学校联动**: 支持从学校库自动完成选择
#### 2.3 编辑客户
- **路径**: `PUT /api/customer/{id}`
- **权限**: 仅管理员
- **功能**: 修改客户信息
#### 2.4 删除客户
- **路径**: `DELETE /api/customer/{id}`
- **权限**: 仅管理员
- **功能**: 删除客户记录
- **限制**: 有报备记录的客户需谨慎处理
#### 2.5 客户搜索
- **路径**: `GET /api/customer/search`
- **功能**: 模糊搜索客户名称(用于报备时的客户选择)
---
### 3. 报备管理
#### 3.1 报备列表
- **路径**: `GET /api/report/page`
- **权限**: 管理员查看全部,经销商查看自己的
- **功能**: 分页查询报备记录
- **状态说明**:
- `0 - 待审核`: 等待管理员审核
- `1 - 已通过`: 审核通过,保护期内
- `2 - 已驳回`: 审核未通过
- `3 - 已失效`: 保护期已过
#### 3.2 提交报备
- **路径**: `POST /api/report`
- **权限**: 经销商
- **功能**: 经销商报备意向客户
- **必填字段**: 客户ID、报备说明
- **限制**:
- 同一客户同一时间只能有一个有效报备
- 已保护的客户无法再次报备
- 待审核的报备可撤回
#### 3.3 撤回报备
- **路径**: `DELETE /api/report/{id}`
- **权限**: 报备所属经销商
- **功能**: 撤回待审核的报备申请
- **限制**: 已通过和已驳回的报备无法撤回
#### 3.4 审核报备
- **路径**: `PUT /api/report/{id}/audit`
- **权限**: 仅管理员
- **功能**: 审核报备申请
- **操作**:
- 通过设置保护期默认90天客户状态改为"保护中"
- 驳回:填写驳回原因,客户保持可报备状态
#### 3.5 报备详情
- **路径**: `GET /api/report/{id}`
- **权限**: 根据权限查看
- **功能**: 查看报备详细信息
---
### 4. 经销商管理
#### 4.1 经销商列表
- **路径**: `GET /api/dealer/list`
- **权限**: 仅管理员
- **功能**: 查询所有经销商信息
- **状态**: 启用/禁用
#### 4.2 新增经销商
- **路径**: `POST /api/dealer`
- **权限**: 仅管理员
- **必填字段**: 经销商名称、经销商账号(用作登录用户名)、联系人、联系电话
- **可选字段**: 邮箱、初始密码
- **自动创建**:
- 创建经销商记录
- 创建对应的登录用户
- 用户名 = 经销商账号
- 默认密码 = 123456可自定义
#### 4.3 编辑经销商
- **路径**: `PUT /api/dealer/{id}`
- **权限**: 仅管理员
- **功能**: 修改经销商信息
#### 4.4 删除经销商
- **路径**: `DELETE /api/dealer/{id}`
- **权限**: 仅管理员
- **功能**: 删除经销商及其关联用户
#### 4.5 重置密码
- **路径**: `POST /api/auth/reset-password`
- **权限**: 仅管理员
- **功能**: 重置经销商用户的登录密码
---
### 5. 学校管理
#### 5.1 学校列表
- **路径**: `GET /api/school/list`
- **权限**: 所有用户
- **功能**: 查询所有学校信息
#### 5.2 学校搜索
- **路径**: `GET /api/school/search?keyword=xxx`
- **权限**: 所有用户
- **功能**: 模糊搜索学校名称(用于客户名称自动完成)
- **应用场景**: 新增客户时,输入学校名称,自动匹配学校库
#### 5.3 批量导入学校
- **路径**: `POST /api/school/import`
- **权限**: 仅管理员
- **功能**: 上传 Excel 文件批量导入学校数据
- **文件格式**: `.xls``.xlsx`
#### 5.4 从 docs 目录导入
- **路径**: `POST /api/school/import-from-docs`
- **权限**: 仅管理员
- **功能**: 直接导入项目 docs 目录下的 `school.xls` 文件
**学校数据结构**:
- 学校标识码
- 学校名称
- 所在地(省份 + 城市)
---
### 6. 系统配置
#### 6.1 保护期配置
- **配置项**: `report.protect.days`
- **默认值**: `90`
- **说明**: 控制报备通过后的保护期时长
- **影响**:
- 保护期计算
- 自动失效定时任务
#### 6.2 报备冲突控制
- **配置项**: `report.allow-overlap`
- **默认值**: `false`
- **说明**: 是否允许同一客户的报备重叠(仅用于测试)
- **生产**: 必须为 `false`
---
## 业务流程
### 报备生命周期
```
┌─────────────────────────────────────────────────────────────┐
│ 报备完整流程 │
└─────────────────────────────────────────────────────────────┘
1. 经销商提交报备
├─ 选择客户(只能选择"可报备"状态的客户)
├─ 填写报备说明
└─ 提交审核
状态:待审核(0)
客户状态:可报备(0)
2. 管理员审核
├─ 通过 → 设置保护期如90天
│ ├─ 报备状态:已通过(1)
│ └─ 客户状态:保护中(1)
└─ 驳回 → 填写驳回原因
├─ 报备状态:已驳回(2)
└─ 客户状态:可报备(0)
3. 保护期内
├─ 客户被锁定,其他经销商无法报备
├─ 原报备经销商可跟进客户
└─ 剩余保护天数倒计时
4. 保护期到期(定时任务)
└─ 每天凌晨1点自动执行
├─ 报备状态:已通过 → 已失效(3)
└─ 客户状态:保护中 → 可报备(0)
5. 客户释放
└─ 所有经销商可再次报备该客户
```
### 客户状态流转
```
可报备(0) ──[提交报备]──> 锁定(其他经销商不可报备)
[管理员审核通过]
保护中(1) ──[90天后]──> 可报备(0)
[报备被驳回]
[管理员驳回]
可报备(0)
```
---
## 数据库设计
### 核心表结构
#### 1. 客户表 (crm_customer)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | BIGINT | 客户ID主键 |
| name | VARCHAR(200) | 客户名称 |
| phone | VARCHAR(20) | 联系电话 |
| address | VARCHAR(500) | 地址 |
| industry | VARCHAR(50) | 所属行业 |
| status | TINYINT | 状态0-可报备 1-保护中 2-已失效 |
| current_dealer_id | BIGINT | 当前报备经销商ID |
| protect_end_date | DATE | 保护期结束日期 |
| created_at | DATETIME | 创建时间 |
| updated_at | DATETIME | 更新时间 |
#### 2. 报备表 (crm_report)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | BIGINT | 报备ID主键 |
| dealer_id | BIGINT | 经销商ID |
| customer_id | BIGINT | 客户ID |
| description | VARCHAR(500) | 报备说明 |
| status | TINYINT | 状态0-待审核 1-已通过 2-已驳回 3-已失效 |
| reject_reason | VARCHAR(255) | 驳回原因 |
| protect_start_date | DATE | 保护期开始日期 |
| protect_end_date | DATE | 保护期结束日期 |
| created_at | DATETIME | 创建时间 |
| updated_at | DATETIME | 更新时间 |
**唯一索引**: `uk_customer_valid (customer_id, status)` - 同一客户只能有一个有效报备
#### 3. 经销商表 (crm_dealer)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | BIGINT | 经销商ID主键 |
| name | VARCHAR(200) | 经销商名称 |
| code | VARCHAR(50) | 经销商账号(唯一) |
| contact_person | VARCHAR(50) | 联系人 |
| contact_phone | VARCHAR(20) | 联系电话 |
| email | VARCHAR(100) | 邮箱 |
| status | TINYINT | 状态0-禁用 1-启用 |
| created_at | DATETIME | 创建时间 |
| updated_at | DATETIME | 更新时间 |
#### 4. 用户表 (crm_user)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | BIGINT | 用户ID主键 |
| username | VARCHAR(50) | 用户名(登录账号) |
| password | VARCHAR(255) | 密码BCrypt加密 |
| real_name | VARCHAR(50) | 真实姓名 |
| dealer_id | BIGINT | 关联经销商ID管理员为NULL |
| role | TINYINT | 角色0-管理员 1-经销商用户 |
| status | TINYINT | 状态0-禁用 1-启用 |
| created_at | DATETIME | 创建时间 |
| updated_at | DATETIME | 更新时间 |
#### 5. 学校表 (crm_school)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | BIGINT | 学校ID主键 |
| school_code | VARCHAR(50) | 学校标识码(唯一) |
| school_name | VARCHAR(200) | 学校名称 |
| location | VARCHAR(255) | 所在地(省份+城市) |
| created_at | DATETIME | 创建时间 |
| updated_at | DATETIME | 更新时间 |
---
## 定时任务
### 报备过期处理
**执行时间**: 每天凌晨 1 点
**Cron 表达式**: `0 0 1 * * ?`
**功能**:
1. 查询所有保护期已到的报备(`protect_end_date <= 今天` 且 `status = 1`
2. 批量更新报备状态为"已失效"`status = 3`
3. 批量更新关联客户状态为"可报备"`status = 0`
4. 保证渠道资源公平分配
---
## 安全机制
### 1. 认证与授权
#### JWT Token 认证
- 用户登录后获取 JWT Token
- Token 包含用户ID、用户名、角色、经销商ID
- Token 存储在客户端 `localStorage`
- 每次请求在 Header 中携带:`Authorization: Bearer {token}`
#### 权限拦截
- 前端路由守卫:未登录重定向到登录页
- 后端拦截器:验证 Token 有效性
- 接口权限注解:`@AuthRequired`
- 数据权限:经销商只能查看自己的报备
### 2. 密码安全
#### 双重加密
```
用户输入 → [前端 SHA-256 哈希] → HTTPS 传输 → [后端 BCrypt 加密] → 存储
```
#### 密码规则
- 长度6-20 位
- 加密BCrypt自动加盐
- 传输SHA-256 哈希后传输
- 修改密码:需验证原密码
### 3. 数据安全
#### SQL 注入防护
- 使用 MyBatis 参数化查询
- 所有用户输入都经过参数绑定
#### XSS 防护
- 前端输出自动转义
- 后端返回 JSON 格式
#### CSRF 防护
- 使用 JWT 无状态认证
- 不依赖 Session Cookie
---
## 项目结构
```
by-crm/
├── backend/ # 后端工程
│ ├── src/main/java/com/bycrm/
│ │ ├── annotations/ # 自定义注解(权限等)
│ │ ├── common/ # 公共类Result、Constants等
│ │ ├── config/ # 配置类CORS、MyBatis、Swagger等
│ │ ├── controller/ # 控制器层
│ │ │ ├── AuthController.java
│ │ │ ├── CustomerController.java
│ │ │ ├── ReportController.java
│ │ │ ├── DealerController.java
│ │ │ └── SchoolController.java
│ │ ├── dto/ # 数据传输对象
│ │ ├── entity/ # 实体类
│ │ ├── exception/ # 异常处理
│ │ ├── mapper/ # MyBatis Mapper 接口
│ │ ├── service/ # 业务逻辑层
│ │ ├── task/ # 定时任务
│ │ ├── util/ # 工具类JWT、加密等
│ │ ├── vo/ # 视图对象
│ │ └── ByCrmApplication.java
│ ├── src/main/resources/
│ │ ├── mapper/*.xml # MyBatis SQL 映射
│ │ └── application.yml # 配置文件
│ └── pom.xml # Maven 依赖
├── frontend/ # 前端工程
│ ├── src/
│ │ ├── api/ # API 接口封装
│ │ ├── assets/ # 静态资源
│ │ ├── components/ # 通用组件
│ │ ├── router/ # Vue Router 配置
│ │ ├── stores/ # Pinia 状态管理
│ │ ├── types/ # TypeScript 类型定义
│ │ ├── utils/ # 工具函数(请求、加密等)
│ │ ├── views/ # 页面组件
│ │ │ ├── Login.vue # 登录页
│ │ │ ├── Layout.vue # 主布局
│ │ │ ├── Dashboard.vue # 首页
│ │ │ ├── Customer.vue # 客户管理
│ │ │ ├── Report.vue # 报备管理
│ │ │ └── Dealer.vue # 经销商管理
│ │ ├── App.vue # 根组件
│ │ └── main.ts # 入口文件
│ ├── vite.config.ts # Vite 配置
│ ├── package.json # 依赖配置
│ └── tsconfig.json # TS 配置
├── sql/ # 数据库脚本
│ ├── init.sql # 初始化脚本
│ ├── school_table.sql # 学校表
│ └── *.sql # 其他 SQL 脚本
└── docs/ # 文档目录
├── api.md # API 文档Swagger 导出)
└── password-security.md # 密码安全说明
```
---
## 环境配置
### 后端配置 (application.yml)
```yaml
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/by_crm
username: root
password: your_password
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.bycrm.entity
# JWT 配置
jwt:
secret: your-secret-key
expiration: 86400000 # 24小时毫秒
# 保护期配置
crm:
report:
ttl-days: 90 # 保护期天数默认90天
allow-overlap: false # 是否允许报备重叠测试用生产必须false
```
### 前端配置
```typescript
// API 基础地址
const BASE_URL = 'http://localhost:8080/api'
// Token 存储
const TOKEN_KEY = 'token'
// 路由模式history 或 hash
const routerMode = 'history'
```
---
## 部署说明
### 开发环境启动
**后端**:
```bash
cd backend
mvn spring-boot:run
# 访问: http://localhost:8080
# Swagger: http://localhost:8080/swagger-ui.html
```
**前端**:
```bash
cd frontend
pnpm install
pnpm dev
# 访问: http://localhost:5173
```
### 生产环境部署
**后端**:
```bash
# 编译打包
mvn clean package
# 运行 JAR
java -jar target/bycrm-0.0.1-SNAPSHOT.jar
```
**前端**:
```bash
# 编译打包
pnpm build
# 部署 dist 目录到 Web 服务器
```
### 数据库初始化
```bash
# 创建数据库
mysql -u root -p -e "CREATE DATABASE by_crm CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"
# 导入初始化脚本
mysql -u root -p by_crm < sql/init.sql
```
---
## API 接口清单
### 认证接口
- `POST /api/auth/login` - 用户登录
- `GET /api/auth/user/info` - 获取当前用户信息
- `POST /api/auth/logout` - 用户退出
- `POST /api/auth/change-password` - 修改密码
- `POST /api/auth/reset-password` - 重置密码
### 客户接口
- `GET /api/customer/page` - 分页查询客户
- `GET /api/customer/{id}` - 获取客户详情
- `POST /api/customer` - 创建客户
- `PUT /api/customer/{id}` - 更新客户
- `DELETE /api/customer/{id}` - 删除客户
- `GET /api/customer/search?keyword=xxx` - 搜索客户
### 报备接口
- `GET /api/report/page` - 分页查询报备
- `GET /api/report/{id}` - 获取报备详情
- `POST /api/report` - 创建报备
- `DELETE /api/report/{id}` - 撤回报备
- `PUT /api/report/{id}/audit` - 审核报备
### 经销商接口(仅管理员)
- `GET /api/dealer/list` - 查询所有经销商
- `POST /api/dealer` - 创建经销商
- `PUT /api/dealer/{id}` - 更新经销商
- `DELETE /api/dealer/{id}` - 删除经销商
### 学校接口
- `GET /api/school/list` - 查询所有学校
- `GET /api/school/search?keyword=xxx` - 搜索学校
- `POST /api/school` - 创建学校
- `POST /api/school/import` - 文件上传导入
- `POST /api/school/import-from-docs` - 从 docs 目录导入
---
## 版本历史
### v1.0.0 (当前版本)
**新增功能**:
- ✅ 客户管理(增删改查)
- ✅ 报备管理(提交、审核、撤回)
- ✅ 经销商管理(增删改查、重置密码)
- ✅ 学校管理(查询、搜索、导入)
- ✅ 用户认证(登录、密码管理)
- ✅ 自动保护期到期处理
- ✅ 学校数据自动完成功能
- ✅ 密码传输加密SHA-256 + BCrypt 双重加密)
**安全特性**:
- ✅ JWT Token 认证
- ✅ BCrypt 密码加密存储
- ✅ SHA-256 前端哈希传输
- ✅ 权限注解拦截
- ✅ SQL 注入防护
- ✅ XSS 防护
---
## 常见问题
### 1. 默认密码是什么?
- 新增经销商时,如果不设置初始密码,默认为 `123456`
- 管理员账号:`admin` / `admin123`
- 经销商账号:`user001~003` / `admin123`
### 2. 保护期可以修改吗?
- 可以,通过修改系统配置 `report.protect.days`
- 默认为 90 天,可根据业务需求调整
### 3. 同一客户可以同时被多个经销商报备吗?
- **不可以**,这是系统的核心规则
- 同一时间只能有一个"已通过"的报备
- 其他经销商报备该客户会被拒绝
### 4. 保护期到期后会发生什么?
- 定时任务每天凌晨1点自动执行
- 将过期报备状态改为"已失效"
- 客户状态自动变为"可报备"
- 其他经销商可以再次报备
### 5. 如何确保传输安全?
- 前端:使用 Web Crypto API 进行 SHA-256 哈希
- 传输HTTPS + 哈希后的密码
- 后端BCrypt 二次加密存储
- 三重安全保障
### 6. 管理员可以重置其他管理员密码吗?
- **不可以**,只能重置经销商用户的密码
- 管理员修改自己的密码通过"修改密码"功能
### 7. 学校数据从哪里来?
- 存放在 `docs/school.xls` 文件中
- 包含:学校标识码、学校名称、所在地
- 可通过 API 导入到数据库
---
## 技术支持
### 开发团队
- 后端开发Spring Boot + MyBatis + MySQL
- 前端开发Vue 3 + TypeScript + Element Plus
- 项目管理Maven + pnpm
### 联系方式
- 问题反馈:提交 Issue 到项目仓库
- 技术文档:详见 `docs/` 目录
---
**版权声明**: 本系统为企业内部使用,未经授权不得复制或传播。