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