# 客户信息跟踪系统解决方案
## 1. 需求分析
### 1.1 功能需求
- 前端记录业务员操作事件(查看详情、编辑、跟进)
- 获取当前账号信息(公司、部门、组织、角色、姓名)
- 根据电话号码在两个数据源中查询客户
- 将操作记录写入`informationtra`表
### 1.2 数据源要求
- `wechat`数据源:`users`表和`informationtra`表
- `primary`数据源:`contacts`表
### 1.3 数据流程
1. 前端传递操作事件、电话号码、事件类型
2. 后端获取当前用户认证信息
3. 根据电话号码查询两个数据源
4. 将查询结果与认证信息结合写入`informationtra`表
## 2. 数据库设计
### 2.1 现有表结构
```sql
CREATE TABLE `informationtra` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`tracompany` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '修改者公司',
`tradepartment` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '修改者部门',
`traorganization` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '修改者组织',
`trarole` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '修改者角色',
`trauserName` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '修改者名字',
`traassistant` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '修改协助人',
`userId` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '客户ID',
`operationEvent` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '操作事件',
`operationTime` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '操作时间',
`created_at` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_userId` (`userId`),
KEY `idx_operationTime` (`operationTime`),
KEY `idx_trauserName` (`trauserName`),
CONSTRAINT `fk_informationtra_userId` FOREIGN KEY (`userId`) REFERENCES `users` (`userId`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='信息跟踪表';
```
## 3. 代码设计
### 3.1 实体类设计
#### InformationTra.java
```java
package com.example.web.entity;
import java.time.LocalDateTime;
public class InformationTra {
private Integer id;
private String tracompany;
private String tradepartment;
private String traorganization;
private String trarole;
private String trauserName;
private String traassistant;
private String userId;
private String operationEvent;
private LocalDateTime operationTime;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
// Getters and Setters
// ...
}
```
### 3.2 Mapper设计
#### InformationTraMapper.java
```java
package com.example.web.mapper;
import com.example.web.entity.InformationTra;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface InformationTraMapper {
/**
* 插入操作记录
*/
int insertInformationTra(InformationTra informationTra);
/**
* 根据userId查询操作记录
*/
InformationTra selectByUserId(@Param("userId") String userId);
}
```
#### InformationTraMapper.xml
```xml
INSERT INTO informationtra (
tracompany, tradepartment, traorganization, trarole,
trauserName, traassistant, userId, operationEvent,
operationTime, created_at, updated_at
) VALUES (
#{tracompany}, #{tradepartment}, #{traorganization}, #{trarole},
#{trauserName}, #{traassistant}, #{userId}, #{operationEvent},
#{operationTime}, #{createdAt}, #{updatedAt}
)
```
### 3.3 Service设计
#### InformationTraService.java
```java
package com.example.web.service;
import com.example.web.dto.ManagerAuthInfo;
import com.example.web.entity.InformationTra;
import com.example.web.mapper.*;
import com.example.web.config.DynamicDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
@Service
public class InformationTraService {
@Autowired
private InformationTraMapper informationTraMapper;
@Autowired
private UsersMapper usersMapper;
@Autowired
private ContactsMapper contactsMapper;
/**
* 记录操作事件
*/
public boolean recordOperationEvent(String phoneNumber, String operationEvent, ManagerAuthInfo authInfo) {
try {
// 1. 从两个数据源查询客户信息
String userId = null;
// 查询wechat数据源的users表
DynamicDataSource.setDataSourceKey("wechat");
com.example.web.entity.Users wechatUser = usersMapper.selectByPhoneNumber(phoneNumber);
if (wechatUser != null) {
userId = wechatUser.getUserId();
} else {
// 查询primary数据源的contacts表
DynamicDataSource.setDataSourceKey("primary");
com.example.web.entity.Contacts contact = contactsMapper.selectByPhoneNumber(phoneNumber);
if (contact != null) {
userId = contact.getId();
}
}
// 如果都没找到,返回失败
if (userId == null) {
return false;
}
// 2. 构造操作记录
InformationTra informationTra = new InformationTra();
informationTra.setTracompany(authInfo.getManagercompany());
informationTra.setTradepartment(authInfo.getManagerdepartment());
informationTra.setTraorganization(authInfo.getOrganization());
informationTra.setTrarole(authInfo.getRole());
informationTra.setTrauserName(authInfo.getUserName());
informationTra.setTraassistant(authInfo.getAssistant());
informationTra.setUserId(userId);
informationTra.setOperationEvent(operationEvent);
informationTra.setOperationTime(LocalDateTime.now());
informationTra.setCreatedAt(LocalDateTime.now());
informationTra.setUpdatedAt(LocalDateTime.now());
// 3. 写入wechat数据源的informationtra表
DynamicDataSource.setDataSourceKey("wechat");
int result = informationTraMapper.insertInformationTra(informationTra);
return result > 0;
} finally {
// 清除数据源标识
DynamicDataSource.clearDataSourceKey();
}
}
}
```
### 3.4 Controller设计
#### InformationTraController.java
```java
package com.example.web.controller;
import com.example.web.dto.ManagerAuthInfo;
import com.example.web.service.InformationTraService;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/api/information-tracking")
public class InformationTraController {
@Autowired
private InformationTraService informationTraService;
/**
* 记录操作事件
*/
@PostMapping("/record")
public ResponseEntity