Browse Source

更新代码 - Boss使用覆盖原有代码

master
Trae AI 2 months ago
parent
commit
8a8424e983
  1. 93
      src/main/java/com/example/web/service/CustomerChangeMonitorService.java
  2. 42
      src/main/java/com/example/web/service/impl/CustomerServiceImpl.java
  3. 85
      src/main/resources/static/sells.html
  4. 80
      src/main/resources/static/supply.html

93
src/main/java/com/example/web/service/CustomerChangeMonitorService.java

@ -0,0 +1,93 @@
package com.example.web.service;
import com.example.web.entity.CustomerData;
import com.example.web.entity.Login;
import com.example.web.dto.NotificationDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 客户数据变化监控服务
* 用于监控数据库中客户数据的变化当管理员在外部系统修改客户数据时通知对应的业务员
*/
@Service
public class CustomerChangeMonitorService {
@Autowired
private CustomerService customerService;
@Autowired
private NotificationService notificationService;
// 存储上次检查时的客户数据状态
private Map<String, String> lastCustomerStates = new HashMap<>();
/**
* 定时检查客户数据变化
* 每5秒检查一次
*/
@Scheduled(fixedRate = 5000)
public void monitorCustomerChanges() {
try {
// 获取所有客户数据
List<CustomerData> allCustomers = customerService.getAllCustomers();
// 检查每个客户的数据变化
for (CustomerData customer : allCustomers) {
// 构建客户状态字符串,包含关键字段
String currentState = buildCustomerState(customer);
String customerId = customer.getId();
String lastState = lastCustomerStates.get(customerId);
// 如果是新客户或者客户数据发生变化
if (lastState == null || !lastState.equals(currentState)) {
// 检查是否是分配给业务员的情况
if (customer.getUserName() != null && !customer.getUserName().isEmpty() &&
"banold".equals(customer.getNotice())) {
// 发送客户分配通知
NotificationDTO notification = new NotificationDTO();
notification.setType("CUSTOMER_ASSIGNMENT");
notification.setTitle("客户分配通知");
notification.setMessage("您已被分配了一个新客户: " + customer.getNickName());
notification.setCustomerId(customerId);
notification.setTimestamp(LocalDateTime.now(ZoneOffset.UTC));
// 广播通知
notificationService.broadcastNotification(notification);
// 发送特定客户通知
notificationService.sendCustomerUpdateNotification(customerId, "客户已分配给您");
}
// 更新客户状态
lastCustomerStates.put(customerId, currentState);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 构建客户状态字符串用于比较客户数据是否变化
*/
private String buildCustomerState(CustomerData customer) {
return String.format("%s|%s|%s|%s|%s|%s|%s|%s",
customer.getId(),
customer.getNickName(),
customer.getUserName(),
customer.getManagercompany(),
customer.getManagerdepartment(),
customer.getOrganization(),
customer.getNotice(),
customer.getUpdated_at());
}
}

42
src/main/java/com/example/web/service/impl/CustomerServiceImpl.java

@ -15,6 +15,7 @@ import com.example.web.mapper.CustomerMapper;
import com.example.web.mapper.InformationTraMapper;
import com.example.web.mapper.WechatCustomerMapper;
import com.example.web.service.CustomerService;
import com.example.web.service.NotificationService;
import com.example.web.utils.CustomerTraceUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@ -45,6 +46,9 @@ public class CustomerServiceImpl implements CustomerService {
@Autowired
private CustomerTraceUtil customerTraceUtil;
@Autowired
private NotificationService notificationService;
@Override
public List<CustomerData> getAllCustomers() {
List<CustomerData> allCustomers = new ArrayList<>();
@ -330,6 +334,9 @@ public class CustomerServiceImpl implements CustomerService {
// 记录客户认领操作
customerTraceUtil.recordCustomerFollowup(contacts.getId(), login.getManagercompany(), login.getManagerdepartment(), login.getOrganization(), login.getProjectName(), login.getUserName(), originalData.toString(), modifiedData.toString(), changedFields);
// 发送客户认领通知
notificationService.sendCustomerUpdateNotification(contacts.getId(), "客户已被认领");
return true;
}
@ -416,6 +423,9 @@ public class CustomerServiceImpl implements CustomerService {
// 记录客户认领操作
customerTraceUtil.recordCustomerFollowup(String.valueOf(user.getUserId()), login.getManagercompany(), login.getManagerdepartment(), login.getOrganization(), login.getProjectName(), login.getUserName(), originalData.toString(), modifiedData.toString(), changedFields);
// 发送客户认领通知
notificationService.sendCustomerUpdateNotification(String.valueOf(user.getUserId()), "客户已被认领");
}
return result > 0;
@ -868,6 +878,9 @@ public class CustomerServiceImpl implements CustomerService {
// 记录客户编辑操作
customerTraceUtil.recordCustomerEdit(existingContacts.getId(), login.getManagercompany(), login.getManagerdepartment(), login.getOrganization(), login.getProjectName(), login.getUserName(), originalData, modifiedData, changedFields);
// 发送客户更新通知
notificationService.sendCustomerUpdateNotification(existingContacts.getId(), "客户信息已更新");
return primaryResult;
}
@ -1023,6 +1036,9 @@ public class CustomerServiceImpl implements CustomerService {
// 记录客户编辑操作
customerTraceUtil.recordCustomerEdit(String.valueOf(existingUser.getUserId()), login.getManagercompany(), login.getManagerdepartment(), login.getOrganization(), login.getProjectName(), login.getUserName(), originalData, modifiedData, changedFields);
// 发送客户更新通知
notificationService.sendCustomerUpdateNotification(String.valueOf(existingUser.getUserId()), "客户信息已更新");
return wechatResult;
}
} catch (Exception e) {
@ -1172,12 +1188,22 @@ public class CustomerServiceImpl implements CustomerService {
System.out.println("DEBUG: 获取联系人信息结果: " + (contacts != null ? "找到" : "未找到"));
if (contacts != null) {
// 更新联系人信息
// 只更新customerData中存在的字段,避免将现有字段设为null
if (customerData.containsKey("wechat")) {
contacts.setWechat((String) customerData.get("wechat"));
}
if (customerData.containsKey("account")) {
contacts.setAccount((String) customerData.get("account"));
}
if (customerData.containsKey("accountNumber")) {
contacts.setAccountNumber((String) customerData.get("accountNumber"));
}
if (customerData.containsKey("bank")) {
contacts.setBank((String) customerData.get("bank"));
}
if (customerData.containsKey("address")) {
contacts.setAddress((String) customerData.get("address"));
}
contacts.setUpdated_at(now);
int contactsUpdateResult = wechatCustomerMapper.updateUsersContacts(contacts);
System.out.println("DEBUG: 更新联系人信息结果: " + contactsUpdateResult);
@ -1188,13 +1214,25 @@ public class CustomerServiceImpl implements CustomerService {
System.out.println("DEBUG: 获取负责人信息结果: " + (managements != null ? "找到" : "未找到"));
if (managements != null) {
// 更新负责人信息
// 只更新customerData中存在的字段,避免将现有字段设为null
if (customerData.containsKey("managercompany")) {
managements.setManagercompany((String) customerData.get("managercompany"));
}
if (customerData.containsKey("managerdepartment")) {
managements.setManagerdepartment((String) customerData.get("managerdepartment"));
}
if (customerData.containsKey("organization")) {
managements.setOrganization((String) customerData.get("organization"));
}
if (customerData.containsKey("projectName")) {
managements.setRole((String) customerData.get("projectName"));
}
if (customerData.containsKey("userName")) {
managements.setUserName((String) customerData.get("userName"));
}
if (customerData.containsKey("assistant")) {
managements.setAssistant((String) customerData.get("assistant"));
}
managements.setUpdated_at(now);
int managementsUpdateResult = wechatCustomerMapper.updateUsersManagements(managements);
System.out.println("DEBUG: 更新负责人信息结果: " + managementsUpdateResult);

85
src/main/resources/static/sells.html

@ -4489,10 +4489,12 @@
// 所有可能的等级
const allLevels = ['important', 'regular', 'low-value', 'logistics', 'unclassified', 'department-sea-pools', 'organization-sea-pools'];
// 非公海池等级(用于全部客户视图)
const nonSeaPoolLevels = ['important', 'regular', 'low-value', 'logistics', 'unclassified'];
if (level === 'all') {
// 全部客户包含所有等级,包括部门和组织公海池
allLevels.forEach(level => {
nonSeaPoolLevels.forEach(level => {
const tbody = document.getElementById(`${level}-customers`);
tbody.style.display = 'table-row-group';
// 全部客户视图,隐藏没有数据的等级的"暂无数据"提示
@ -4525,9 +4527,7 @@
'regular': '暂无普通客户数据',
'low-value': '暂无低价值客户数据',
'logistics': '暂无物流客户数据',
'unclassified': '暂无未分级客户数据',
'department-sea-pools': '暂无部门公海客户数据',
'organization-sea-pools': '暂无组织公海客户数据'
'unclassified': '暂无未分级客户数据'
}[level] || '暂无客户数据';
tbody.innerHTML = `<tr><td colspan="9" style="text-align: center; color: #666;">${noDataText}</td></tr>`;
}
@ -5606,10 +5606,13 @@
updateOrganizationSeaPoolTable();
}
// 同时更新全局客户列表和相关表格
updateRecentCustomers();
updateStatsCards();
updateCustomerTable(customer);
// 重新获取客户数据,确保认领的客户出现在我的客户列表中
// 检查stompClient是否存在
if (typeof stompClient !== 'undefined' && stompClient && stompClient.connected) {
const loginInfo = getLoginUserInfo();
// 重新请求获取最新的客户数据 - 使用buyer角色
stompClient.send("/app/customer/role/buyer", {}, JSON.stringify(loginInfo));
}
} else {
alert('客户认领失败: ' + (data.message || '未知错误'));
}
@ -6737,9 +6740,9 @@
});
// WebSocket客户端逻辑
let stompClient = null; // 暴露到全局作用域
(function () {
// 全局变量
let stompClient = null;
// 局部变量
let loginUser = null;
// 初始化WebSocket连接
@ -6789,6 +6792,41 @@
handleOrganizationSeaPoolMessage(organizationSeaPoolCustomers);
});
// 订阅客户更新通知
stompClient.subscribe('/topic/notifications', function(response) {
try {
const notification = JSON.parse(response.body);
console.log('收到客户更新通知:', notification);
// 更新通知显示
updateNotificationDisplay();
// 重新获取客户数据
const loginInfo = getLoginUserInfo();
stompClient.send("/app/customer/role/buyer", {}, JSON.stringify(loginInfo));
// 获取部门和组织公海池数据
stompClient.send("/app/customer/departmentSeaPool/buyer", {}, JSON.stringify(loginInfo));
stompClient.send("/app/customer/organizationSeaPool/buyer", {}, JSON.stringify(loginInfo));
} catch (error) {
console.error('处理通知数据时出错:', error);
}
});
// 订阅特定客户更新通知
stompClient.subscribe('/topic/customers/*', function(response) {
try {
const notification = JSON.parse(response.body);
console.log('收到特定客户更新通知:', notification);
// 重新获取客户数据
const loginInfo = getLoginUserInfo();
stompClient.send("/app/customer/role/buyer", {}, JSON.stringify(loginInfo));
} catch (error) {
console.error('处理特定客户通知时出错:', error);
}
});
// 订阅buyer角色数据(sells.html页面显示buyer类型客户)
stompClient.subscribe('/topic/role/buyer', function(response) {
const customers = JSON.parse(response.body);
@ -6855,8 +6893,17 @@
console.log('过滤后的客户数据:', filteredCustomers);
// 更新客户数据,过滤掉Colleague类型的客户
// 更新客户数据,过滤掉Colleague类型的客户,保留公海池客户数据
const newCustomerData = {};
// 先保留现有公海池客户数据
Object.values(customerData).forEach(customer => {
if (customer.level && customer.level.includes('sea-pools')) {
newCustomerData[customer.id] = customer;
}
});
// 再添加当前用户的客户数据
filteredCustomers.forEach(customer => {
// 过滤掉Colleague类型的客户
if (customer.type === 'Colleague') {
@ -6881,27 +6928,29 @@
updateStatsCards();
updateRecentCustomers();
// 收集所有唯一的客户等级
// 收集所有唯一的客户等级(不包括公海池)
const customerList = Object.values(customerData);
const levels = [...new Set(customerList.map(customer => customer.level || 'unclassified'))];
const levels = [...new Set(customerList.map(customer => customer.level || 'unclassified'))].filter(level => !level.includes('sea-pools'));
// 清空所有等级的客户表格
const allLevels = ['important', 'regular', 'low-value', 'logistics', 'unclassified', 'department-sea-pools', 'organization-sea-pools'];
allLevels.forEach(level => {
// 只清空非公海池等级的客户表格
const nonSeaPoolLevels = ['important', 'regular', 'low-value', 'logistics', 'unclassified'];
nonSeaPoolLevels.forEach(level => {
const tbody = document.getElementById(`${level}-customers`);
if (tbody) {
tbody.innerHTML = '';
}
});
// 重新渲染所有客户
// 重新渲染非公海池客户
customerList.forEach(customer => {
if (!customer.level.includes('sea-pools')) {
updateCustomerTable(customer);
}
});
// 检查每个等级的tbody,如果没有数据且当前不是全部客户视图,则添加"暂无数据"提示
const currentLevel = document.querySelector('.level-tab.active').dataset.level;
allLevels.forEach(level => {
nonSeaPoolLevels.forEach(level => {
const tbody = document.getElementById(`${level}-customers`);
if (tbody && tbody.children.length === 0) {
if (currentLevel === 'all') {

80
src/main/resources/static/supply.html

@ -4581,9 +4581,7 @@
'regular': '暂无普通客户数据',
'low-value': '暂无低价值客户数据',
'logistics': '暂无物流客户数据',
'unclassified': '暂无未分级客户数据',
'department-sea-pools': '暂无部门公海客户数据',
'organization-sea-pools': '暂无组织公海客户数据'
'unclassified': '暂无未分级客户数据'
}[level] || '暂无客户数据';
tbody.innerHTML = `<tr><td colspan="9" style="text-align: center; color: #666;">${noDataText}</td></tr>`;
}
@ -5637,15 +5635,11 @@
renderOrganizationSeaPool(organizationSeaPoolData);
}
// 同时更新全局客户列表和相关表格
if (typeof updateRecentCustomers === 'function') {
updateRecentCustomers();
}
if (typeof updateStatsCards === 'function') {
updateStatsCards();
}
if (typeof updateCustomerTable === 'function') {
updateCustomerTable(customer);
// 重新获取客户数据,确保认领的客户出现在我的客户列表中
if (stompClient && stompClient.connected) {
const loginInfo = getLoginInfo();
// 重新请求获取最新的客户数据
stompClient.send("/app/customer/role/seller", {}, JSON.stringify(loginInfo));
}
} else {
alert('客户认领失败: ' + (data.message || '未知错误'));
@ -6915,6 +6909,41 @@
}
});
// 订阅客户更新通知
stompClient.subscribe('/topic/notifications', function(response) {
try {
const notification = JSON.parse(response.body);
console.log('收到客户更新通知:', notification);
// 更新通知显示
updateNotificationDisplay();
// 重新获取客户数据
const loginInfo = getLoginInfo();
stompClient.send("/app/customer/role/seller", {}, JSON.stringify(loginInfo));
// 获取部门和组织公海池数据
stompClient.send("/app/customer/departmentSeaPool/seller", {}, JSON.stringify(loginInfo));
stompClient.send("/app/customer/organizationSeaPool/seller", {}, JSON.stringify(loginInfo));
} catch (error) {
console.error('处理通知数据时出错:', error);
}
});
// 订阅特定客户更新通知
stompClient.subscribe('/topic/customers/*', function(response) {
try {
const notification = JSON.parse(response.body);
console.log('收到特定客户更新通知:', notification);
// 重新获取客户数据
const loginInfo = getLoginInfo();
stompClient.send("/app/customer/role/seller", {}, JSON.stringify(loginInfo));
} catch (error) {
console.error('处理特定客户通知时出错:', error);
}
});
// 订阅seller角色数据(supply.html页面显示seller类型客户)
stompClient.subscribe('/topic/role/seller', function(response) {
try {
@ -6930,8 +6959,17 @@
console.log('过滤后的客户数据:', filteredCustomers);
// 更新客户数据 - 以客户ID为键,过滤掉Colleague类型的客户
// 更新客户数据 - 以客户ID为键,过滤掉Colleague类型的客户,保留公海池客户数据
const newCustomerData = {};
// 先保留现有公海池客户数据
Object.values(customerData).forEach(customer => {
if (customer.level && customer.level.includes('sea-pools')) {
newCustomerData[customer.id] = customer;
}
});
// 再添加当前用户的客户数据
filteredCustomers.forEach(customer => {
// 过滤掉Colleague类型的客户
if (customer.type === 'Colleague') {
@ -6956,27 +6994,29 @@
updateStatsCards();
updateRecentCustomers();
// 收集所有唯一的客户等级
// 收集所有唯一的客户等级(不包括公海池)
const customerList = Object.values(customerData);
const levels = [...new Set(customerList.map(customer => customer.level || 'unclassified'))];
const levels = [...new Set(customerList.map(customer => customer.level || 'unclassified'))].filter(level => !level.includes('sea-pools'));
// 清空所有等级的客户表格
const allLevels = ['important', 'regular', 'low-value', 'logistics', 'unclassified', 'department-sea-pools', 'organization-sea-pools'];
allLevels.forEach(level => {
// 只清空非公海池等级的客户表格
const nonSeaPoolLevels = ['important', 'regular', 'low-value', 'logistics', 'unclassified'];
nonSeaPoolLevels.forEach(level => {
const tbody = document.getElementById(`${level}-customers`);
if (tbody) {
tbody.innerHTML = '';
}
});
// 重新渲染所有客户
// 重新渲染非公海池客户
customerList.forEach(customer => {
if (!customer.level.includes('sea-pools')) {
updateCustomerTable(customer);
}
});
// 检查每个等级的tbody,如果没有数据且当前不是全部客户视图,则添加"暂无数据"提示
const currentLevel = document.querySelector('.level-tab.active').dataset.level;
allLevels.forEach(level => {
nonSeaPoolLevels.forEach(level => {
const tbody = document.getElementById(`${level}-customers`);
if (tbody && tbody.children.length === 0) {
if (currentLevel === 'all') {

Loading…
Cancel
Save