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 +

+ + + +
+ + +

+
+ + +
+ + +

+
+ + + + + + + + +
+ +
+ + + +
+ + +
+ + + + + + +