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