From 02bb94e413f6950b9786c5ee86c0937bc20f8ae8 Mon Sep 17 00:00:00 2001 From: 无关风月 <443237572@qq.com> Date: 星期六, 12 七月 2025 14:42:20 +0800 Subject: [PATCH] Merge remote-tracking branch 'origin/master' --- ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/template/wxTemplateTaskReturn/WxTemplateTaskResultRequestData.java | 23 ++ ruoyi-system/src/main/java/com/ruoyi/system/utils/TemplateMessageSendUtil.java | 82 ++++++++ ruoyi-admin/src/main/resources/application-test.yml | 2 ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/tools/WxAppletTools.java | 8 ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/WorkbenchesController.java | 45 +++ ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml | 2 ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TLocationController.java | 39 ++- ruoyi-system/src/main/java/com/ruoyi/system/utils/JsonUtils.java | 110 +++++++++++ ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/pojo/AppletUserEncrypteData.java | 2 ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/config/JacksonConfig.java | 35 +++ ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/template/Template.java | 19 + ruoyi-system/src/main/java/com/ruoyi/system/importExcel/TLocationImportExcel.java | 36 +- /dev/null | 77 ------- ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/TUserController.java | 38 +++ ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/model/WeixinProperties.java | 14 + ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java | 5 ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java | 5 ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/template/wxTemplateTaskReturn/WxTemplateTaskResultRequest.java | 22 ++ 18 files changed, 447 insertions(+), 117 deletions(-) diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TLocationController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TLocationController.java index d1872b3..e96f3cb 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TLocationController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TLocationController.java @@ -5,6 +5,8 @@ import cn.afterturn.easypoi.excel.ExcelImportUtil; import cn.afterturn.easypoi.excel.entity.ExportParams; import cn.afterturn.easypoi.excel.entity.ImportParams; +import cn.hutool.json.JSON; +import cn.hutool.json.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.ruoyi.common.annotation.Log; @@ -341,7 +343,7 @@ @PostMapping("/importLocation") public R<String> importLocation(@RequestPart("file") MultipartFile file) { ImportParams params = new ImportParams(); - params.setTitleRows(2); // 标题行数 +// params.setTitleRows(1); // 标题行数 params.setHeadRows(1); //表头行数 InputStream inputStream = null; // List<CustomerImportFailedData> failedData = new ArrayList<>(); @@ -371,9 +373,11 @@ // 查询所有用户 List<SysUser> users = sysUserService.selectAllList(); // 查询所有部门 - List<TDept> deptList = deptService.list(); + List<TProjectDept> deptList = projectDeptService.list(); // 查询所有保洁员 List<TCleaner> cleaners = cleanerService.list(); + + JSONObject result = new JSONObject(); for (TLocationImportExcel locationExcel : locationExcelList) { System.err.println(locationExcel); @@ -385,28 +389,43 @@ location.setLocationType(tLocationType.getId()); } location.setLocationAddress(locationExcel.getLocationAddress()); - String[] addressLonLat = locationExcel.getLocationAddressLonLat().split("/"); + String[] addressLonLat = locationExcel.getLocationAddressLonLat().split(","); location.setLocationLon(addressLonLat[0]); location.setLocationLat(addressLonLat[1]); location.setLocationAddressEnd(locationExcel.getLocationAddressEnd()); - String[] addressEndLonLat = locationExcel.getLocationAddressEndLonLat().split("/"); + String[] addressEndLonLat = locationExcel.getLocationAddressEndLonLat().split(","); location.setLocationLonEnd(addressEndLonLat[0]); location.setLocationLatEnd(addressEndLonLat[1]); - TDept tDept = deptList.stream().filter(dept -> dept.getCode().equals(locationExcel.getDeptCode())).findFirst().orElse(null); - if(Objects.nonNull(tDept)){ - location.setProjectId(tDept.getId()); + TProjectDept projectDept = deptList.stream().filter(dept -> dept.getCode().equals(locationExcel.getDeptCode())).findFirst().orElse(null); + if(Objects.nonNull(projectDept)){ + location.setProjectId(projectDept.getId()); + }else { + result.append("路段名:[", locationExcel.getLocationName()+"]未查询到部门"); + continue; } SysUser sysUser = users.stream().filter(user -> user.getNickName().equals(locationExcel.getNickName())).findFirst().orElse(null); if(Objects.nonNull(sysUser)){ location.setLocationLeader(String.valueOf(sysUser.getUserId())); + }else { + result.append("路段名:[", locationExcel.getLocationName()+"]未查询到点位负责人"); + continue; } - cleaners.stream().filter(cleaner -> cleaner.getCleanerCode().equals(locationExcel.getCleanerCodeClear()) + TCleaner tCleaner = cleaners.stream().filter(cleaner -> cleaner.getCleanerCode().equals(locationExcel.getCleanerCodeClear()) && cleaner.getDeptCode().equals(locationExcel.getDeptCodeClear()) - && cleaner.getProjectCode().equals(locationExcel.getProjectCodeClear())).findFirst().orElse(null); - location.setLocationCleaner(locationExcel.getProjectCodeClear()); + && cleaner.getProjectCode().equals(locationExcel.getProjectCodeClear()) + && cleaner.getCleanerName().equals(locationExcel.getCleanerName())).findFirst().orElse(null); + if(Objects.nonNull(tCleaner)){ + location.setLocationCleaner(tCleaner.getId()); + }else { + result.append("路段名:[", locationExcel.getLocationName()+"]未查询到保洁员"); + continue; + } locationService.save(location); } + if(!result.isEmpty()){ + return R.ok(result.toString()); + } return R.ok(); } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/WorkbenchesController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/WorkbenchesController.java index 1f7c0b0..5501de8 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/WorkbenchesController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/WorkbenchesController.java @@ -204,6 +204,10 @@ } query.setProjectId(projectIds); } + + // 巡检员数 + Integer totalEmployeeNum = sysUserService.selectUserCount(query.getProjectId(),deptType); + map.put("totalEmployeeNum", totalEmployeeNum); }else { // 公司人员 // 查询自己的任务列表 @@ -218,6 +222,9 @@ query.setProjectId(projectIds); } } + // 巡检员数 + Integer totalEmployeeNum = sysUserService.selectUserCount(query.getProjectId(),1); + map.put("totalEmployeeNum", totalEmployeeNum+1); } // 查询片区 @@ -283,6 +290,16 @@ list.addAll(taskList); } list = list.stream().distinct().collect(Collectors.toList()); + + // 巡检员数 + if(CollectionUtils.isEmpty(query.getProjectId())){ + Integer totalEmployeeNum = sysUserService.selectUserCount(query.getProjectId(),deptType); + Integer totalEmployeeNum1 = sysUserService.selectUserCount(query.getProjectId(),1); + map.put("totalEmployeeNum", totalEmployeeNum+totalEmployeeNum1); + }else { + Integer totalEmployeeNum = sysUserService.selectUserCount(query.getProjectId(),1); + map.put("totalEmployeeNum", totalEmployeeNum); + } } // 查询任务相关数据 @@ -294,11 +311,11 @@ map.put("waitTaskNum", list.stream().filter(tTask -> tTask.getStatus() == 1).count()); // 总计员工数 - Integer totalEmployeeNum = sysUserService.selectUserCount(null,deptType); - if (deptType != 1) { - totalEmployeeNum = totalEmployeeNum + 1; - } - map.put("totalEmployeeNum", totalEmployeeNum); +// Integer totalEmployeeNum = sysUserService.selectUserCount(null,deptType); +// if (deptType != 1) { +// totalEmployeeNum = totalEmployeeNum + 1; +// } +// map.put("totalEmployeeNum", totalEmployeeNum); // 今日请假员工数量 List<TLeave> leaves = leaveService.list(Wrappers.lambdaQuery(TLeave.class) @@ -499,6 +516,22 @@ && task.getStatus() != 3 && task.getStatus() != 4).collect(Collectors.toList()); if(CollectionUtils.isEmpty(tasks)){ taskSituationVO.setPassRate(BigDecimal.ZERO); + for (long i = 0; i <= daysBetween; i++) { + TaskSituationDayVO taskSituationDayVO = new TaskSituationDayVO(); + if(i == 0){ + format = localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); + }else { + format = DateUtils.stringToLocalDate(format).plusDays(1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); + } + taskSituationDayVO.setTaskTime(format); + // 任务数 + taskSituationDayVO.setTaskNum(0); + // 完成数 + taskSituationDayVO.setCompletedNum(0); + taskSituationDayVO.setCompleteRate(BigDecimal.ZERO); + taskSituationDayVOList.add(taskSituationDayVO); + } + taskSituationVO.setTaskSituationDayVO(taskSituationDayVOList); return R.ok(taskSituationVO); } List<String> taskIds = tasks.stream().map(TTask::getId).collect(Collectors.toList()); @@ -541,7 +574,7 @@ if(tTasks.isEmpty()){ taskSituationDayVO.setCompleteRate(BigDecimal.ZERO); }else { - taskSituationDayVO.setCompleteRate(new BigDecimal(qualifiedWarnChild).divide(new BigDecimal(tTasks.size()), 2, RoundingMode.HALF_DOWN)); + taskSituationDayVO.setCompleteRate(new BigDecimal(qualifiedWarnChild).divide(new BigDecimal(taskSituationDayVO.getCompletedNum()), 2, RoundingMode.HALF_DOWN)); } taskSituationDayVOList.add(taskSituationDayVO); } diff --git a/ruoyi-admin/src/main/resources/application-test.yml b/ruoyi-admin/src/main/resources/application-test.yml index b1f942b..f5a8d21 100644 --- a/ruoyi-admin/src/main/resources/application-test.yml +++ b/ruoyi-admin/src/main/resources/application-test.yml @@ -198,6 +198,8 @@ conf: appId: wxe91f1af7638aa5dd secretId: a787e1a462715604e0c9528b6d8960d1 + templateResultId: C4YA0kRIhoJYwKbhrNhxi8wcRLP4R92QME-lc6eygAo + templateDateId: fWv6EnWlUNhR5Gu-6b6rv0xbk-yr7pB_kKH_Xnt7ts4 #OSS及短信配置 code: config: diff --git a/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/TUserController.java b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/TUserController.java index 2548608..570babe 100644 --- a/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/TUserController.java +++ b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/TUserController.java @@ -5,11 +5,13 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.ruoyi.common.annotation.Log; import com.ruoyi.common.basic.PageInfo; +import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.BaseModel; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.domain.entity.SysRole; import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.redis.service.RedisService; import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.bean.BeanUtils; import com.ruoyi.framework.web.service.TokenService; @@ -25,14 +27,24 @@ import com.ruoyi.system.query.KnowledgeListQuery; import com.ruoyi.system.query.TaskListQuery; import com.ruoyi.system.service.*; +import com.ruoyi.system.utils.wx.body.resp.Code2SessionRespBody; +import com.ruoyi.system.utils.wx.body.resq.Code2SessionResqBody; +import com.ruoyi.system.utils.wx.model.WeixinProperties; +import com.ruoyi.system.utils.wx.pojo.AppletUserDecodeData; +import com.ruoyi.system.utils.wx.pojo.AppletUserEncrypteData; +import com.ruoyi.system.utils.wx.tools.WxAppletTools; +import com.ruoyi.system.utils.wx.tools.WxUtils; import com.ruoyi.system.vo.system.*; import com.ruoyi.web.controller.tool.EmailUtils; import com.ruoyi.web.controller.tool.MsgUtils; import com.sun.jna.platform.win32.LMAccess; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.*; +import org.springframework.web.client.RestTemplate; import javax.annotation.Resource; import javax.validation.Valid; @@ -54,6 +66,7 @@ * @author xiaochen * @since 2025-05-28 */ +@Slf4j @Api(tags = "个人中心") @RestController @RequestMapping("/t-user") @@ -100,6 +113,31 @@ private TProblemEscalationService problemEscalationService; @Resource private TNoticeService noticeService; + @Autowired + private RestTemplate wxRestTemplate; + @Autowired + private WeixinProperties weixinProperties; + @Resource + private RedisService redisService; + @ApiOperation(value = "通过code获得openid,获取用户信息",tags = {"微信小程序登录"}) + @GetMapping("/openIdByJsCode") + public R<String> openIdByJsCode(@RequestParam String code) { + Long userId = tokenService.getLoginUser().getUserId(); + SysUser sysUser = sysUserService.selectUserById(userId); + if(Objects.isNull(sysUser)){ + return R.fail("未查询到当前登录用户信息"); + } + if(StringUtils.hasLength(sysUser.getOpenId())){ + return R.ok(); + } + log.info("<<<<<<<<换取openid开始<<<<<<<<:{}", code); + WxAppletTools appletTools = new WxAppletTools(wxRestTemplate, weixinProperties, redisService); + Code2SessionRespBody body = appletTools.getOpenIdByJscode2session(new Code2SessionResqBody().build(code)); + String openid = body.getOpenid(); + sysUser.setOpenId(openid); + sysUserService.updateUser(sysUser); + return R.ok(); + } @Resource private MsgUtils msgUtils; diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java index 93d8567..500087e 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java @@ -163,4 +163,9 @@ * 用户类型 */ public static final String USER_TYPE = "用户类型"; + + /** + * 模板消息发送地址 + */ + public static final String TEMPLATE_URL = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=ACCESS_TOKEN"; } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java index 7034d98..3810712 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java @@ -152,6 +152,11 @@ @ApiModelProperty(value = "营业部id") @TableField("business_dept_id") private String businessDeptId; + @ApiModelProperty(value = "openId") + @TableField("openId") + private String openId; + + public String getRoleName() { return roleName; diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/WxAppletTools.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/WxAppletTools.java deleted file mode 100644 index 7c6ee85..0000000 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/WxAppletTools.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.ruoyi.common.utils; - -import com.alibaba.fastjson2.JSONObject; -import com.ruoyi.common.config.WxConfig; -import com.ruoyi.common.core.redis.RedisCache; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; -import org.springframework.util.StringUtils; -import org.springframework.web.client.RestTemplate; - -import java.text.MessageFormat; - -/** - * @author liheng - * @ClassName WxAppletTools - * @Description - * @date 2020-12-04 13:55 - */ -@Slf4j -@Component -public class WxAppletTools { - @Autowired - private RedisCache redisCache; - @Autowired - private RestTemplate restTemplate; - @Autowired - private WxConfig wxConfig; - private final static String ACCESSTOKEN_CACHE_KEY = "accessToken"; - /** - * 请求参数 - * 属性 类型 默认值 必填 说明 - * appid string 是 小程序 appId - * secret string 是 小程序 appSecret - * js_code string 是 登录时获取的 code - * grant_type string 是 授权类型,此处只需填写 authorization_cod - * <p> - * 返回值: - * <p> - * 属性 类型 说明 - * openid string 用户唯一标识 - * session_key string 会话密钥 - * unionid string 用户在开放平台的唯一标识符,若当前小程序已绑定到微信开放平台帐号下会返回,详见 UnionID 机制说明。 - * errcode number 错误码 - * errmsg string 错误信息 - */ - private static final String JSCODE_2_SESSION_URL = "https://api.weixin.qq.com/sns/jscode2session?appid={0}&secret={1}&js_code={2}&grant_type=authorization_code"; - - - /** - * 请求参数 - * 属性 类型 默认值 必填 说明 - * grant_type string 是 填写 client_credential - * appid string 是 小程序唯一凭证,即 AppID,可在「微信公众平台 - 设置 - 开发设置」页中获得。(需要已经成为开发者,且帐号没有异常状态) - * secret string 是 小程序唯一凭证密钥,即 AppSecret,获取方式同 appid - * 返回值 - * Object - * 返回的 JSON 数据包 - * <p> - * 属性 类型 说明 - * access_token string 获取到的凭证 - * expires_in number 凭证有效时间,单位:秒。目前是7200秒之内的值。 - * errcode number 错误码 - * errmsg string 错误信息 - */ - private static String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}"; - - /** - * @return - */ - public String getAccessToken() { - String requestUrl = MessageFormat.format(ACCESS_TOKEN_URL, wxConfig.getAppId(), wxConfig.getSecret()); - String respBody = restTemplate.getForEntity(requestUrl, String.class).getBody(); - JSONObject jsonObject = JSONObject.parseObject(respBody); - return jsonObject.getString("access_token"); - } -} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/importExcel/TLocationImportExcel.java b/ruoyi-system/src/main/java/com/ruoyi/system/importExcel/TLocationImportExcel.java index 67423d5..cb9bff8 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/importExcel/TLocationImportExcel.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/importExcel/TLocationImportExcel.java @@ -10,39 +10,39 @@ @ApiModel(value = "点位导入excel") public class TLocationImportExcel implements Serializable { - @Excel(name = "项目部编号") + @Excel(name = "项目部编号",width = 20) private String deptCode; - @Excel(name = "项目部名称") + @Excel(name = "项目部名称",width = 20) private String deptName; - @Excel(name = "基层管理员部门编号") + @Excel(name = "基层管理员部门编号",width = 20) private String deptNumber; - @Excel(name = "基层管理员项目部编号") + @Excel(name = "基层管理员项目部编号",width = 20) private String projectDeptNumber; - @Excel(name = "基层管理员姓名 巡检员") + @Excel(name = "基层管理员姓名 巡检员",width = 20) private String nickName; - @Excel(name = "保洁员部门编号") - private String projectCodeClear; - @Excel(name = "保洁员项目部编号") + @Excel(name = "保洁员部门编号",width = 20) private String deptCodeClear; - @Excel(name = "保洁员片区编号") + @Excel(name = "保洁员项目部编号",width = 20) + private String projectCodeClear; + @Excel(name = "保洁员片区编号",width = 20) private String cleanerCodeClear; - @Excel(name = "保洁员(驾驶员)") + @Excel(name = "保洁员(驾驶员)",width = 20) private String cleanerName; - @Excel(name = "路段总号") + @Excel(name = "路段总号",width = 20) private String locationCode; - @Excel(name = "个人编号") + @Excel(name = "个人编号",width = 20) private String cleanerCode; - @Excel(name = "点位类型") + @Excel(name = "点位类型",width = 20) private String locationType; - @Excel(name = "路段名(村名)") + @Excel(name = "路段名(村名)",width = 20) private String locationName; - @Excel(name = "起点") + @Excel(name = "起点",width = 20) private String locationAddress; - @Excel(name = "终点") + @Excel(name = "终点",width = 20) private String locationAddressEnd; - @Excel(name = "起点(经纬度)") + @Excel(name = "起点(经纬度)",width = 20) private String locationAddressLonLat; - @Excel(name = "终点(经纬度)") + @Excel(name = "终点(经纬度)",width = 20) private String locationAddressEndLonLat; } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/utils/JsonUtils.java b/ruoyi-system/src/main/java/com/ruoyi/system/utils/JsonUtils.java new file mode 100644 index 0000000..727ae96 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/utils/JsonUtils.java @@ -0,0 +1,110 @@ +package com.ruoyi.system.utils; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.ruoyi.common.exception.ServiceException; +import com.ruoyi.system.utils.wx.config.JacksonConfig; +import lombok.extern.slf4j.Slf4j; + +import java.io.IOException; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +/** + * Json转换工具类 + * 参考:https://blog.csdn.net/weixin_38413579/article/details/82562634 + * @author madman + */ +@Slf4j +public final class JsonUtils { + + private static final ObjectMapper OM = new ObjectMapper(); + private static final JavaTimeModule timeModule = new JavaTimeModule(); + + /** + * 转换LocalDateTime + */ + static class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> { + @Override + public void serialize(LocalDateTime localDateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { + jsonGenerator.writeString(localDateTime.format(DateTimeFormatter.ofPattern(JacksonConfig.dateTimeFormat))); + } + } + + /** + * 转换LocalDate + */ + static class LocalDateSerializer extends JsonSerializer<LocalDate> { + @Override + public void serialize(LocalDate localDate, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { + jsonGenerator.writeString(localDate.format(DateTimeFormatter.ofPattern(JacksonConfig.dateFormat))); + } + } + + /** + * 设置 ObjectMapper + * + * @return + */ + private static ObjectMapper getObjectMapper() { + // 序列化 + timeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer()); + timeModule.addSerializer(LocalDate.class, new LocalDateSerializer()); + // 反序列化 + timeModule.addDeserializer(LocalDateTime.class, + new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(JacksonConfig.dateTimeFormat))); + timeModule.addDeserializer(LocalDate.class, + new LocalDateDeserializer(DateTimeFormatter.ofPattern(JacksonConfig.dateFormat))); + // 允许对象忽略json中不存在的属性 + OM.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + OM.registerModule(timeModule); + return OM; + } + + /** + * 将对象序列化 + */ + public static <T> String toJsonString(T obj) { + try { + ObjectMapper om = getObjectMapper(); + return om.writeValueAsString(obj); + } catch (JsonProcessingException e) { + log.error("转json字符串失败:{}", obj); + return null; + } + } + + /** + * 反序列化对象字符串 + */ + public static <T> T parseObject(String json, Class<T> clazz) { + try { + ObjectMapper om = getObjectMapper(); + return om.readValue(json, clazz); + } catch (JsonProcessingException e) { + throw new ServiceException("反序列化对象字符串失败"); + } + } + + /** + * 反序列化字符串成为对象 + */ + public static <T> T parseObject(String json, TypeReference<T> valueTypeRef) { + try { + ObjectMapper om = getObjectMapper(); + return om.readValue(json, valueTypeRef); + } catch (JsonProcessingException e) { + throw new ServiceException("反序列化字符串成为对象失败"); + } + } + +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/utils/TemplateMessageSendUtil.java b/ruoyi-system/src/main/java/com/ruoyi/system/utils/TemplateMessageSendUtil.java new file mode 100644 index 0000000..233a802 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/utils/TemplateMessageSendUtil.java @@ -0,0 +1,82 @@ +package com.ruoyi.system.utils; + + +import com.ruoyi.common.constant.Constants; +import com.ruoyi.common.core.redis.RedisCache; +import com.ruoyi.common.core.utils.HttpUtils; +import com.ruoyi.common.redis.service.RedisService; +import com.ruoyi.system.utils.wx.model.WeixinProperties; +import com.ruoyi.system.utils.wx.template.Template; +import com.ruoyi.system.utils.wx.template.wxTemplateTaskReturn.WxTemplateTaskResultRequest; +import com.ruoyi.system.utils.wx.template.wxTemplateTaskReturn.WxTemplateTaskResultRequestData; +import com.ruoyi.system.utils.wx.tools.WxAppletTools; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; +import org.springframework.web.client.RestTemplate; + +import javax.annotation.Resource; +import java.io.Serializable; + +/** + * 消息模板发送 + */ +@Slf4j +@Component +public class TemplateMessageSendUtil implements Serializable { + private final static String ACCESSTOKEN_CACHE_KEY = "accessToken:"; + @Autowired + private RedisCache redisCache; + @Autowired + private RestTemplate wxRestTemplate; + @Autowired + private WeixinProperties weixinProperties; + @Resource + private RedisService redisService; + + /** + * 任务数据提交结果通知 + * @param openId 用户openId + * @param taskName 任务名称 + * @param auditResult 审核结果 + * @param auditPerson 审核人 + */ + public void wxTemplateTaskResultRequest(String openId,String taskName,String auditResult,String auditPerson) { + WxAppletTools appletTools = new WxAppletTools(wxRestTemplate, weixinProperties, redisService); + // 1,获取access_token + String accessToken = redisCache.getCacheObject(ACCESSTOKEN_CACHE_KEY); + if (!StringUtils.hasLength(accessToken)) { + accessToken = appletTools.getAccessToken(); + } + try { + log.info("任务数据提交结果通知:------------------------"); + // 创建请求实体 + WxTemplateTaskResultRequest wxTemplateTaskResultRequest = new WxTemplateTaskResultRequest(); + wxTemplateTaskResultRequest.setTouser(openId); + wxTemplateTaskResultRequest.setTemplate_id(weixinProperties.getTaskResultTemplateId()); + // 任务名称 + Template thing1 = new Template(); + thing1.setValue(taskName); + // 审核结果 + Template phrase4 = new Template(); + phrase4.setValue(auditResult); + // 审核人 + Template thing3 = new Template(); + thing3.setValue(auditPerson); + // 发送模板消息参数实体封装 + WxTemplateTaskResultRequestData wxTemplateTaskResultRequestData = new WxTemplateTaskResultRequestData(); + wxTemplateTaskResultRequestData.setThing1(thing1); + wxTemplateTaskResultRequestData.setPhrase4(phrase4); + wxTemplateTaskResultRequestData.setThing3(thing3); + wxTemplateTaskResultRequest.setData(wxTemplateTaskResultRequestData); + // 4,发送消息给用户 + String url = Constants.TEMPLATE_URL.replace("ACCESS_TOKEN", accessToken); + String result = HttpUtils.sendPost(url, JsonUtils.toJsonString(wxTemplateTaskResultRequest)); + log.info("任务数据提交结果通知模板消息返回数据:{}", result); + } catch (Exception e) { + log.error("任务数据提交结果通知失败;"); + } + } + +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/config/JacksonConfig.java b/ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/config/JacksonConfig.java new file mode 100644 index 0000000..f96bb5a --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/config/JacksonConfig.java @@ -0,0 +1,35 @@ +package com.ruoyi.system.utils.wx.config; + +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.time.format.DateTimeFormatter; + +/** + * @author liheng + * @ClassName LocalDateTimeSerializerConfig + * @Description + * @date 2020-09-22 11:22 + */ +@Configuration +public class JacksonConfig { + public static final String dateFormat = "yyyy-MM-dd"; + public static final String dateTimeFormat = "yyyy-MM-dd HH:mm:ss"; + + @Bean + public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() { + return builder -> { + // Long型精度丢失问题 + // builder.serializerByType(Long.TYPE, ToStringSerializer.instance); + builder.serializerByType(Long.class, ToStringSerializer.instance); + // 时间格式化 + builder.simpleDateFormat(dateTimeFormat); + builder.serializers(new LocalDateSerializer(DateTimeFormatter.ofPattern(dateFormat))); + builder.serializers(new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(dateTimeFormat))); + }; + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/model/WeixinProperties.java b/ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/model/WeixinProperties.java index fdeb5ab..5a6d407 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/model/WeixinProperties.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/model/WeixinProperties.java @@ -37,6 +37,20 @@ * @return secret ID */ private String secretId; + /** + * 任务驳回通知 || 任务审核通过通知 + * + * @return secret ID + */ + private String taskResultTemplateId; + + public String getTaskResultTemplateId() { + return taskResultTemplateId; + } + + public void setTaskResultTemplateId(String taskResultTemplateId) { + this.taskResultTemplateId = taskResultTemplateId; + } public String getSecretId() { return secretId; diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/pojo/AppletUserEncrypteData.java b/ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/pojo/AppletUserEncrypteData.java index 16d0057..e018465 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/pojo/AppletUserEncrypteData.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/pojo/AppletUserEncrypteData.java @@ -15,6 +15,4 @@ private String rawData; private String signature; private String code; - @ApiModelProperty(value = "邀请用户id") - private Long inviteUserId; } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/template/Template.java b/ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/template/Template.java new file mode 100644 index 0000000..b2c9659 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/template/Template.java @@ -0,0 +1,19 @@ +package com.ruoyi.system.utils.wx.template; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +/** + * @Description 微信消息模板参数实体 + * @Author xiaochen + * @Date 2021/11/8 10:30 + */ +@Data +public class Template implements Serializable{ + + @ApiModelProperty(value = "消息内容") + private String value; + +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/template/wxTemplateTaskReturn/WxTemplateTaskResultRequest.java b/ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/template/wxTemplateTaskReturn/WxTemplateTaskResultRequest.java new file mode 100644 index 0000000..bb6c26c --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/template/wxTemplateTaskReturn/WxTemplateTaskResultRequest.java @@ -0,0 +1,22 @@ +package com.ruoyi.system.utils.wx.template.wxTemplateTaskReturn; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +@Data +@ApiModel(value = "任务驳回消息模板配置") +public class WxTemplateTaskResultRequest implements Serializable { + + @ApiModelProperty(value = "用户openid") + private String touser; + + @ApiModelProperty(value = "消息模板id") + private String template_id; + + @ApiModelProperty(value = "消息模板data数据") + private WxTemplateTaskResultRequestData data; + +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/template/wxTemplateTaskReturn/WxTemplateTaskResultRequestData.java b/ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/template/wxTemplateTaskReturn/WxTemplateTaskResultRequestData.java new file mode 100644 index 0000000..f0e7cd2 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/template/wxTemplateTaskReturn/WxTemplateTaskResultRequestData.java @@ -0,0 +1,23 @@ +package com.ruoyi.system.utils.wx.template.wxTemplateTaskReturn; + +import com.ruoyi.system.utils.wx.template.Template; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +@Data +@ApiModel(value = "任务驳回消息模板配置数据") +public class WxTemplateTaskResultRequestData implements Serializable { + + @ApiModelProperty(value = "任务名称") + private Template thing1; + + @ApiModelProperty(value = "审核结果") + private Template phrase4; + + @ApiModelProperty(value = "审核人") + private Template thing3; + +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/tools/WxAppletTools.java b/ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/tools/WxAppletTools.java index 2298a44..04a6198 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/tools/WxAppletTools.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/tools/WxAppletTools.java @@ -21,7 +21,7 @@ */ @Slf4j public class WxAppletTools { - private final static String ACCESSTOKEN_CACHE_KEY = "accessToken"; + private final static String ACCESSTOKEN_CACHE_KEY = "accessToken:"; /** * 请求参数 * 属性 类型 默认值 必填 说明 @@ -103,8 +103,8 @@ /** * @return */ - public String getAccessToken(String version) { - String accessToken = redisService.getCacheObject(ACCESSTOKEN_CACHE_KEY + version); + public String getAccessToken() { + String accessToken = redisService.getCacheObject(ACCESSTOKEN_CACHE_KEY); if (StringUtils.hasLength(accessToken)) { return accessToken; } @@ -116,7 +116,7 @@ // 抛出错误 throw new WxException(accessTokenRespBody.getErrorCode() + ":" + accessTokenRespBody.getErrorMsg()); } - redisService.setCacheObject(ACCESSTOKEN_CACHE_KEY + version, accessTokenRespBody.getAccessToken(), 7200L, TimeUnit.SECONDS); + redisService.setCacheObject(ACCESSTOKEN_CACHE_KEY, accessTokenRespBody.getAccessToken(), 7200L, TimeUnit.SECONDS); return accessTokenRespBody.getAccessToken(); } diff --git a/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml index 00038b0..a03756b 100644 --- a/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml @@ -28,6 +28,7 @@ <result property="businessDeptId" column="business_dept_id" /> <result property="roleName" column="role_name" /> <result property="code" column="code" /> + <result property="openId" column="openId" /> <result property="deptType" column="deptType" /> <association property="dept" javaType="SysDept" resultMap="deptResult" /> <collection property="roles" javaType="java.util.List" resultMap="RoleResult" /> @@ -413,6 +414,7 @@ <if test="deptType != null">deptType=#{deptType},</if> <if test="templateId != null">templateId=#{templateId},</if> <if test="code != null and code != ''">code = #{code},</if> + <if test="openId != null and openId != ''">openId = #{openId},</if> update_time = sysdate() </set> -- Gitblit v1.7.1