feat(watch): 手表数据统计与设备管理功能增强
- WatchDataItemVO 新增 Date 类型字段及 JsonFormat 格式化支持 - DeptStatisticDataController 部门统计数据查询逻辑优化 - IWatchDeviceService 接口扩展新业务方法声明
This commit is contained in:
+12
-3
@@ -1,9 +1,11 @@
|
||||
package com.renkang.watch.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 手表数据条目 VO
|
||||
@@ -20,10 +22,10 @@ public class WatchDataItemVO implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 工号
|
||||
* 员工编号
|
||||
*/
|
||||
@Schema(title = "工号")
|
||||
private String workNo;
|
||||
@Schema(title = "员工编号")
|
||||
private String employeeNum;
|
||||
|
||||
/**
|
||||
* 手表编号
|
||||
@@ -36,4 +38,11 @@ public class WatchDataItemVO implements Serializable {
|
||||
*/
|
||||
@Schema(title = "姓名")
|
||||
private String realName;
|
||||
|
||||
/**
|
||||
* 绑定日期
|
||||
*/
|
||||
@Schema(title = "绑定日期")
|
||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
|
||||
private Date bindDate;
|
||||
}
|
||||
|
||||
+1
-1
@@ -391,7 +391,7 @@ public class DeptStatisticDataController extends JeecgController<DeptStatisticDa
|
||||
@RequestMapping(value = "/exportDeptDetail", method = RequestMethod.GET)
|
||||
public Result<?> exportDeptDetailAsync(DepartStatsFilter filter) {
|
||||
deptStatisticDataService.exportDeptDetailAsync(filter);
|
||||
return Result.OK("导出结果请在个用户明细导出记录查看");
|
||||
return Result.OK("导出结果请在用户明细导出记录查看");
|
||||
}
|
||||
|
||||
|
||||
|
||||
+49
-21
@@ -8,14 +8,18 @@ import com.renkang.watch.vo.WatchDataItemVO;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.common.system.api.ISysBaseAPI;
|
||||
import org.jeecg.util.AjaxJson;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -58,33 +62,37 @@ public class WatchApiController {
|
||||
ajaxJson.setSuccess(true);
|
||||
return ajaxJson;
|
||||
}
|
||||
|
||||
@GetMapping(value = "getIdcardByWatchNo")
|
||||
@Operation(summary = "根据手表编码获取最新的身份证号")
|
||||
@ResponseBody
|
||||
public Result<?> getIdcardByWatchNo(@RequestParam("watchNo") String watchNo) {
|
||||
String idcard = watchDeviceService.getIdcardByWatchNo(watchNo);
|
||||
Map<String ,String> map = new HashMap<>();
|
||||
map.put("idcard",idcard);
|
||||
String idcard = watchDeviceService.getIdcardByWatchNo(watchNo);
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("idcard", idcard);
|
||||
return Result.ok(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询手表数据总页数
|
||||
* 查询手表用户数据总页数
|
||||
*
|
||||
* @param workNo 工号(可空,模糊匹配)
|
||||
* @param pageSize 每页大小(可空,默认 10)
|
||||
* @param employeeNum 员工编号(可空,模糊匹配)
|
||||
* @param pageSize 每页大小(可空,默认 10)
|
||||
* @param bindDate 绑定日期(可空,格式 yyyy-MM-dd)
|
||||
* @return 包含 pageCount 字段的 Map
|
||||
*/
|
||||
@GetMapping(value = "getWatchDataPageCount")
|
||||
@Operation(summary = "查询手表数据总页数")
|
||||
@GetMapping(value = "getWatchUserDataPageCount")
|
||||
@Operation(summary = "查询手表用户数据总页数")
|
||||
@ResponseBody
|
||||
public Result<Map<String, Integer>> getWatchDataPageCount(@RequestParam(value = "workNo", required = false) String workNo,
|
||||
@RequestParam(value = "pageSize", required = false) Integer pageSize) {
|
||||
@RequiresPermissions("watch:user:data:query")
|
||||
public Result<Map<String, Integer>> getWatchUserDataPageCount(@RequestParam(value = "employeeNum", required = false) String employeeNum,
|
||||
@RequestParam(value = "pageSize", required = false) Integer pageSize,
|
||||
@RequestParam(value = "bindDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date bindDate) {
|
||||
if (pageSize != null && pageSize > 200) {
|
||||
return Result.error("pageSize 不能超过 200");
|
||||
}
|
||||
int actualPageSize = (pageSize == null || pageSize <= 0) ? 10 : pageSize;
|
||||
Integer pageCount = watchDeviceService.getWatchDataPageCount(workNo, actualPageSize);
|
||||
Integer pageCount = watchDeviceService.getWatchUserDataPageCount(employeeNum, actualPageSize, bindDate);
|
||||
Map<String, Integer> map = new HashMap<>();
|
||||
map.put("pageCount", pageCount);
|
||||
map.put("pageSize", actualPageSize);
|
||||
@@ -92,23 +100,43 @@ public class WatchApiController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询手表数据列表
|
||||
* 分页查询手表用户数据列表
|
||||
*
|
||||
* @param workNo 工号(可空,模糊匹配)
|
||||
* @param pageNo 页码(默认 1)
|
||||
* @param pageSize 每页大小(默认 10)
|
||||
* @param employeeNum 员工编号(可空,模糊匹配)
|
||||
* @param pageNo 页码(默认 1)
|
||||
* @param pageSize 每页大小(默认 10)
|
||||
* @param bindDate 绑定日期(可空,格式 yyyy-MM-dd)
|
||||
* @return 手表数据条目分页
|
||||
*/
|
||||
@GetMapping(value = "getWatchDataByPage")
|
||||
@Operation(summary = "分页查询手表数据列表")
|
||||
@GetMapping(value = "getWatchUserDataByPage")
|
||||
@Operation(summary = "分页查询手表用户数据列表")
|
||||
@ResponseBody
|
||||
public Result<IPage<WatchDataItemVO>> getWatchDataByPage(@RequestParam(value = "workNo", required = false) String workNo,
|
||||
@RequestParam(value = "pageNo", required = false, defaultValue = "1") Integer pageNo,
|
||||
@RequestParam(value = "pageSize", required = false, defaultValue = "10") Integer pageSize) {
|
||||
@RequiresPermissions("watch:user:data:query")
|
||||
public Result<IPage<WatchDataItemVO>> getWatchUserDataByPage(@RequestParam(value = "employeeNum", required = false) String employeeNum,
|
||||
@RequestParam(value = "pageNo", required = false, defaultValue = "1") Integer pageNo,
|
||||
@RequestParam(value = "pageSize", required = false, defaultValue = "10") Integer pageSize,
|
||||
@RequestParam(value = "bindDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date bindDate) {
|
||||
if (pageSize != null && pageSize > 200) {
|
||||
return Result.error("pageSize 不能超过 200");
|
||||
}
|
||||
IPage<WatchDataItemVO> page = watchDeviceService.getWatchDataByPage(workNo, pageNo, pageSize);
|
||||
IPage<WatchDataItemVO> page = watchDeviceService.getWatchUserDataByPage(employeeNum, pageNo, pageSize, bindDate);
|
||||
return Result.ok(page);
|
||||
}
|
||||
|
||||
/**
|
||||
* 全量查询手表用户数据列表(不分页)
|
||||
*
|
||||
* @param employeeNum 员工编号(可空,模糊匹配)
|
||||
* @param bindDate 绑定日期(可空,格式 yyyy-MM-dd)
|
||||
* @return 手表数据条目列表
|
||||
*/
|
||||
@GetMapping(value = "getWatchUserDataAll")
|
||||
@Operation(summary = "全量查询手表用户数据列表(不分页)")
|
||||
@ResponseBody
|
||||
@RequiresPermissions("watch:user:data:query")
|
||||
public Result<List<WatchDataItemVO>> getWatchUserDataAll(@RequestParam(value = "employeeNum", required = false) String employeeNum,
|
||||
@RequestParam(value = "bindDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date bindDate) {
|
||||
List<WatchDataItemVO> list = watchDeviceService.getWatchUserDataAll(employeeNum, bindDate);
|
||||
return Result.ok(list);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -304,7 +304,7 @@
|
||||
|
||||
<insert id="insertWorkout">
|
||||
insert into QH_WAT_DATA (id, userid, username, orgcode, watch_no, type, data_value, last_update_time)
|
||||
(select #{id,jdbcType=VARCHAR}, bind_user_id, #{username,jdbcType=VARCHAR}, #{orgcode,jdbcType=VARCHAR}, watch_no, 6, sum(calorie), data_date
|
||||
(select #{id,jdbcType=VARCHAR}, bind_user_id, #{username,jdbcType=VARCHAR}, #{orgcode,jdbcType=VARCHAR}, watch_no, 6, calorie, data_date
|
||||
from (select bind_user_id, watch_no, sum(calorie) as calorie, data_date,
|
||||
ROW_NUMBER() OVER (PARTITION BY bind_user_id, watch_no ORDER BY data_date desc) as rn
|
||||
from QH_WAT_DATA_WORKOUT
|
||||
@@ -340,7 +340,7 @@
|
||||
|
||||
<insert id="insertDistance">
|
||||
insert into QH_WAT_DATA (id, userid, username, orgcode, watch_no, type, data_value, last_update_time)
|
||||
(select #{id,jdbcType=VARCHAR}, bind_user_id, #{username,jdbcType=VARCHAR}, #{orgcode,jdbcType=VARCHAR}, watch_no, 7, max(data_value), data_date
|
||||
(select #{id,jdbcType=VARCHAR}, bind_user_id, #{username,jdbcType=VARCHAR}, #{orgcode,jdbcType=VARCHAR}, watch_no, 7, data_value, data_date
|
||||
from (select bind_user_id, watch_no, max(data_value) as data_value, data_date,
|
||||
ROW_NUMBER() OVER (PARTITION BY bind_user_id, watch_no ORDER BY data_date desc) as rn
|
||||
from QH_WAT_DATA_DISTANCE
|
||||
@@ -376,7 +376,7 @@
|
||||
|
||||
<insert id="insertSteps">
|
||||
insert into QH_WAT_DATA (id, userid, username, orgcode, watch_no, type, data_value, last_update_time)
|
||||
(select #{id,jdbcType=VARCHAR}, bind_user_id, #{username,jdbcType=VARCHAR}, #{orgcode,jdbcType=VARCHAR}, watch_no, 8, max(data_value), data_date
|
||||
(select #{id,jdbcType=VARCHAR}, bind_user_id, #{username,jdbcType=VARCHAR}, #{orgcode,jdbcType=VARCHAR}, watch_no, 8, data_value, data_date
|
||||
from (select bind_user_id, watch_no, max(data_value) as data_value, data_date,
|
||||
ROW_NUMBER() OVER (PARTITION BY bind_user_id, watch_no ORDER BY data_date desc) as rn
|
||||
from QH_WAT_DATA_STEPS
|
||||
|
||||
+25
-9
@@ -237,21 +237,37 @@ public interface IWatchDeviceService extends IService<WatchDevice> {
|
||||
void deleteKeyUser(String userId,String errorType);
|
||||
|
||||
/**
|
||||
* 查询手表数据总页数
|
||||
* 查询手表用户数据总页数
|
||||
*
|
||||
* @param workNo 工号(可空,模糊匹配)
|
||||
* @param pageSize 每页大小(可空,默认 10)
|
||||
* @param employeeNum 员工编号(可空,模糊匹配)
|
||||
* @param pageSize 每页大小(可空,默认 10)
|
||||
* @param bindDate 绑定日期(可空,精确匹配当天)
|
||||
* @return 总页数
|
||||
*/
|
||||
Integer getWatchDataPageCount(String workNo, Integer pageSize);
|
||||
Integer getWatchUserDataPageCount(String employeeNum, Integer pageSize, java.util.Date bindDate);
|
||||
|
||||
/**
|
||||
* 分页查询手表数据列表
|
||||
* 分页查询手表用户数据列表
|
||||
*
|
||||
* @param workNo 工号(可空,模糊匹配)
|
||||
* @param pageNo 页码
|
||||
* @param pageSize 每页大小
|
||||
* @param employeeNum 员工编号(可空,模糊匹配)
|
||||
* @param pageNo 页码
|
||||
* @param pageSize 每页大小
|
||||
* @param bindDate 绑定日期(可空,精确匹配当天)
|
||||
* @return 手表数据条目分页
|
||||
*/
|
||||
IPage<com.renkang.watch.vo.WatchDataItemVO> getWatchDataByPage(String workNo, Integer pageNo, Integer pageSize);
|
||||
IPage<com.renkang.watch.vo.WatchDataItemVO> getWatchUserDataByPage(String employeeNum, Integer pageNo, Integer pageSize, java.util.Date bindDate);
|
||||
|
||||
/**
|
||||
* 全量查询手表用户数据列表(不分页)
|
||||
*
|
||||
* @param employeeNum 员工编号(可空,模糊匹配)
|
||||
* @param bindDate 绑定日期(可空,精确匹配当天)
|
||||
* @return 手表数据条目列表
|
||||
*/
|
||||
java.util.List<com.renkang.watch.vo.WatchDataItemVO> getWatchUserDataAll(String employeeNum, java.util.Date bindDate);
|
||||
|
||||
/**
|
||||
* 刷新全量手表用户数据缓存(由定时任务调用,刷新 employeeNum=null、bindDate=null 的全量缓存)
|
||||
*/
|
||||
void refreshWatchUserDataAllCache();
|
||||
}
|
||||
|
||||
+146
-15
@@ -2349,23 +2349,33 @@ public class WatchDeviceServiceImpl extends ServiceImpl<WatchDeviceMapper, Watch
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
public Integer getWatchDataPageCount(String workNo, Integer pageSize) {
|
||||
public Integer getWatchUserDataPageCount(String employeeNum, Integer pageSize, Date bindDate) {
|
||||
String cacheKey = buildCacheKey("watch:data:page:count", employeeNum, bindDate, String.valueOf(pageSize));
|
||||
String cached = stringRedisTemplate.opsForValue().get(cacheKey);
|
||||
if (cached != null) {
|
||||
log.info("[缓存命中] key={} value={}", cacheKey, cached);
|
||||
return Integer.valueOf(cached);
|
||||
}
|
||||
int size = (pageSize == null || pageSize <= 0) ? 10 : pageSize;
|
||||
LambdaQueryWrapper<WatchDevice> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.isNotNull(WatchDevice::getBindUserId);
|
||||
wrapper.ne(WatchDevice::getBindUserId, "");
|
||||
if (StrUtil.isNotBlank(workNo)) {
|
||||
List<String> userIds = sysBaseAPI.getUserIdsByDepartAndUsername(null, null, null, workNo);
|
||||
if (StrUtil.isNotBlank(employeeNum)) {
|
||||
List<String> userIds = sysBaseAPI.getUserIdsByDepartAndUsername(null, null, null, employeeNum);
|
||||
if (CollectionUtil.isEmpty(userIds)) {
|
||||
return 0;
|
||||
}
|
||||
wrapper.in(WatchDevice::getBindUserId, userIds);
|
||||
}
|
||||
applyBindDateFilter(wrapper, bindDate);
|
||||
long total = watchDeviceMapper.selectCount(wrapper);
|
||||
if (total <= 0) {
|
||||
return 0;
|
||||
}
|
||||
return (int) ((total + size - 1) / size);
|
||||
int pageCount = (int) ((total + size - 1) / size);
|
||||
stringRedisTemplate.opsForValue().set(cacheKey, String.valueOf(pageCount), 2, java.util.concurrent.TimeUnit.HOURS);
|
||||
log.info("[缓存写入] key={} value={}", cacheKey, pageCount);
|
||||
return pageCount;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2377,31 +2387,118 @@ public class WatchDeviceServiceImpl extends ServiceImpl<WatchDeviceMapper, Watch
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
public IPage<WatchDataItemVO> getWatchDataByPage(String workNo, Integer pageNo, Integer pageSize) {
|
||||
public IPage<WatchDataItemVO> getWatchUserDataByPage(String employeeNum, Integer pageNo, Integer pageSize, Date bindDate) {
|
||||
int pn = (pageNo == null || pageNo <= 0) ? 1 : pageNo;
|
||||
int ps = (pageSize == null || pageSize <= 0) ? 10 : pageSize;
|
||||
Page<WatchDataItemVO> voPage = new Page<>(pn, ps);
|
||||
|
||||
String cacheKey = buildCacheKey("watch:data:page", employeeNum, bindDate, pn + ":" + ps);
|
||||
String cached = stringRedisTemplate.opsForValue().get(cacheKey);
|
||||
if (cached != null) {
|
||||
log.info("[缓存命中] key={}", cacheKey);
|
||||
com.alibaba.fastjson.JSONObject jsonObj = com.alibaba.fastjson.JSONObject.parseObject(cached);
|
||||
Page<WatchDataItemVO> cachedPage = new Page<>(pn, ps);
|
||||
cachedPage.setTotal(jsonObj.getLongValue("total"));
|
||||
java.util.List<WatchDataItemVO> records = com.alibaba.fastjson.JSONArray.parseArray(
|
||||
jsonObj.getString("records"), WatchDataItemVO.class);
|
||||
cachedPage.setRecords(records);
|
||||
return cachedPage;
|
||||
}
|
||||
|
||||
LambdaQueryWrapper<WatchDevice> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.isNotNull(WatchDevice::getBindUserId);
|
||||
wrapper.ne(WatchDevice::getBindUserId, "");
|
||||
// 通过工号过滤:先查 health-system 拿到 userIds,再用 userId 过滤 QH_WAT_DEVICE
|
||||
if (StrUtil.isNotBlank(workNo)) {
|
||||
List<String> userIds = sysBaseAPI.getUserIdsByDepartAndUsername(null, null, null, workNo);
|
||||
// 通过员工编号过滤:先查 health-system 拿到 userIds,再用 userId 过滤 QH_WAT_DEVICE
|
||||
if (StrUtil.isNotBlank(employeeNum)) {
|
||||
List<String> userIds = sysBaseAPI.getUserIdsByDepartAndUsername(null, null, null, employeeNum);
|
||||
if (CollectionUtil.isEmpty(userIds)) {
|
||||
return voPage;
|
||||
}
|
||||
wrapper.in(WatchDevice::getBindUserId, userIds);
|
||||
}
|
||||
wrapper.orderByDesc(WatchDevice::getCreateDate);
|
||||
applyBindDateFilter(wrapper, bindDate);
|
||||
wrapper.orderByDesc(WatchDevice::getBindDate);
|
||||
|
||||
Page<WatchDevice> page = watchDeviceMapper.selectPage(new Page<>(pn, ps), wrapper);
|
||||
BeanUtil.copyProperties(page, voPage, "records");
|
||||
if (CollectionUtil.isEmpty(page.getRecords())) {
|
||||
return voPage;
|
||||
}
|
||||
// 跨服务批量查询用户基本信息(工号、姓名)
|
||||
List<String> userIdList = page.getRecords().stream()
|
||||
List<WatchDataItemVO> records = buildWatchDataItemVOList(page.getRecords());
|
||||
voPage.setRecords(records);
|
||||
|
||||
// 写入缓存
|
||||
com.alibaba.fastjson.JSONObject cacheObj = new com.alibaba.fastjson.JSONObject();
|
||||
cacheObj.put("total", voPage.getTotal());
|
||||
cacheObj.put("records", records);
|
||||
stringRedisTemplate.opsForValue().set(cacheKey, cacheObj.toJSONString(), 2, java.util.concurrent.TimeUnit.HOURS);
|
||||
log.info("[缓存写入] key={} total={} size={}", cacheKey, voPage.getTotal(), records.size());
|
||||
return voPage;
|
||||
}
|
||||
|
||||
/**
|
||||
* 全量查询手表数据列表(不分页)
|
||||
* <p>
|
||||
* 仅查询已绑定用户的设备,支持按工号和绑定日期过滤,结果缓存 1 小时
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
public java.util.List<WatchDataItemVO> getWatchUserDataAll(String employeeNum, Date bindDate) {
|
||||
String cacheKey = buildCacheKey("watch:api:user:data:all", employeeNum, bindDate, null);
|
||||
String cached = stringRedisTemplate.opsForValue().get(cacheKey);
|
||||
if (cached != null) {
|
||||
log.info("[缓存命中] key={}", cacheKey);
|
||||
return com.alibaba.fastjson.JSONArray.parseArray(cached, WatchDataItemVO.class);
|
||||
}
|
||||
|
||||
LambdaQueryWrapper<WatchDevice> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.isNotNull(WatchDevice::getBindUserId);
|
||||
wrapper.ne(WatchDevice::getBindUserId, "");
|
||||
if (StrUtil.isNotBlank(employeeNum)) {
|
||||
List<String> userIds = sysBaseAPI.getUserIdsByDepartAndUsername(null, null, null, employeeNum);
|
||||
if (CollectionUtil.isEmpty(userIds)) {
|
||||
return java.util.Collections.emptyList();
|
||||
}
|
||||
wrapper.in(WatchDevice::getBindUserId, userIds);
|
||||
}
|
||||
applyBindDateFilter(wrapper, bindDate);
|
||||
wrapper.orderByDesc(WatchDevice::getBindDate);
|
||||
|
||||
List<WatchDevice> devices = watchDeviceMapper.selectList(wrapper);
|
||||
if (CollectionUtil.isEmpty(devices)) {
|
||||
return java.util.Collections.emptyList();
|
||||
}
|
||||
java.util.List<WatchDataItemVO> result = buildWatchDataItemVOList(devices);
|
||||
stringRedisTemplate.opsForValue().set(cacheKey, com.alibaba.fastjson.JSONArray.toJSONString(result), 2, java.util.concurrent.TimeUnit.HOURS);
|
||||
log.info("[缓存写入] key={} size={}", cacheKey, result.size());
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建绑定日期范围过滤条件(取当天 00:00:00 ~ 次日 00:00:00)
|
||||
*/
|
||||
private void applyBindDateFilter(LambdaQueryWrapper<WatchDevice> wrapper, Date bindDate) {
|
||||
if (bindDate == null) {
|
||||
return;
|
||||
}
|
||||
java.util.Calendar cal = java.util.Calendar.getInstance();
|
||||
cal.setTime(bindDate);
|
||||
cal.set(java.util.Calendar.HOUR_OF_DAY, 0);
|
||||
cal.set(java.util.Calendar.MINUTE, 0);
|
||||
cal.set(java.util.Calendar.SECOND, 0);
|
||||
cal.set(java.util.Calendar.MILLISECOND, 0);
|
||||
Date start = cal.getTime();
|
||||
cal.add(java.util.Calendar.DAY_OF_MONTH, 1);
|
||||
Date end = cal.getTime();
|
||||
wrapper.ge(WatchDevice::getBindDate, start);
|
||||
wrapper.lt(WatchDevice::getBindDate, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量查询用户信息并组装 WatchDataItemVO 列表
|
||||
*/
|
||||
private java.util.List<WatchDataItemVO> buildWatchDataItemVOList(List<WatchDevice> devices) {
|
||||
List<String> userIdList = devices.stream()
|
||||
.map(WatchDevice::getBindUserId)
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.distinct()
|
||||
@@ -2411,18 +2508,52 @@ public class WatchDeviceServiceImpl extends ServiceImpl<WatchDeviceMapper, Watch
|
||||
? Collections.emptyMap()
|
||||
: loginUserNews.stream().collect(Collectors.toMap(LoginUserNew::getId, u -> u, (a, b) -> a));
|
||||
|
||||
List<WatchDataItemVO> records = page.getRecords().stream().map(device -> {
|
||||
return devices.stream().map(device -> {
|
||||
WatchDataItemVO vo = new WatchDataItemVO();
|
||||
vo.setWatchNo(device.getWatchNo());
|
||||
vo.setBindDate(device.getBindDate());
|
||||
LoginUserNew user = userMap.get(device.getBindUserId());
|
||||
if (user != null) {
|
||||
vo.setWorkNo(user.getWorkNo());
|
||||
vo.setEmployeeNum(user.getWorkNo());
|
||||
vo.setRealName(user.getRealname());
|
||||
}
|
||||
return vo;
|
||||
}).collect(Collectors.toList());
|
||||
voPage.setRecords(records);
|
||||
return voPage;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建 Redis 缓存 key,null 参数用 "null" 占位
|
||||
*/
|
||||
private String buildCacheKey(String prefix, String workNo, Date bindDate, String extra) {
|
||||
String dateStr = bindDate == null ? "null"
|
||||
: new java.text.SimpleDateFormat("yyyy-MM-dd").format(bindDate);
|
||||
String wn = StrUtil.isBlank(workNo) ? "null" : workNo;
|
||||
StringBuilder sb = new StringBuilder(prefix).append(":").append(wn).append(":").append(dateStr);
|
||||
if (extra != null) {
|
||||
sb.append(":").append(extra);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新全量手表用户数据缓存(由定时任务调用)
|
||||
* 查询全量已绑定设备数据并强制写入缓存,覆盖旧值
|
||||
*/
|
||||
@Override
|
||||
public void refreshWatchUserDataAllCache() {
|
||||
String cacheKey = buildCacheKey("watch:api:user:data:all", null, null, null);
|
||||
LambdaQueryWrapper<WatchDevice> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.isNotNull(WatchDevice::getBindUserId);
|
||||
wrapper.ne(WatchDevice::getBindUserId, "");
|
||||
wrapper.orderByDesc(WatchDevice::getBindDate);
|
||||
List<WatchDevice> devices = watchDeviceMapper.selectList(wrapper);
|
||||
if (CollectionUtil.isEmpty(devices)) {
|
||||
stringRedisTemplate.delete(cacheKey);
|
||||
return;
|
||||
}
|
||||
java.util.List<WatchDataItemVO> result = buildWatchDataItemVOList(devices);
|
||||
stringRedisTemplate.opsForValue().set(cacheKey, com.alibaba.fastjson.JSONArray.toJSONString(result), 2, java.util.concurrent.TimeUnit.HOURS);
|
||||
log.info("[缓存刷新] key={} size={}", cacheKey, result.size());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.renkang.watch.task;
|
||||
|
||||
import com.renkang.watch.service.IWatchDeviceService;
|
||||
import com.xxl.job.core.handler.annotation.XxlJob;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 手表用户数据全量缓存刷新任务
|
||||
* <p>
|
||||
* 定时刷新 Redis 中 watch:api:user:data:all:null:null 缓存,供 getWatchUserDataAll 接口使用。
|
||||
* 具体执行频率在 xxl-job 控制台配置,handler 名称:watch-user-data-cache-refresh
|
||||
* </p>
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class WatchUserDataCacheJob {
|
||||
|
||||
private final IWatchDeviceService watchDeviceService;
|
||||
|
||||
/**
|
||||
* 刷新手表用户全量数据缓存
|
||||
*/
|
||||
@XxlJob("watch-user-data-cache-refresh")
|
||||
public void refreshCache() {
|
||||
log.info("------开始刷新手表用户全量数据缓存------");
|
||||
try {
|
||||
watchDeviceService.refreshWatchUserDataAllCache();
|
||||
log.info("======手表用户全量数据缓存刷新完成======");
|
||||
} catch (Exception e) {
|
||||
log.error("手表用户全量数据缓存刷新失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
@@ -105,6 +105,10 @@ public class JeecgBootExceptionHandler implements ResponseBodyAdvice<String> {
|
||||
return Result.error(errorInfoEnum.getError());
|
||||
}
|
||||
//update-end---author:zyf ---date:20220411 for:处理Sentinel限流自定义异常
|
||||
//吞提示信息了,这里先单独处理一下吧
|
||||
if(e.getMessage().startsWith("已存在")){
|
||||
return Result.error(e.getMessage());
|
||||
}
|
||||
return Result.error("系统异常,请稍后再试", e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ import org.jeecgframework.poi.excel.ExcelExportUtil;
|
||||
import org.jeecgframework.poi.excel.entity.ExportParams;
|
||||
import org.jeecgframework.poi.excel.entity.enmus.ExcelType;
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
@@ -108,6 +109,8 @@ public class ExportUtils {
|
||||
if (ObjectUtil.isNotNull(threadLocal)) {
|
||||
T o = threadLocal.get();
|
||||
return executor.submit(() -> {
|
||||
// 清除线程池复用线程可能残留的 HTTP 请求上下文,避免 Feign 拦截器读到过期 token
|
||||
RequestContextHolder.resetRequestAttributes();
|
||||
UserTokenContext.setToken(token);
|
||||
threadLocal.set(o);
|
||||
EXPORT_LOCAL.set(info);
|
||||
@@ -125,6 +128,8 @@ public class ExportUtils {
|
||||
});
|
||||
} else {
|
||||
return executor.submit(() -> {
|
||||
// 清除线程池复用线程可能残留的 HTTP 请求上下文,避免 Feign 拦截器读到过期 token
|
||||
RequestContextHolder.resetRequestAttributes();
|
||||
UserTokenContext.setToken(token);
|
||||
EXPORT_LOCAL.set(info);
|
||||
try {
|
||||
|
||||
@@ -199,7 +199,7 @@ public class RSAEncryptUtils {
|
||||
// Map<String, Object> keyMap;
|
||||
// String cipherText;
|
||||
// // 原始明文
|
||||
String content = "UserPwd@123!";
|
||||
String content = "v6BQj8452!j8KYj";
|
||||
//
|
||||
// // 生成密钥对
|
||||
// keyMap = initKey(1024);
|
||||
|
||||
Reference in New Issue
Block a user