15 changed files with 1618 additions and 17 deletions
@ -0,0 +1,377 @@ |
|||
# 客户信息跟踪系统解决方案 |
|||
|
|||
## 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 |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
|||
<mapper namespace="com.example.web.mapper.InformationTraMapper"> |
|||
|
|||
<resultMap id="informationTraMap" type="com.example.web.entity.InformationTra"> |
|||
<id property="id" column="id"/> |
|||
<result property="tracompany" column="tracompany"/> |
|||
<result property="tradepartment" column="tradepartment"/> |
|||
<result property="traorganization" column="traorganization"/> |
|||
<result property="trarole" column="trarole"/> |
|||
<result property="trauserName" column="trauserName"/> |
|||
<result property="traassistant" column="traassistant"/> |
|||
<result property="userId" column="userId"/> |
|||
<result property="operationEvent" column="operationEvent"/> |
|||
<result property="operationTime" column="operationTime"/> |
|||
<result property="createdAt" column="created_at"/> |
|||
<result property="updatedAt" column="updated_at"/> |
|||
</resultMap> |
|||
|
|||
<insert id="insertInformationTra" parameterType="com.example.web.entity.InformationTra"> |
|||
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} |
|||
) |
|||
</insert> |
|||
|
|||
<select id="selectByUserId" resultMap="informationTraMap"> |
|||
SELECT * FROM informationtra WHERE userId = #{userId} |
|||
</select> |
|||
</mapper> |
|||
``` |
|||
|
|||
### 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<Map<String, Object>> recordOperationEvent( |
|||
@RequestBody Map<String, String> requestBody, |
|||
HttpServletRequest request) { |
|||
|
|||
Map<String, Object> response = new HashMap<>(); |
|||
|
|||
try { |
|||
// 获取请求参数 |
|||
String phoneNumber = requestBody.get("phoneNumber"); |
|||
String operationEvent = requestBody.get("operationEvent"); |
|||
|
|||
// 验证参数 |
|||
if (phoneNumber == null || phoneNumber.isEmpty() || operationEvent == null || operationEvent.isEmpty()) { |
|||
response.put("success", false); |
|||
response.put("message", "电话号码和操作事件不能为空"); |
|||
return ResponseEntity.badRequest().body(response); |
|||
} |
|||
|
|||
// 获取当前用户认证信息 |
|||
String isSupplySideParam = request.getParameter("isSupplySide"); |
|||
boolean isSupplySide = !"false".equalsIgnoreCase(isSupplySideParam); |
|||
|
|||
ManagerAuthInfo authInfo = null; |
|||
if (isSupplySide) { |
|||
// 供应端获取认证信息的逻辑 |
|||
authInfo = getManagerAuthInfoFromRequest(request, true); |
|||
} else { |
|||
// 销售端获取认证信息的逻辑 |
|||
authInfo = getManagerAuthInfoFromRequest(request, false); |
|||
} |
|||
|
|||
if (authInfo == null) { |
|||
response.put("success", false); |
|||
response.put("message", "用户未登录或认证信息缺失"); |
|||
return ResponseEntity.status(401).body(response); |
|||
} |
|||
|
|||
// 记录操作事件 |
|||
boolean success = informationTraService.recordOperationEvent(phoneNumber, operationEvent, authInfo); |
|||
|
|||
if (success) { |
|||
response.put("success", true); |
|||
response.put("message", "操作记录成功"); |
|||
return ResponseEntity.ok(response); |
|||
} else { |
|||
response.put("success", false); |
|||
response.put("message", "未找到对应的客户信息"); |
|||
return ResponseEntity.badRequest().body(response); |
|||
} |
|||
|
|||
} catch (Exception e) { |
|||
response.put("success", false); |
|||
response.put("message", "记录操作事件失败: " + e.getMessage()); |
|||
return ResponseEntity.internalServerError().body(response); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 从请求中获取认证信息(复用现有逻辑) |
|||
*/ |
|||
private ManagerAuthInfo getManagerAuthInfoFromRequest(HttpServletRequest request, boolean isSupplySide) { |
|||
// 复用SupplyCustomerController或CustomerController中的现有逻辑 |
|||
// 这里需要根据实际情况实现 |
|||
return null; |
|||
} |
|||
} |
|||
``` |
|||
|
|||
### 3.5 前端调用示例 |
|||
|
|||
```javascript |
|||
// 前端调用API示例 |
|||
function recordOperation(phoneNumber, operationEvent) { |
|||
fetch('/api/information-tracking/record?isSupplySide=true', { |
|||
method: 'POST', |
|||
headers: { |
|||
'Content-Type': 'application/json' |
|||
}, |
|||
body: JSON.stringify({ |
|||
phoneNumber: phoneNumber, |
|||
operationEvent: operationEvent |
|||
}) |
|||
}) |
|||
.then(response => response.json()) |
|||
.then(data => { |
|||
if (data.success) { |
|||
console.log('操作记录成功'); |
|||
} else { |
|||
console.error('操作记录失败:', data.message); |
|||
} |
|||
}) |
|||
.catch(error => { |
|||
console.error('API调用失败:', error); |
|||
}); |
|||
} |
|||
|
|||
// 查看客户详情时调用 |
|||
recordOperation('13800138000', '查看客户详情'); |
|||
|
|||
// 编辑客户信息后调用 |
|||
recordOperation('13800138000', '修改客户信息'); |
|||
|
|||
// 跟进客户后调用 |
|||
recordOperation('13800138000', '更新客户跟进'); |
|||
``` |
|||
|
|||
## 4. 实现步骤 |
|||
|
|||
1. 创建InformationTra实体类 |
|||
2. 创建InformationTraMapper接口和XML文件 |
|||
3. 创建InformationTraService |
|||
4. 创建InformationTraController |
|||
5. 在前端页面添加API调用逻辑 |
|||
6. 测试功能完整性 |
|||
|
|||
## 5. 注意事项 |
|||
|
|||
1. 确保数据源切换正确,避免数据查询错误 |
|||
2. 验证电话号码格式,确保查询准确性 |
|||
3. 处理并发情况,确保操作记录的完整性 |
|||
4. 添加适当的日志记录,便于调试和监控 |
|||
5. 考虑添加权限控制,确保只有授权用户可以调用API |
|||
|
|||
## 6. 扩展建议 |
|||
|
|||
1. 添加操作记录查询功能,便于查看历史操作 |
|||
2. 实现操作记录统计分析,提供数据可视化 |
|||
3. 添加操作记录导出功能,支持Excel或PDF格式 |
|||
4. 实现操作记录告警功能,对异常操作进行告警 |
|||
5. 添加操作记录审计功能,满足合规要求 |
|||
@ -0,0 +1,183 @@ |
|||
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.HttpStatus; |
|||
import org.springframework.http.ResponseEntity; |
|||
import org.springframework.web.bind.annotation.PostMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
|
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
|
|||
/** |
|||
* 信息操作记录控制器 |
|||
* 处理前端操作记录请求,包括查看客户详情、修改客户信息、更新客户跟进等操作 |
|||
*/ |
|||
@RestController |
|||
@RequestMapping("/api/info-tracking") |
|||
public class InformationTraController { |
|||
|
|||
@Autowired |
|||
private InformationTraService informationTraService; |
|||
|
|||
/** |
|||
* 记录操作事件 |
|||
* @param request HttpServletRequest对象,包含操作信息和认证信息 |
|||
* @return ResponseEntity<Map<String, Object>> 响应结果 |
|||
*/ |
|||
@PostMapping("/record") |
|||
public ResponseEntity<Map<String, Object>> recordOperation(HttpServletRequest request) { |
|||
Map<String, Object> result = new HashMap<>(); |
|||
try { |
|||
// 获取操作类型
|
|||
String operationType = request.getParameter("operationType"); |
|||
// 获取电话号码
|
|||
String phoneNumber = request.getParameter("phoneNumber"); |
|||
// 获取客户名称
|
|||
String customerName = request.getParameter("customerName"); |
|||
|
|||
// 验证必要参数
|
|||
if (operationType == null || operationType.trim().isEmpty()) { |
|||
result.put("success", false); |
|||
result.put("message", "操作类型不能为空"); |
|||
return new ResponseEntity<>(result, HttpStatus.BAD_REQUEST); |
|||
} |
|||
if (phoneNumber == null || phoneNumber.trim().isEmpty()) { |
|||
result.put("success", false); |
|||
result.put("message", "电话号码不能为空"); |
|||
return new ResponseEntity<>(result, HttpStatus.BAD_REQUEST); |
|||
} |
|||
|
|||
// 获取认证信息
|
|||
ManagerAuthInfo authInfo = getManagerAuthInfoFromRequest(request, false); // 默认销售端,后续根据部门自动调整
|
|||
if (authInfo == null) { |
|||
result.put("success", false); |
|||
result.put("message", "获取认证信息失败"); |
|||
return new ResponseEntity<>(result, HttpStatus.UNAUTHORIZED); |
|||
} |
|||
|
|||
// 记录操作事件
|
|||
boolean success = informationTraService.recordOperationEvent( |
|||
phoneNumber, |
|||
customerName != null ? customerName : "", |
|||
operationType, |
|||
authInfo.getManagercompany(), |
|||
authInfo.getManagerdepartment(), |
|||
authInfo.getOrganization(), |
|||
authInfo.getRole(), |
|||
authInfo.getUserName(), |
|||
authInfo.getAssistant() |
|||
); |
|||
|
|||
if (success) { |
|||
result.put("success", true); |
|||
result.put("message", "操作记录成功"); |
|||
return new ResponseEntity<>(result, HttpStatus.OK); |
|||
} else { |
|||
result.put("success", false); |
|||
result.put("message", "操作记录失败"); |
|||
return new ResponseEntity<>(result, HttpStatus.INTERNAL_SERVER_ERROR); |
|||
} |
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
result.put("success", false); |
|||
result.put("message", "操作记录异常: " + e.getMessage()); |
|||
return new ResponseEntity<>(result, HttpStatus.INTERNAL_SERVER_ERROR); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 从请求中获取管理员认证信息 |
|||
* @param request HttpServletRequest对象 |
|||
* @param isSupplySide 是否为采购端 |
|||
* @return ManagerAuthInfo 认证信息对象 |
|||
*/ |
|||
private ManagerAuthInfo getManagerAuthInfoFromRequest(HttpServletRequest request, boolean isSupplySide) { |
|||
String managerId = request.getParameter("managerId"); |
|||
String managercompany = request.getParameter("company"); |
|||
String managerdepartment = request.getParameter("department"); |
|||
String organization = request.getParameter("organization"); |
|||
String role = request.getParameter("role"); |
|||
String userName = request.getParameter("userName"); |
|||
String assistant = request.getParameter("assistant"); |
|||
|
|||
// URL解码参数
|
|||
try { |
|||
if (managerId != null) managerId = java.net.URLDecoder.decode(managerId, "UTF-8"); |
|||
if (managercompany != null) managercompany = java.net.URLDecoder.decode(managercompany, "UTF-8"); |
|||
if (managerdepartment != null) managerdepartment = java.net.URLDecoder.decode(managerdepartment, "UTF-8"); |
|||
if (organization != null) organization = java.net.URLDecoder.decode(organization, "UTF-8"); |
|||
if (role != null) role = java.net.URLDecoder.decode(role, "UTF-8"); |
|||
if (userName != null) userName = java.net.URLDecoder.decode(userName, "UTF-8"); |
|||
if (assistant != null) assistant = java.net.URLDecoder.decode(assistant, "UTF-8"); |
|||
} catch (java.io.UnsupportedEncodingException e) { |
|||
System.err.println("URL解码失败: " + e.getMessage()); |
|||
} |
|||
|
|||
// 检查必要参数
|
|||
if (userName == null || userName.trim().isEmpty()) { |
|||
System.out.println("❌ 用户名为空,无法获取认证信息"); |
|||
return null; |
|||
} |
|||
|
|||
// 部门检查
|
|||
if (managerdepartment == null) { |
|||
System.out.println("⚠️ 部门信息为空,使用默认值"); |
|||
managerdepartment = ""; |
|||
} |
|||
|
|||
// 智能判断实际端类型:根据部门信息自动调整isSupplySide值
|
|||
boolean actualIsSupplySide = isSupplySide; |
|||
if (managerdepartment.contains("销售")) { |
|||
actualIsSupplySide = false; // 销售部门自动判定为销售端
|
|||
System.out.println("🔄 部门包含'销售',自动调整为销售端"); |
|||
} else if (managerdepartment.contains("采购")) { |
|||
actualIsSupplySide = true; // 采购部门自动判定为采购端
|
|||
System.out.println("🔄 部门包含'采购',自动调整为采购端"); |
|||
} |
|||
|
|||
System.out.println("🔍 认证信息检查,实际端类型: " + (actualIsSupplySide ? "采购端" : "销售端") + |
|||
",部门: '" + managerdepartment + "'"); |
|||
System.out.println("✅ 认证信息检查通过"); |
|||
|
|||
// 验证公司信息一致性
|
|||
if (managercompany == null || managercompany.trim().isEmpty()) { |
|||
System.out.println("❌ 公司信息为空"); |
|||
return null; |
|||
} |
|||
|
|||
ManagerAuthInfo authInfo = new ManagerAuthInfo( |
|||
managerId != null ? managerId : "", |
|||
managercompany != null ? managercompany : "", |
|||
managerdepartment != null ? managerdepartment : "", |
|||
organization != null ? organization : "", |
|||
role != null ? role : "", |
|||
userName, |
|||
assistant != null ? assistant : ""); |
|||
|
|||
// 设置实际的端类型
|
|||
try { |
|||
// 尝试通过反射或setter方法设置supplySide属性
|
|||
java.lang.reflect.Field field = authInfo.getClass().getDeclaredField("supplySide"); |
|||
field.setAccessible(true); |
|||
field.set(authInfo, actualIsSupplySide); |
|||
} catch (Exception e) { |
|||
System.out.println("ℹ️ 无法设置supplySide属性: " + e.getMessage()); |
|||
} |
|||
|
|||
System.out.println("🎯 认证信息详情: " + |
|||
"系统类型=" + (actualIsSupplySide ? "采购端" : "销售端") + |
|||
", 公司=" + authInfo.getManagercompany() + |
|||
", 部门=" + authInfo.getManagerdepartment() + |
|||
", 组织=" + authInfo.getOrganization() + |
|||
", 角色=" + authInfo.getRole() + |
|||
", 负责人=" + authInfo.getUserName() + |
|||
", 协助人=" + authInfo.getAssistant()); |
|||
|
|||
return authInfo; |
|||
} |
|||
} |
|||
@ -0,0 +1,115 @@ |
|||
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
|
|||
public Integer getId() { |
|||
return id; |
|||
} |
|||
|
|||
public void setId(Integer id) { |
|||
this.id = id; |
|||
} |
|||
|
|||
public String getTracompany() { |
|||
return tracompany; |
|||
} |
|||
|
|||
public void setTracompany(String tracompany) { |
|||
this.tracompany = tracompany; |
|||
} |
|||
|
|||
public String getTradepartment() { |
|||
return tradepartment; |
|||
} |
|||
|
|||
public void setTradepartment(String tradepartment) { |
|||
this.tradepartment = tradepartment; |
|||
} |
|||
|
|||
public String getTraorganization() { |
|||
return traorganization; |
|||
} |
|||
|
|||
public void setTraorganization(String traorganization) { |
|||
this.traorganization = traorganization; |
|||
} |
|||
|
|||
public String getTrarole() { |
|||
return trarole; |
|||
} |
|||
|
|||
public void setTrarole(String trarole) { |
|||
this.trarole = trarole; |
|||
} |
|||
|
|||
public String getTrauserName() { |
|||
return trauserName; |
|||
} |
|||
|
|||
public void setTrauserName(String trauserName) { |
|||
this.trauserName = trauserName; |
|||
} |
|||
|
|||
public String getTraassistant() { |
|||
return traassistant; |
|||
} |
|||
|
|||
public void setTraassistant(String traassistant) { |
|||
this.traassistant = traassistant; |
|||
} |
|||
|
|||
public String getUserId() { |
|||
return userId; |
|||
} |
|||
|
|||
public void setUserId(String userId) { |
|||
this.userId = userId; |
|||
} |
|||
|
|||
public String getOperationEvent() { |
|||
return operationEvent; |
|||
} |
|||
|
|||
public void setOperationEvent(String operationEvent) { |
|||
this.operationEvent = operationEvent; |
|||
} |
|||
|
|||
public LocalDateTime getOperationTime() { |
|||
return operationTime; |
|||
} |
|||
|
|||
public void setOperationTime(LocalDateTime operationTime) { |
|||
this.operationTime = operationTime; |
|||
} |
|||
|
|||
public LocalDateTime getCreatedAt() { |
|||
return createdAt; |
|||
} |
|||
|
|||
public void setCreatedAt(LocalDateTime createdAt) { |
|||
this.createdAt = createdAt; |
|||
} |
|||
|
|||
public LocalDateTime getUpdatedAt() { |
|||
return updatedAt; |
|||
} |
|||
|
|||
public void setUpdatedAt(LocalDateTime updatedAt) { |
|||
this.updatedAt = updatedAt; |
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
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); |
|||
} |
|||
@ -0,0 +1,105 @@ |
|||
package com.example.web.service; |
|||
|
|||
import com.example.web.dto.UserProductCartDTO; |
|||
import com.example.web.entity.Contacts; |
|||
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 customerName, String operationEvent, |
|||
String managerCompany, String managerDepartment, String organization, |
|||
String role, String userName, String assistant) { |
|||
// 保存原始数据源,以便在finally块中恢复
|
|||
String originalDataSource = DynamicDataSource.getCurrentDataSourceKey(); |
|||
try { |
|||
// 1. 从两个数据源查询客户信息
|
|||
String userId = null; |
|||
|
|||
// 查询wechat数据源的users表
|
|||
DynamicDataSource.setDataSourceKey("wechat"); |
|||
UserProductCartDTO wechatUser = usersMapper.selectByPhone(phoneNumber); |
|||
|
|||
if (wechatUser != null) { |
|||
userId = wechatUser.getUserId(); |
|||
System.out.println("ℹ️ 从wechat数据源获取到userId: " + userId); |
|||
} else { |
|||
System.out.println("ℹ️ 在wechat数据源中未找到客户"); |
|||
// 查询primary数据源的contacts表
|
|||
DynamicDataSource.setDataSourceKey("primary"); |
|||
Contacts contact = contactsMapper.selectByPhoneNumber(phoneNumber); |
|||
|
|||
if (contact != null) { |
|||
System.out.println("✅ 在primary数据源中找到客户: " + contact.getNickName()); |
|||
userId = contact.getId(); |
|||
System.out.println("ℹ️ 使用primary数据源的contact.id作为userId: " + userId); |
|||
} |
|||
} |
|||
|
|||
// 如果都没找到,返回失败
|
|||
if (userId == null) { |
|||
System.err.println("❌ 无法获取客户ID,操作记录失败"); |
|||
return false; |
|||
} |
|||
|
|||
// 2. 获取当前时间
|
|||
LocalDateTime now = LocalDateTime.now(); |
|||
|
|||
// 3. 构造操作记录
|
|||
InformationTra informationTra = new InformationTra(); |
|||
informationTra.setTracompany(managerCompany); |
|||
informationTra.setTradepartment(managerDepartment); |
|||
informationTra.setTraorganization(organization); |
|||
informationTra.setTrarole(role); |
|||
informationTra.setTrauserName(userName); |
|||
informationTra.setTraassistant(assistant); |
|||
informationTra.setUserId(userId); |
|||
informationTra.setOperationEvent(operationEvent); |
|||
informationTra.setOperationTime(now); |
|||
informationTra.setCreatedAt(now); |
|||
informationTra.setUpdatedAt(now); |
|||
|
|||
// 4. 始终写入wechat数据源的informationtra表
|
|||
DynamicDataSource.setDataSourceKey("wechat"); |
|||
System.out.println("🔄 设置数据源为wechat,准备插入信息跟踪记录"); |
|||
int result = informationTraMapper.insertInformationTra(informationTra); |
|||
if (result > 0) { |
|||
System.out.println("✅ 插入信息跟踪记录成功,影响行数: " + result); |
|||
return true; |
|||
} else { |
|||
System.err.println("❌ 插入信息跟踪记录失败,影响行数: " + result); |
|||
return false; |
|||
} |
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
System.err.println("❌ 操作记录异常: " + e.getMessage()); |
|||
return false; |
|||
} finally { |
|||
// 恢复原始数据源,避免线程池复用问题
|
|||
if (originalDataSource != null) { |
|||
DynamicDataSource.setDataSourceKey(originalDataSource); |
|||
} else { |
|||
DynamicDataSource.clearDataSourceKey(); |
|||
} |
|||
System.out.println("🔄 恢复数据源为原始值: " + (originalDataSource != null ? originalDataSource : "默认数据源")); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
|||
<mapper namespace="com.example.web.mapper.InformationTraMapper"> |
|||
|
|||
<resultMap id="informationTraMap" type="com.example.web.entity.InformationTra"> |
|||
<id property="id" column="id"/> |
|||
<result property="tracompany" column="tracompany"/> |
|||
<result property="tradepartment" column="tradepartment"/> |
|||
<result property="traorganization" column="traorganization"/> |
|||
<result property="trarole" column="trarole"/> |
|||
<result property="trauserName" column="trauserName"/> |
|||
<result property="traassistant" column="traassistant"/> |
|||
<result property="userId" column="userId"/> |
|||
<result property="operationEvent" column="operationEvent"/> |
|||
<result property="operationTime" column="operationTime"/> |
|||
<result property="createdAt" column="created_at"/> |
|||
<result property="updatedAt" column="updated_at"/> |
|||
</resultMap> |
|||
|
|||
<insert id="insertInformationTra" parameterType="com.example.web.entity.InformationTra"> |
|||
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} |
|||
) |
|||
</insert> |
|||
|
|||
<select id="selectByUserId" resultMap="informationTraMap"> |
|||
SELECT * FROM informationtra WHERE userId = #{userId} |
|||
</select> |
|||
</mapper> |
|||
Loading…
Reference in new issue