From 4e24321256a938f1ccc6c29b99a8f410779262b0 Mon Sep 17 00:00:00 2001
From: andy <1042025947@qq.com>
Date: Sat, 30 Aug 2025 09:37:55 +0800
Subject: [PATCH] =?UTF-8?q?=E8=80=83=E5=8B=A4=E6=96=B0=E5=A2=9E=E6=9C=AA?=
=?UTF-8?q?=E6=89=93=E5=8D=A1,=20=E5=BE=AE=E4=BF=A1=E5=85=AC=E4=BC=97?=
=?UTF-8?q?=E5=8F=B7=E9=80=9A=E7=9F=A5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
evo-admin/pom.xml | 12 ++
.../impl/KQDeviceExchangeProcessor.java | 83 +++-------
.../evo/common/controller/TestController.java | 31 ++++
.../common/core/domain/entity/SysDept.java | 3 +
.../com/evo/common/core/redis/RedisCache.java | 22 +++
.../evo/framework/config/SecurityConfig.java | 3 +-
.../impl/RzRestaurantDetailServiceImpl.java | 19 ++-
.../java/com/evo/system/domain/SysStaff.java | 5 +
.../java/com/evo/wechat/AccessTokenUtil.java | 48 ++++++
.../com/evo/wechat/TemplateMessageUtil.java | 28 ++++
.../java/com/evo/wechat/WeChatController.java | 67 ++++++++
.../com/evo/wechat/config/GZHProperties.java | 20 +++
.../dto/AbnormalAttendanceTemplate.java | 20 +++
.../com/evo/wechat/dto/MessageTemplate.java | 29 ++++
.../wechat/service/GZHAccessTokenService.java | 38 +++++
.../evo/wechat/service/SendClientService.java | 47 ++++++
.../mapper/system/SysStaffMapper.xml | 6 +-
.../src/main/resources/templates/success.html | 9 ++
.../main/resources/templates/user_info.html | 143 ++++++++++++++++++
19 files changed, 558 insertions(+), 75 deletions(-)
create mode 100644 evo-admin/src/main/java/com/evo/wechat/AccessTokenUtil.java
create mode 100644 evo-admin/src/main/java/com/evo/wechat/TemplateMessageUtil.java
create mode 100644 evo-admin/src/main/java/com/evo/wechat/WeChatController.java
create mode 100644 evo-admin/src/main/java/com/evo/wechat/config/GZHProperties.java
create mode 100644 evo-admin/src/main/java/com/evo/wechat/dto/AbnormalAttendanceTemplate.java
create mode 100644 evo-admin/src/main/java/com/evo/wechat/dto/MessageTemplate.java
create mode 100644 evo-admin/src/main/java/com/evo/wechat/service/GZHAccessTokenService.java
create mode 100644 evo-admin/src/main/java/com/evo/wechat/service/SendClientService.java
create mode 100644 evo-admin/src/main/resources/templates/success.html
create mode 100644 evo-admin/src/main/resources/templates/user_info.html
diff --git a/evo-admin/pom.xml b/evo-admin/pom.xml
index 4077ee3..170d4fc 100644
--- a/evo-admin/pom.xml
+++ b/evo-admin/pom.xml
@@ -229,6 +229,18 @@
gson
2.8.9
+
+
+
+ cn.hutool
+ hutool-http
+ 5.8.35
+
+
+
+ org.springframework.boot
+ spring-boot-starter-thymeleaf
+
diff --git a/evo-admin/src/main/java/com/evo/attendance/processor/impl/KQDeviceExchangeProcessor.java b/evo-admin/src/main/java/com/evo/attendance/processor/impl/KQDeviceExchangeProcessor.java
index ae7660f..59aab25 100644
--- a/evo-admin/src/main/java/com/evo/attendance/processor/impl/KQDeviceExchangeProcessor.java
+++ b/evo-admin/src/main/java/com/evo/attendance/processor/impl/KQDeviceExchangeProcessor.java
@@ -24,8 +24,10 @@ import com.evo.system.domain.SysStaffDetail;
import com.evo.system.mapper.SysDeptMapper;
import com.evo.system.mapper.SysStaffDetailMapper;
import com.evo.system.mapper.SysStaffMapper;
+import com.evo.wechat.service.SendClientService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
+import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@@ -63,6 +65,9 @@ public class KQDeviceExchangeProcessor implements PunchTheClockStrategyExchangeP
@Resource
private SysStaffDetailMapper sysStaffDetailMapper;
+ @Resource
+ private SendClientService sendClientService;
+
@Override
public boolean accept(String sn) {
//餐饮打卡机不下发按钮
@@ -222,81 +227,29 @@ public class KQDeviceExchangeProcessor implements PunchTheClockStrategyExchangeP
RzAttendance beforeAttendance = rzAttendanceMapper.queryNowDayAttendanceByStatisticalIdAndDate(Long.valueOf(userId),DateUtils.addDays(date, -1));
if(beforeAttendance.getWorkStartTime() != null && beforeAttendance.getWorkEndTime() == null){
notBeforeEndTimeMessage = " - 昨天未打下班卡";
+ sendAbnormalAttendance(userId, beforeAttendance.getWorkStartTime());
}
} catch (Exception e) {
e.printStackTrace();
log.error("查询前一天的打卡情况报错了");
}
-
return (rzAttendanceMapper.updateRzAttendance(attendance) > 0) ? initMessage(0, "打卡成功"+notBeforeEndTimeMessage) : initMessage(1, "打卡失败"+notBeforeEndTimeMessage);
}
-// /*** 上班卡的下班卡
-// * @param date
-// * @param rules
-// * @return
-// */
-// public String workOffDutyCard(Date date, String rules, RzAttendance attendance){
-//
-// //计算工时
-// Long hours = (date.getTime() - attendance.getWorkStartTime().getTime())/1000/60/60;
-//
-// EqButton eqButton = eqButtonMapper.selectOne(new LambdaQueryWrapper().eq(EqButton::getName, rules));
-//
-// Integer maxWorkHour = ParamUtils.getTsWorkHour(attendance.getName());
-// if(maxWorkHour == null){
-// maxWorkHour = eqButton.getWorkHour();
-// }
-//
-// //判断打卡时间, 添加夜班次数 打卡时间在晚上7点以后
-// if(eqButton.getWorkHour() ==12 && hours >= 12 && attendance.getWorkStartTime().getHours() > 12){
-// attendance.setNightNumber(1);
-// }else if(eqButton.getWorkHour() == 8 && hours >= 8 && attendance.getWorkStartTime().getHours() > 18){
-// attendance.setMiddleShiftNumber(1);
-// }
-// //获取工作时长
-// BigDecimal res = new BigDecimal(hours);
-// if(hours.compareTo(Long.valueOf(maxWorkHour)) >= 0){
-// res = new BigDecimal(maxWorkHour);
-// }
-//// else if(hours.compareTo(Long.valueOf(eqButton.getWorkHour()/2)) > 0){
-//// res = new BigDecimal(eqButton.getWorkHour()/2);
-//// }
-// //检查是否异常
-// if(checkYc("下班", rules, sdf.format(date), sdfd.format(date))){
-// attendance.setYcxFlag("1");
-// }
-//
-// attendance.setWorkEndTime(date);
-// attendance.setWorkSum(res);
-// return (rzAttendanceMapper.updateRzAttendance(attendance) > 0) ? initMessage(0, "打卡成功") : initMessage(1,"打卡失败");
-// }
+ @Async
+ public void sendAbnormalAttendance(Long userId, Date date){
+ try {
+ SysStaff sysStaff = sysStaffMapper.selectById(userId);
+ if(sysStaff != null && StringUtils.isNotEmpty(sysStaff.getOpenid())){
+ SysDept sysDept = sysDeptMapper.selectById(sysStaff.getDeptId());
+ sendClientService.sendAbnormalAttendance(sysDept != null ? sysDept.getDeptName() : "未知",sysStaff.getName(), "昨天下班未打卡", date, sysStaff.getOpenid());
+ }
+ } catch (Exception e) {
+ log.error("推送公众号打卡异常失败, 原因为: {}", e.getMessage(), e);
+ }
+ }
-// /*** 校验是否上班卡打卡异常
-// * @param rules
-// * @param dateTime
-// * @param date
-// * @return
-// */
-// public Boolean checkYc(String type, String rules, String dateTime, String date){
-// String script = ParamUtils.getYcRulesByButtonName(type, rules);
-// if(StringUtils.isEmpty(script)){
-// return false;
-// }
-// ScriptEngineManager manager = new ScriptEngineManager();
-// ScriptEngine engine = manager.getEngineByName("javascript");
-// try {
-// Object result = engine.eval(script.replaceAll("dkDateTime",dateTime).replaceAll("dkDate", date));
-// System.out.println("检查结果"+result);
-// return new Boolean(String.valueOf(result));
-// } catch (Exception e) {
-// logger.error("打卡交易是否异常出现错误{}", e.getMessage());
-// }
-// //默认为没有异常
-// return false;
-// }
-
/*** 撤销卡
* @param date
* @return
diff --git a/evo-admin/src/main/java/com/evo/common/controller/TestController.java b/evo-admin/src/main/java/com/evo/common/controller/TestController.java
index b00b269..e8230a1 100644
--- a/evo-admin/src/main/java/com/evo/common/controller/TestController.java
+++ b/evo-admin/src/main/java/com/evo/common/controller/TestController.java
@@ -12,6 +12,7 @@ import com.evo.personnelMatters.mapper.RzOverTimeMapper;
import com.evo.restaurant.service.IRzRestaurantStatisticsService;
import com.evo.system.domain.SysStaff;
import com.evo.system.service.ISysStaffService;
+import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -81,6 +82,36 @@ public class TestController {
+ @GetMapping("/message")
+ public String message(Model model, String code) {
+
+ System.out.println(code);
+// String res = AccessTokenUtil.accessToken2("wx268e32962db19f5f", "84a6065165ec82862c5e03a010a6dc6c", code);
+// System.out.println(res);
+// JSONObject obj = JSONObject.parseObject(res);
+// String openid = obj.getString("openid");
+ SysStaff user = new SysStaff();
+ user.setOpenid(code);
+ model.addAttribute("user", user);
+ //model.addAttribute("openid", openid);
+// ErrorData templateData = new ErrorData();
+//
+// templateData.setThing1((JSONObject)JSON.toJSON(Collections.asMap("value", "研发部")));
+// templateData.setThing2((JSONObject)JSON.toJSON(Collections.asMap("value", "张三")));//动态跟换车牌号
+// templateData.setConst4((JSONObject)JSON.toJSON(Collections.asMap("value", "昨天下班未打卡")));//动态跟换车牌号
+// templateData.setTime6((JSONObject)JSON.toJSON(Collections.asMap("value", DateUtil.format(new Date(), "yyyy年MM月dd日"))));//动态跟换车牌号
+//
+// MessageTemplateSendData sendData = new MessageTemplateSendData();
+// sendData.setTouser(openid);
+// sendData.setTemplate_id("z9sy-38K-iC5MAWHbxcxwg1c-9oNTFWeCOoy6B6zdKY");
+// sendData.setData((JSONObject)JSON.toJSON(templateData));
+// TemplateMessageUtil.templateMessageSend(GZHAccessTokenService.gzhAccessToken(), sendData);
+
+ return "user_info.html";
+ }
+
+
+
/**
* 清洗加班
*/
diff --git a/evo-admin/src/main/java/com/evo/common/core/domain/entity/SysDept.java b/evo-admin/src/main/java/com/evo/common/core/domain/entity/SysDept.java
index d4550b5..6419c53 100644
--- a/evo-admin/src/main/java/com/evo/common/core/domain/entity/SysDept.java
+++ b/evo-admin/src/main/java/com/evo/common/core/domain/entity/SysDept.java
@@ -7,7 +7,9 @@ import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
+import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
@@ -24,6 +26,7 @@ public class SysDept extends BaseEntity
private static final long serialVersionUID = 1L;
/** 部门ID */
+ @TableId(value = "dept_id", type = IdType.AUTO)
private Long deptId;
/** 父部门ID */
diff --git a/evo-admin/src/main/java/com/evo/common/core/redis/RedisCache.java b/evo-admin/src/main/java/com/evo/common/core/redis/RedisCache.java
index ff18910..1982513 100644
--- a/evo-admin/src/main/java/com/evo/common/core/redis/RedisCache.java
+++ b/evo-admin/src/main/java/com/evo/common/core/redis/RedisCache.java
@@ -36,6 +36,28 @@ public class RedisCache
redisTemplate.opsForValue().set(key, value);
}
+ /**
+ * 缓存基本的对象,Integer、String、实体类等
+ *
+ * @param key 缓存的键值
+ * @param value 缓存的值
+ * @param timeout 时间
+ * @param timeUnit 时间颗粒度
+ */
+ public void setCacheObject(final String key, final T value, final Long timeout)
+ {
+ try {
+ if (timeout > 0) {
+ redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
+ } else {
+ setCacheObject(key, value);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+
/**
* 缓存基本的对象,Integer、String、实体类等
*
diff --git a/evo-admin/src/main/java/com/evo/framework/config/SecurityConfig.java b/evo-admin/src/main/java/com/evo/framework/config/SecurityConfig.java
index 240c5d3..254268a 100644
--- a/evo-admin/src/main/java/com/evo/framework/config/SecurityConfig.java
+++ b/evo-admin/src/main/java/com/evo/framework/config/SecurityConfig.java
@@ -116,7 +116,8 @@ public class SecurityConfig
// 静态资源,可匿名访问
.antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
.antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
- .antMatchers("/websocket/**").permitAll()
+ .antMatchers("/wechat/**").permitAll()
+ .antMatchers("/websocket/**").permitAll()
.antMatchers("/test/**").permitAll()
.antMatchers("/api/v1/verify_user").permitAll()
.antMatchers("/api/v1/record/face").permitAll()
diff --git a/evo-admin/src/main/java/com/evo/restaurant/service/impl/RzRestaurantDetailServiceImpl.java b/evo-admin/src/main/java/com/evo/restaurant/service/impl/RzRestaurantDetailServiceImpl.java
index 5073cd4..4851c23 100644
--- a/evo-admin/src/main/java/com/evo/restaurant/service/impl/RzRestaurantDetailServiceImpl.java
+++ b/evo-admin/src/main/java/com/evo/restaurant/service/impl/RzRestaurantDetailServiceImpl.java
@@ -2,10 +2,7 @@ package com.evo.restaurant.service.impl;
import com.alibaba.fastjson2.JSONObject;
import com.evo.common.constant.Constants;
-import com.evo.common.core.domain.AjaxResult;
-import com.evo.common.utils.DateUtils;
import com.evo.common.utils.ParamUtils;
-import com.evo.common.utils.SecurityUtils;
import com.evo.common.utils.StringUtils;
import com.evo.restaurant.domain.RzRestaurantDetail;
import com.evo.restaurant.domain.RzRestaurantImages;
@@ -19,6 +16,7 @@ import com.evo.restaurant.service.IRzRestaurantDetailService;
import com.evo.system.domain.SysStaff;
import com.evo.system.mapper.SysStaffMapper;
import org.springframework.stereotype.Service;
+
import javax.annotation.Resource;
import java.util.Calendar;
import java.util.Date;
@@ -63,6 +61,7 @@ public class RzRestaurantDetailServiceImpl implements IRzRestaurantDetailService
@Override
public String insertRzRestaurantDetail(String json)
{
+ System.out.println(json.toString());
//需要返回的对象
RestaurantVo cfiv = new RestaurantVo();
RestaurantData cfd = new RestaurantData();
@@ -76,7 +75,8 @@ public class RzRestaurantDetailServiceImpl implements IRzRestaurantDetailService
//if(hour!=7&&hour!=8&&hour!=11&&hour!=12&&hour!=13&&hour!=18&&hour!=19&&hour!=20){
if(!ParamUtils.getCanteenOpenHour().contains(hour)){
cfiv.setResult(2);
- cfiv.setMsg("{\"Result\":1,\"Msg\":\"不在打卡时间内\"}");
+ cfiv.setMsg("不在打卡时间内");
+ System.out.println(JSONObject.toJSONString(cfiv));
return JSONObject.toJSONString(cfiv);
}
@@ -90,7 +90,7 @@ public class RzRestaurantDetailServiceImpl implements IRzRestaurantDetailService
RzRestaurantImages img_obj = rzRestaurantImagesMapper.selectRzRestaurantImagesById(Long.valueOf(userId));
if(StringUtils.isNull(sysStaff) && StringUtils.isNull(img_obj)){
cfiv.setResult(2);
- cfiv.setMsg("{\"Result\":1,\"Msg\":\"验证失败,未设置考勤权限\"}");
+ cfiv.setMsg("当前人员信息不存在");
return JSONObject.toJSONString(cfiv);
}
@@ -100,6 +100,9 @@ public class RzRestaurantDetailServiceImpl implements IRzRestaurantDetailService
if(StringUtils.isNotNull(restaurantDetail) && (new Date().getTime() - restaurantDetail.getTime().getTime()) < 1000*60*60*3){
//如果不是第一次打卡,则弹窗提示
cfiv.setResult(1);
+ //返回打卡次数
+ cfd.setClock_in_count(1);
+ cfiv.setContent(cfd);
cfiv.setMsg("重复打卡!!");
return JSONObject.toJSONString(cfiv);
}
@@ -134,17 +137,17 @@ public class RzRestaurantDetailServiceImpl implements IRzRestaurantDetailService
int i = rzRestaurantDetailMapper.insertRzRestaurantDetail(cyFaceInfo);
if(i<1){
cfiv.setResult(2);
- cfiv.setMsg("{\"Result\":1,\"Msg\":\"打卡失败\"}");
+ cfiv.setMsg("打卡失败");
return JSONObject.toJSONString(cfiv);
}
//反写统计次数
i = rzRestaurantStatisticsMapper.updateRzRestaurantStatistics(restaurantStatistics);
if(i<1){
cfiv.setResult(2);
- cfiv.setMsg("{\"Result\":1,\"Msg\":\"打卡失败\"}");
+ cfiv.setMsg("打卡失败");
return JSONObject.toJSONString(cfiv);
}
- cfiv.setMsg("{\"Result\":1,\"Msg\":\"打卡成功!\"}");
+ cfiv.setMsg("打卡成功");
cfd.setClock_in_count(1);
cfiv.setContent(cfd);
cfiv.setResult(0);
diff --git a/evo-admin/src/main/java/com/evo/system/domain/SysStaff.java b/evo-admin/src/main/java/com/evo/system/domain/SysStaff.java
index 813862c..f4dc611 100644
--- a/evo-admin/src/main/java/com/evo/system/domain/SysStaff.java
+++ b/evo-admin/src/main/java/com/evo/system/domain/SysStaff.java
@@ -198,6 +198,11 @@ public class SysStaff extends BaseEntity
* 打卡位置
*/
private String timeClock;
+
+ /***
+ * 公众号的openId
+ */
+ private String openid;
/***
* 享有补贴
*/
diff --git a/evo-admin/src/main/java/com/evo/wechat/AccessTokenUtil.java b/evo-admin/src/main/java/com/evo/wechat/AccessTokenUtil.java
new file mode 100644
index 0000000..b850b9d
--- /dev/null
+++ b/evo-admin/src/main/java/com/evo/wechat/AccessTokenUtil.java
@@ -0,0 +1,48 @@
+package com.evo.wechat;
+
+import cn.hutool.http.HttpUtil;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 调用凭据
+ */
+public class AccessTokenUtil {
+
+ private static String accessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token";
+
+
+ /**
+ * 获取接口调用凭据
+ * GET https://api.weixin.qq.com/cgi-bin/token
+ * @param appid
+ * @param secret
+ * @return
+ */
+ public static String accessToken(String appid, String secret) {
+ Map m = new HashMap();
+ m.put("appid", appid);
+ m.put("secret", secret);
+ m.put("grant_type", "client_credential");
+ String res = HttpUtil.get(accessTokenUrl, m);
+ return res;
+ }
+
+ private static String accessTokenUrl2 = "https://api.weixin.qq.com/sns/oauth2/access_token";
+ /**
+ * 获取接口调用凭据
+ * GET https://api.weixin.qq.com/cgi-bin/token
+ * @return
+ */
+ public static String accessToken2(String appid, String secret, String code) {
+ Map m = new HashMap();
+ m.put("appid",appid);
+ m.put("secret", secret);
+ m.put("code", code);
+ m.put("grant_type", "authorization_code");
+ String res = HttpUtil.get(accessTokenUrl2, m);
+ return res;
+ }
+
+}
diff --git a/evo-admin/src/main/java/com/evo/wechat/TemplateMessageUtil.java b/evo-admin/src/main/java/com/evo/wechat/TemplateMessageUtil.java
new file mode 100644
index 0000000..b2bfeb6
--- /dev/null
+++ b/evo-admin/src/main/java/com/evo/wechat/TemplateMessageUtil.java
@@ -0,0 +1,28 @@
+package com.evo.wechat;
+
+
+import cn.hutool.http.HttpRequest;
+import com.alibaba.fastjson2.JSONObject;
+import com.evo.wechat.dto.MessageTemplate;
+
+public class TemplateMessageUtil {
+
+
+ private static String templateSendUrl = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=";
+
+ /**
+ * 发送模板消息 POST
+ * @param accessToken
+ * @param templateData
+ * @return
+ */
+ public static String templateMessageSend(String accessToken, MessageTemplate templateData) {
+ String body = JSONObject.toJSONString(templateData);
+ String res = HttpRequest.post(templateSendUrl + accessToken)
+ .header("Content-Type", "application/json")
+ .body(body)
+ .execute()
+ .body();
+ return res;
+ }
+}
diff --git a/evo-admin/src/main/java/com/evo/wechat/WeChatController.java b/evo-admin/src/main/java/com/evo/wechat/WeChatController.java
new file mode 100644
index 0000000..06b5b4f
--- /dev/null
+++ b/evo-admin/src/main/java/com/evo/wechat/WeChatController.java
@@ -0,0 +1,67 @@
+package com.evo.wechat;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.evo.system.domain.SysStaff;
+import com.evo.system.service.ISysStaffService;
+import com.evo.wechat.config.GZHProperties;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ObjectUtils;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import javax.annotation.Resource;
+
+/**
+ * 类
+ *
+ * @ClassName:WeChatController
+ * @date: 2025年08月29日 16:39
+ * @author: andy.shi
+ * @remark: 开发人员联系方式 1042025947@qq.com/微信同步
+ */
+@Slf4j
+@Controller
+@RequestMapping("/wechat")
+public class WeChatController {
+
+ @Resource
+ private GZHProperties gzhProperties;
+ @Resource
+ private ISysStaffService sysStaffService;
+
+
+ @GetMapping("/callback")
+ public String message(Model model, String code) {
+ log.info("获取到的code{}", code);
+ String res = AccessTokenUtil.accessToken2(gzhProperties.getAppid(), gzhProperties.getAppSecret(), code);
+ log.info("获取到的openId相关信息{}", code);
+ JSONObject obj = JSONObject.parseObject(res);
+ SysStaff user = new SysStaff();
+ user.setOpenid(obj.getString("openid"));
+ model.addAttribute("user", user);
+ return "user_info.html";
+ }
+
+ @PostMapping("/submit_user")
+ public String submitUser(Model model, @ModelAttribute("user") SysStaff user) {
+ log.info("获取到的code{}", user.toString());
+
+ SysStaff sysStaff = sysStaffService.getOne(new LambdaQueryWrapper().eq(SysStaff::getIdCard, user.getIdCard()), false);
+ if(ObjectUtils.isEmpty(sysStaff)){
+ sysStaff = sysStaffService.getOne(new LambdaQueryWrapper().eq(SysStaff::getPhone, user.getPhone()), false);
+ }
+ if(ObjectUtils.isEmpty(sysStaff)){
+ model.addAttribute("message", "处理失败, 请检查你的个人信息录入是否正确");
+ return "success.html";
+ }
+ sysStaff.setOpenid(user.getOpenid());
+ sysStaffService.updateById(sysStaff);
+ model.addAttribute("message", "处理成功");
+ return "success.html";
+ }
+}
diff --git a/evo-admin/src/main/java/com/evo/wechat/config/GZHProperties.java b/evo-admin/src/main/java/com/evo/wechat/config/GZHProperties.java
new file mode 100644
index 0000000..f904ecd
--- /dev/null
+++ b/evo-admin/src/main/java/com/evo/wechat/config/GZHProperties.java
@@ -0,0 +1,20 @@
+package com.evo.wechat.config;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@ConfigurationProperties(prefix = "yt.gzh", ignoreUnknownFields = true)
+@Data
+@Schema(description = "公众号信息")
+public class GZHProperties {
+
+ private String appid;
+
+ private String appSecret;
+ //打卡异常通知
+ private String abnormalAttendanceTemplateId;
+
+}
diff --git a/evo-admin/src/main/java/com/evo/wechat/dto/AbnormalAttendanceTemplate.java b/evo-admin/src/main/java/com/evo/wechat/dto/AbnormalAttendanceTemplate.java
new file mode 100644
index 0000000..088d163
--- /dev/null
+++ b/evo-admin/src/main/java/com/evo/wechat/dto/AbnormalAttendanceTemplate.java
@@ -0,0 +1,20 @@
+package com.evo.wechat.dto;
+
+import com.alibaba.fastjson2.JSONObject;
+import lombok.Data;
+
+/**
+ * 考勤异常消息模版
+ */
+@Data
+public class AbnormalAttendanceTemplate {
+ //部门
+ private JSONObject thing1;
+ //姓名
+ private JSONObject thing2;
+ //异常类型 昨天上班未打卡 or 昨天下班未打卡
+ private JSONObject const4;
+ //考勤异常日期
+ private JSONObject time6;
+
+}
diff --git a/evo-admin/src/main/java/com/evo/wechat/dto/MessageTemplate.java b/evo-admin/src/main/java/com/evo/wechat/dto/MessageTemplate.java
new file mode 100644
index 0000000..825a02d
--- /dev/null
+++ b/evo-admin/src/main/java/com/evo/wechat/dto/MessageTemplate.java
@@ -0,0 +1,29 @@
+package com.evo.wechat.dto;
+
+import com.alibaba.fastjson2.JSONObject;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class MessageTemplate implements Serializable {
+
+ private static final long serialVersionUID = -8911097073333862L;
+
+ private String touser;
+
+ private String template_id;
+
+ @Schema(description = "模板跳转链接")
+ private String url;
+
+ @Schema(description = "防重入id。对于同一个openid + client_msg_id, 只发送一条消息,10分钟有效")
+ private String client_msg_id;
+
+ @Schema(description = "模板数据")
+ private JSONObject data;
+
+}
+
+
diff --git a/evo-admin/src/main/java/com/evo/wechat/service/GZHAccessTokenService.java b/evo-admin/src/main/java/com/evo/wechat/service/GZHAccessTokenService.java
new file mode 100644
index 0000000..9002c40
--- /dev/null
+++ b/evo-admin/src/main/java/com/evo/wechat/service/GZHAccessTokenService.java
@@ -0,0 +1,38 @@
+package com.evo.wechat.service;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.evo.common.core.redis.RedisCache;
+import com.evo.wechat.AccessTokenUtil;
+import com.evo.wechat.config.GZHProperties;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+import javax.annotation.Resource;
+
+@Service
+public class GZHAccessTokenService {
+
+ @Resource
+ GZHProperties gzhProperties;
+ @Resource
+ private RedisCache redisUtil;
+
+ private String accessTokenPrefix = "hd:wechat:accessToken:gzh:";
+
+ public String gzhAccessToken() {
+
+ if (redisUtil.hasKey(accessTokenPrefix + gzhProperties.getAppid())) {
+ return redisUtil.getCacheObject(accessTokenPrefix + gzhProperties.getAppid()).toString();
+ }
+
+ String res = AccessTokenUtil.accessToken(gzhProperties.getAppid(),gzhProperties.getAppSecret());
+ JSONObject jo = JSONObject.parseObject(res);
+ // {"errcode":40013,"errmsg":"invalid appid rid: 6708ba65-0b425b74-4620599c"}
+ if (StringUtils.hasText(jo.getString("errcode"))) {
+ throw new RuntimeException(res);
+ }
+ redisUtil.setCacheObject(accessTokenPrefix + gzhProperties.getAppid(), jo.getString("access_token"), 7200L);
+ return jo.getString("access_token");
+ }
+
+}
diff --git a/evo-admin/src/main/java/com/evo/wechat/service/SendClientService.java b/evo-admin/src/main/java/com/evo/wechat/service/SendClientService.java
new file mode 100644
index 0000000..ce57390
--- /dev/null
+++ b/evo-admin/src/main/java/com/evo/wechat/service/SendClientService.java
@@ -0,0 +1,47 @@
+package com.evo.wechat.service;
+
+import cn.hutool.core.date.DateUtil;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.evo.common.utils.Collections;
+import com.evo.wechat.TemplateMessageUtil;
+import com.evo.wechat.config.GZHProperties;
+import com.evo.wechat.dto.AbnormalAttendanceTemplate;
+import com.evo.wechat.dto.MessageTemplate;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.Date;
+
+/**
+ * 类
+ *
+ * @ClassName:SendClientService
+ * @date: 2025年08月29日 16:53
+ * @author: andy.shi
+ * @remark: 开发人员联系方式 1042025947@qq.com/微信同步
+ */
+@Service
+public class SendClientService {
+
+ @Resource
+ GZHAccessTokenService gzhAccessTokenService;
+ @Resource
+ GZHProperties gzhProperties;
+
+
+ public void sendAbnormalAttendance(String deptName, String userName, String info, Date date, String openId){
+ AbnormalAttendanceTemplate templateData = new AbnormalAttendanceTemplate();
+ templateData.setThing1((JSONObject) JSON.toJSON(Collections.asMap("value", deptName)));
+ templateData.setThing2((JSONObject)JSON.toJSON(Collections.asMap("value",userName)));//动态跟换车牌号
+ templateData.setConst4((JSONObject)JSON.toJSON(Collections.asMap("value", info)));//动态跟换车牌号
+ templateData.setTime6((JSONObject)JSON.toJSON(Collections.asMap("value", DateUtil.format(date, "yyyy年MM月dd日"))));//动态跟换车牌号
+
+ MessageTemplate sendData = new MessageTemplate();
+ sendData.setTouser(openId);
+ sendData.setTemplate_id(gzhProperties.getAbnormalAttendanceTemplateId());
+ sendData.setData((JSONObject)JSON.toJSON(templateData));
+ TemplateMessageUtil.templateMessageSend(gzhAccessTokenService.gzhAccessToken(), sendData);
+ }
+
+}
diff --git a/evo-admin/src/main/resources/mapper/system/SysStaffMapper.xml b/evo-admin/src/main/resources/mapper/system/SysStaffMapper.xml
index 9236a02..32ed1df 100644
--- a/evo-admin/src/main/resources/mapper/system/SysStaffMapper.xml
+++ b/evo-admin/src/main/resources/mapper/system/SysStaffMapper.xml
@@ -52,7 +52,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
- select user_id,company_name, dept_id, code, name, id_card,is_leader, sex, age, phone, address, level, major, school, bank_number,social_subsidy, bank, employment_date, experience, worker_term, regular_date, quit_date, contract_start, contract_end, contract_type, social_type, seniority, is_overtime_pay, zs_flag, secrecy, injury, insurance, introducer, clock_in, status, wages_ratio_date, remarks, del_flag, create_by, create_time, update_by, update_time, image_url,time_clock,subsidys, job_code from sys_staff
+ select user_id,company_name, dept_id, code, name, id_card,is_leader, sex, age, phone, address, level, major, school, bank_number,social_subsidy, bank, employment_date, experience, worker_term, regular_date, quit_date, contract_start, contract_end, contract_type, social_type, seniority, is_overtime_pay, zs_flag, secrecy, injury, insurance, introducer, clock_in, status, wages_ratio_date, remarks, del_flag, create_by, create_time, update_by, update_time, image_url,time_clock,subsidys, job_code, openid from sys_staff