feat(client): 实现用户数据隔离与设备绑定优化- 添加用户会话ID构建逻辑,确保数据按用户隔离- 优化设备绑定流程,支持设备状态更新和绑定时间同步- 实现用户缓存清理功能,仅清除当前用户的数据- 增强客户端账号删除逻辑,级联删除相关数据
- 调整设备在线查询逻辑,确保只返回活跃绑定的设备 - 优化试用期逻辑,精确计算过期时间和类型- 添加账号管理弹窗和相关状态注入 -修复跟卖精灵按钮加载状态显示问题 - 增强文件上传区域UI,显示选中文件名 - 调整分页组件样式,优化界面展示效果- 优化反馈日志存储路径逻辑,默认使用用户目录 - 移除冗余代码和无用导入,提升代码整洁度
This commit is contained in:
@@ -3,6 +3,7 @@ import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* 启动程序
|
||||
@@ -15,6 +16,7 @@ public class RuoYiApplication
|
||||
{
|
||||
public static void main(String[] args)
|
||||
{
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));
|
||||
// System.setProperty("spring.devtools.restart.enabled", "false");
|
||||
SpringApplication.run(RuoYiApplication.class, args);
|
||||
System.out.println("(♥◠‿◠)ノ゙ 若依启动成功 ლ(´ڡ`ლ)゙ \n" +
|
||||
|
||||
@@ -37,7 +37,7 @@ public class ClientFeedbackController extends BaseController {
|
||||
@Autowired
|
||||
private IClientFeedbackService feedbackService;
|
||||
|
||||
@Value("${feedback.log.path:C:/ProgramData/erp-logs/feedback/}")
|
||||
@Value("${feedback.log.path:}")
|
||||
private String feedbackLogPath;
|
||||
|
||||
/**
|
||||
@@ -258,20 +258,21 @@ public class ClientFeedbackController extends BaseController {
|
||||
* 保存日志文件
|
||||
*/
|
||||
private String saveLogFile(String username, String deviceId, MultipartFile file) throws IOException {
|
||||
// 确保目录存在
|
||||
Path uploadPath = Paths.get(feedbackLogPath);
|
||||
String logPath = feedbackLogPath;
|
||||
if (logPath == null || logPath.trim().isEmpty()) {
|
||||
logPath = System.getProperty("user.home") + File.separator + "erp-feedback";
|
||||
}
|
||||
|
||||
Path uploadPath = Paths.get(logPath).toAbsolutePath();
|
||||
if (!Files.exists(uploadPath)) {
|
||||
Files.createDirectories(uploadPath);
|
||||
}
|
||||
|
||||
// 生成文件名: username_deviceId_timestamp.log
|
||||
String timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
|
||||
String fileName = String.format("%s_%s_%s.log", username, deviceId, timestamp);
|
||||
Path filePath = uploadPath.resolve(fileName);
|
||||
|
||||
// 保存文件
|
||||
file.transferTo(filePath.toFile());
|
||||
|
||||
return filePath.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import com.ruoyi.system.mapper.ClientAccountDeviceMapper;
|
||||
import com.ruoyi.system.domain.ClientAccountDevice;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Date;
|
||||
|
||||
@@ -22,7 +21,6 @@ public class ClientDeviceController {
|
||||
@Autowired private ClientAccountMapper accountMapper;
|
||||
@Autowired private ClientAccountDeviceMapper accountDeviceMapper;
|
||||
@Autowired private SseHubService sseHubService;
|
||||
|
||||
private ClientAccount getAccount(String username) {
|
||||
return accountMapper.selectClientAccountByUsername(username);
|
||||
}
|
||||
@@ -58,18 +56,18 @@ public class ClientDeviceController {
|
||||
String deviceId = data.get("deviceId");
|
||||
ClientAccount account = getAccount(username);
|
||||
if (account == null) return AjaxResult.error("账号不存在");
|
||||
|
||||
int limit = getDeviceLimit(account);
|
||||
if (exceedDeviceLimit(account.getId(), deviceId, limit)) {
|
||||
return AjaxResult.error("设备数量已达上限(" + limit + "个)");
|
||||
}
|
||||
|
||||
ClientDevice device = deviceMapper.selectByDeviceId(deviceId);
|
||||
Date now = new Date();
|
||||
ClientDevice device = deviceMapper.selectByDeviceId(deviceId);
|
||||
if (device == null) {
|
||||
device = new ClientDevice();
|
||||
device.setDeviceId(deviceId);
|
||||
device.setTrialExpireTime(new Date(System.currentTimeMillis() + 3 * 24L * 60 * 60 * 1000));
|
||||
device.setStatus("online");
|
||||
device.setTrialExpireTime(new Date(System.currentTimeMillis() + 7 * 24L * 60 * 60 * 1000));
|
||||
deviceMapper.insert(device);
|
||||
}
|
||||
device.setName(username + "@" + data.get("computerName") + " (" + data.get("os") + ")");
|
||||
@@ -84,12 +82,13 @@ public class ClientDeviceController {
|
||||
binding = new ClientAccountDevice();
|
||||
binding.setAccountId(account.getId());
|
||||
binding.setDeviceId(deviceId);
|
||||
binding.setBindTime(now);
|
||||
binding.setStatus("active");
|
||||
accountDeviceMapper.insert(binding);
|
||||
} else if ("removed".equals(binding.getStatus())) {
|
||||
accountDeviceMapper.updateStatus(account.getId(), deviceId, "active");
|
||||
binding.setStatus("active");
|
||||
accountDeviceMapper.update(binding);
|
||||
}
|
||||
binding.setBindTime(now);
|
||||
|
||||
return AjaxResult.success();
|
||||
}
|
||||
|
||||
@@ -5,6 +5,11 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.ruoyi.system.domain.ClientAccount;
|
||||
import com.ruoyi.system.mapper.ClientAccountMapper;
|
||||
import com.ruoyi.system.mapper.BanmaAccountMapper;
|
||||
import com.ruoyi.system.mapper.ClientFeedbackMapper;
|
||||
import com.ruoyi.system.mapper.ClientMonitorMapper;
|
||||
import com.ruoyi.system.mapper.ClientAccountDeviceMapper;
|
||||
import com.ruoyi.system.mapper.RefreshTokenMapper;
|
||||
import com.ruoyi.web.service.IClientAccountService;
|
||||
|
||||
/**
|
||||
@@ -17,6 +22,16 @@ public class ClientAccountServiceImpl implements IClientAccountService
|
||||
{
|
||||
@Autowired
|
||||
private ClientAccountMapper clientAccountMapper;
|
||||
@Autowired
|
||||
private BanmaAccountMapper banmaAccountMapper;
|
||||
@Autowired
|
||||
private ClientFeedbackMapper clientFeedbackMapper;
|
||||
@Autowired
|
||||
private ClientMonitorMapper clientMonitorMapper;
|
||||
@Autowired
|
||||
private ClientAccountDeviceMapper clientAccountDeviceMapper;
|
||||
@Autowired
|
||||
private RefreshTokenMapper refreshTokenMapper;
|
||||
|
||||
/**
|
||||
* 查询客户端账号
|
||||
@@ -65,10 +80,31 @@ public class ClientAccountServiceImpl implements IClientAccountService
|
||||
|
||||
/**
|
||||
* 批量删除客户端账号
|
||||
* 级联删除所有关联数据:斑马账号、反馈、错误报告、设备绑定、刷新令牌
|
||||
*/
|
||||
@Override
|
||||
public int deleteClientAccountByIds(Long[] ids)
|
||||
{
|
||||
for (Long id : ids) {
|
||||
// 查询账号信息获取username
|
||||
ClientAccount account = clientAccountMapper.selectClientAccountById(id);
|
||||
if (account != null) {
|
||||
String username = account.getUsername();
|
||||
|
||||
// 根据username删除关联数据
|
||||
if (username != null) {
|
||||
banmaAccountMapper.deleteByClientUsername(username);
|
||||
clientFeedbackMapper.deleteFeedbackByUsername(username);
|
||||
clientMonitorMapper.deleteErrorReportByUsername(username);
|
||||
}
|
||||
|
||||
// 根据accountId删除关联数据
|
||||
clientAccountDeviceMapper.deleteByAccountId(id);
|
||||
refreshTokenMapper.deleteByAccountId(id);
|
||||
}
|
||||
}
|
||||
|
||||
// 最后删除客户端账号本身
|
||||
return clientAccountMapper.deleteClientAccountByIds(ids);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.ruoyi.web.sse;
|
||||
import com.ruoyi.system.domain.ClientDevice;
|
||||
import com.ruoyi.system.mapper.ClientDeviceMapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
|
||||
@@ -18,6 +19,14 @@ public class SseHubService {
|
||||
|
||||
@Autowired
|
||||
private ClientDeviceMapper clientDeviceMapper;
|
||||
|
||||
@Scheduled(fixedRate = 30000)
|
||||
public void heartbeat() {
|
||||
sessionEmitters.forEach((key, emitter) -> {
|
||||
String clientId = key.split(":")[1];
|
||||
sendPing(key.split(":")[0], clientId);
|
||||
});
|
||||
}
|
||||
|
||||
public String buildSessionKey(String username, String clientId) {
|
||||
return (username == null ? "" : username) + ":" + (clientId == null ? "" : clientId);
|
||||
|
||||
Reference in New Issue
Block a user