diff --git a/src/main/java/com/budwk/app/base/sms/SmsService.java b/src/main/java/com/budwk/app/base/sms/SmsService.java index df7cd4d..8f874c1 100644 --- a/src/main/java/com/budwk/app/base/sms/SmsService.java +++ b/src/main/java/com/budwk/app/base/sms/SmsService.java @@ -4,36 +4,7 @@ import java.util.List; public interface SmsService { - /** - * 单发 - * @param loginName 工号 - * @param content 内容 - */ - void send(String loginName, String content); + void send(String mobile, String content); - /** - * 单发 - * @param loginName 工号 - * @param title 标题 - * @param content 内容 - */ - void send(String loginName, String title, String content); - - /** - * 单发 - * @param loginName 工号 - * @param title 标题 - * @param content 内容 - * @param link 链接 - */ - void send(String loginName, String title, String content, String link); - - /** - * 群发 多人接收内容相同时使用该方法 - * @param loginNames 工号 - * @param title 标题 - * @param content 内容 - * @param link 链接 - */ - void massSend(List loginNames, String title, String content, String link); + void massSend(List mobile, String content); } diff --git a/src/main/java/com/budwk/app/base/sms/impl/SmsWhcpServiceImpl.java b/src/main/java/com/budwk/app/base/sms/impl/SmsWhcpServiceImpl.java new file mode 100644 index 0000000..d32ad96 --- /dev/null +++ b/src/main/java/com/budwk/app/base/sms/impl/SmsWhcpServiceImpl.java @@ -0,0 +1,73 @@ +package com.budwk.app.base.sms.impl; + +import cn.hutool.crypto.SecureUtil; +import cn.hutool.http.HttpRequest; +import cn.hutool.json.JSONUtil; +import com.alibaba.fastjson.JSONObject; +import com.budwk.app.base.sms.SmsService; +import com.budwk.app.web.commons.base.Globals; +import com.google.common.net.MediaType; +import lombok.extern.slf4j.Slf4j; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.json.Json; +import org.nutz.lang.Lang; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * @ClassName SmsWhcpServiceImpl + * @Author JyuHsin + * @Date 2026/3/16 14:08 + * @Version 1.0 + * @Description TODO + */ +@Slf4j +@IocBean +public class SmsWhcpServiceImpl implements SmsService { + + @Override + public void send(String mobile, String content) { + this.doSend(mobile, content); + } + + @Override + public void massSend(List mobiles, String content) { + if (Lang.isEmpty(mobiles)) { + return; + } + String formatMobile = String.join(",", mobiles); + this.doSend(formatMobile, content); + } + + private void doSend(String mobile, String content) { + if (!Globals.sso) { + log.info("【log】本地开发环境,不允许调用短信消息接口"); + return; + } + + String urls = "https://api-shss.zthysms.com/v2/sendSms"; + + long tKey = System.currentTimeMillis() / 1000; + JSONObject json = new JSONObject(); + json.put("username", "whszyxy"); + json.put("password", SecureUtil.md5(SecureUtil.md5("Whszyxy123") + tKey)); + json.put("tKey", tKey + ""); + json.put("mobile", mobile); + json.put("content", "【智慧工会】" + content); + + log.info("【log】调用短信消息接口,请求参数:{}", Json.toJson(json)); + String result = HttpRequest.post(urls) + .header("Content-Type", "application/json") + .timeout(60000) + .body(json.toJSONString()).execute().body(); + log.info("【log】调用短信消息接口,接口响应数据:{}", result); + + JSONObject resultJsonBody = JSONObject.parseObject(result); + if (resultJsonBody.getInteger("code") == 200) { + log.info("【log】调用短信消息接口成功"); + } else { + log.info("【log】调用短信消息接口失败:{}", resultJsonBody.getString("msg")); + } + } +} diff --git a/src/main/java/com/budwk/app/base/sms/impl/jshvc/SmsJshvcServiceImpl.java b/src/main/java/com/budwk/app/base/sms/impl/jshvc/SmsJshvcServiceImpl.java deleted file mode 100644 index 9eeb4bb..0000000 --- a/src/main/java/com/budwk/app/base/sms/impl/jshvc/SmsJshvcServiceImpl.java +++ /dev/null @@ -1,150 +0,0 @@ -package com.budwk.app.base.sms.impl.jshvc; - -import cn.hutool.core.util.StrUtil; -import cn.hutool.crypto.digest.DigestUtil; -import cn.hutool.http.HttpRequest; -import cn.hutool.http.HttpResponse; -import com.budwk.app.base.sms.SmsService; -import lombok.extern.slf4j.Slf4j; -import org.nutz.integration.jedis.RedisService; -import org.nutz.ioc.loader.annotation.Inject; -import org.nutz.ioc.loader.annotation.IocBean; -import org.nutz.json.Json; -import org.nutz.lang.Lang; -import org.nutz.lang.util.NutMap; - -import java.util.List; -import java.util.Map; - -/** - * @ClassName SmsJshvcServiceImpl - * @Author JyuHsin - * @Date 2025/11/26 19:32 - * @Version 1.0 - * @Description TODO - */ -@Slf4j -@IocBean -public class SmsJshvcServiceImpl implements SmsService { - - private static final String APPID = "1430576717768122368"; - private static final String APP_SECRET = "19A0ACB03FBQHL4R4XQD"; - private static final String TOKEN_URL = "https://gateway.jshvc.edu.cn/token/gateway/accessToken"; - private static final String MSG_URL = "https://gateway.jshvc.edu.cn/mp/restful/v2/message/send"; - private static final String REDIS_KEY_MSG_ACCESS_TOKEN = "msg:token:"; - - @Inject - private RedisService redisService; - - @Override - public void send(String loginName, String content) { -// send(loginName, "智慧工会", content); - } - - @Override - public void send(String loginName, String title, String content) { - send(loginName, "智慧工会", content, null); - } - - @Override - public void send(String loginName, String title, String content, String link) { -// Map paramMap = Map.of("userId", loginName); -// doSend(title, content, List.of(paramMap), link); - } - - @Override - public void massSend(List loginNames, String title, String content, String link) { -// List> receivers = loginNames.stream() -// .map(name -> Map.of("userId", name)) -// .toList(); -// doSend(title, content, receivers, link); - } - - /** - * sign: 请求签名:(accessToken + 第一个receivers 的userID )的32位小写的MD5加密值,其中如果相应部分没有则忽略 - * msgType: 0: 普通消息(默认) 1: 必读消息 2: 验证码(为验证码时消息一定不入收件箱) - * expiredTime: 当msgType 为1必读消息 ,该字段为必填字段 格式:yyyy-MM-dd HH:mm:ss - * sendType: 1.只发送PC门户 2.只发送移动校园 3.邮件 4.短信 5.微信企业号 6.钉钉企业内部应用工作通知 7.微信服务号 8.welink - * wxSendType: 当发送类型为5时此字段才会生效:text(文本消息)、textcard(文本卡片)、nes(图文卡片,如果图文,则qyWeChatImgUrl必填)、button(按钮卡片详见示例),不传默认为text - * receiverType: 1:用户 2:用户组 3:部门,默认为1 - * - * @param title - * @param content - * @param receivers - */ - private void doSend(String title, String content, List> receivers, String link) { - - if (Lang.isEmpty(receivers)) { - log.error("send fail by receivers is null"); - return; - } - - // 获取token - String accessToken = buildAccessToken(); - // 获取第一个接收人的userID - String firstUserId = receivers.get(0).get("userId"); - // md5小写加密生成签名 - String sign = DigestUtil.md5Hex(accessToken + firstUserId); - - NutMap paramsMap = new NutMap(); - paramsMap.put("sign", sign); - paramsMap.put("msgType", "0"); - paramsMap.put("subject", title); - paramsMap.put("content", content); - paramsMap.put("sendType", "5"); - paramsMap.put("receivers", receivers); - if (StrUtil.isBlank(link)) { - paramsMap.put("wxSendType", "text"); - } else { - paramsMap.put("wxSendType", "textcard"); - paramsMap.put("mobileUrl", link); - // 这是图文卡片,后面用到再对接吧 - // paramsMap.put("qyWeChatImgUrl", ""); - } - - log.debug("send params: {}", Json.toJson(paramsMap)); - - HttpRequest request = HttpRequest.post(MSG_URL) - .header("appId", APPID) - .header("accessToken", accessToken) - .body(Json.toJson(paramsMap)); - - try { - HttpResponse response = request.execute(); - log.info("send response body: {}", response.body()); - - NutMap bodyMap = Json.fromJson(NutMap.class, response.body()); - if (bodyMap.getInt("status") == 200) { - log.info("send success code: {}, msg: {}", bodyMap.getInt("status"), bodyMap.getString("msg")); - } else { - log.error("send error code: {}, msg: {}", bodyMap.getInt("status"), bodyMap.getString("msg")); - } - } catch (Exception e) { - log.error("Failed to send: {}", e.getMessage(), e); - } - } - - private String buildAccessToken() { - String token = redisService.get(REDIS_KEY_MSG_ACCESS_TOKEN); - if (StrUtil.isNotBlank(token)) { - return token; - } - HttpRequest request = HttpRequest.get(TOKEN_URL); - request.header("appId", APPID); - request.header("appSecret", APP_SECRET); - - HttpResponse response = request.execute(); - - log.info("accessToken response: {}", Json.toJson(response.body())); - - NutMap bodyMap = Json.fromJson(NutMap.class, response.body()); - if (bodyMap.getInt("errcode") == 0) { - log.info("accessToken status: {}", bodyMap.getInt("errorcode")); - redisService.setex(REDIS_KEY_MSG_ACCESS_TOKEN, 60 * 120, bodyMap.getString("data")); - return bodyMap.getString("data"); - } else { - log.error("accessToken status: {}", bodyMap.getInt("errorcode")); - } - return ""; - } -} diff --git a/src/main/java/com/budwk/app/base/utils/MoneyUtil.java b/src/main/java/com/budwk/app/base/utils/MoneyUtil.java new file mode 100644 index 0000000..c489cb1 --- /dev/null +++ b/src/main/java/com/budwk/app/base/utils/MoneyUtil.java @@ -0,0 +1,166 @@ +package com.budwk.app.base.utils; +import java.math.BigDecimal; + +/** + * @author : hongqiwei + * @description : + * @createDate : 2026/1/20 15:41 + */ +public class MoneyUtil { + public MoneyUtil() { + } + + public static String toRMBUpper(String money) throws Exception { + boolean lessZero = false; + if (money.contains("E")) { + BigDecimal bg = new BigDecimal(Double.valueOf(money)); + money = bg.toPlainString(); + } + + if (money.startsWith("-")) { + money = money.substring(1); + lessZero = true; + } + + if (!money.matches("^[0-9]*$|^0+\\.[0-9]+$|^[1-9]+[0-9]*$|^[1-9]+[0-9]*.[0-9]+$")) { + throw new Exception("钱数格式错误!"); + } else { + String[] part = money.split("\\."); + String integerData = part[0]; + String decimalData = part.length > 1 ? part[1] : ""; + if (integerData.matches("^0+$")) { + integerData = "0"; + } else if (integerData.matches("^0+(\\d+)$")) { + integerData = integerData.replaceAll("^0+(\\d+)$", "$1"); + } + + StringBuffer integer = new StringBuffer(); + + for(int i = 0; i < integerData.length(); ++i) { + char perchar = integerData.charAt(i); + integer.append(upperNumber(perchar)); + integer.append(upperNumber(integerData.length() - i - 1)); + } + + StringBuffer decimal = new StringBuffer(); + if (part.length > 1 && !"00".equals(decimalData)) { + int length = decimalData.length() >= 2 ? 2 : decimalData.length(); + + for(int i = 0; i < length; ++i) { + char perchar = decimalData.charAt(i); + decimal.append(upperNumber(perchar)); + if (i == 0) { + decimal.append('角'); + } + + if (i == 1) { + decimal.append('分'); + } + } + } + + String var10000 = integer.toString(); + String result = var10000 + decimal.toString(); + result = dispose(result); + if (lessZero && !"零圆整".equals(result)) { + result = "负" + result; + } + + return result; + } + } + + private static char upperNumber(char number) { + switch (number) { + case '0' -> { + return '零'; + } + case '1' -> { + return '壹'; + } + case '2' -> { + return '贰'; + } + case '3' -> { + return '叁'; + } + case '4' -> { + return '肆'; + } + case '5' -> { + return '伍'; + } + case '6' -> { + return '陆'; + } + case '7' -> { + return '柒'; + } + case '8' -> { + return '捌'; + } + case '9' -> { + return '玖'; + } + default -> { + return '0'; + } + } + } + + private static char upperNumber(int index) { + int realIndex = index % 9; + if (index > 8) { + realIndex = (index - 9) % 8; + ++realIndex; + } + + switch (realIndex) { + case 0 -> { + return '圆'; + } + case 1 -> { + return '拾'; + } + case 2 -> { + return '佰'; + } + case 3 -> { + return '仟'; + } + case 4 -> { + return '万'; + } + case 5 -> { + return '拾'; + } + case 6 -> { + return '佰'; + } + case 7 -> { + return '仟'; + } + case 8 -> { + return '亿'; + } + default -> { + return '0'; + } + } + } + + private static String dispose(String result) { + result = result.replaceAll("0", ""); + result = result.replaceAll("零仟零佰零拾|零仟零佰|零佰零拾|零仟|零佰|零拾", "零"); + result = result.replaceAll("零+", "零").replace("零亿", "亿"); + result = result.matches("^.*亿零万[^零]仟.*$") ? result.replace("零万", "零") : result.replace("零万", "万"); + result = result.replace("亿万", "亿"); + result = result.replace("零角", "零").replace("零分", ""); + result = result.replaceAll("(^[零圆]*)(.+$)", "$2"); + result = result.replaceAll("(^.*)([零]+圆)(.+$)", "$1圆零$3"); + result = result.replaceAll("圆零角零分|圆零角$|圆$|^零$|圆零$|圆零零$|零圆$", "圆整"); + result = result.replaceAll("^圆整$", "零圆整"); + return result; + } +} + diff --git a/src/main/java/com/budwk/app/flow/controller/FlowCommonController.java b/src/main/java/com/budwk/app/flow/controller/FlowCommonController.java index 40c96f6..1437fa1 100644 --- a/src/main/java/com/budwk/app/flow/controller/FlowCommonController.java +++ b/src/main/java/com/budwk/app/flow/controller/FlowCommonController.java @@ -146,7 +146,7 @@ public class FlowCommonController { @ApiOperation("获取流程定义的审批记录") public Result approvalRecord(Long instanceId) { List processTaskList = dao.query(ProcessTask.class, Cnd.where(ProcessTask::getProcessInstanceId, "=", instanceId) - .and(ProcessTask::getTaskState, "not in", List.of(ProcessTaskStateEnum.DOING, ProcessTaskStateEnum.WITHDRAW, ProcessTaskStateEnum.ABANDON)) + .and(ProcessTask::getTaskState, "not in", List.of(ProcessTaskStateEnum.WITHDRAW, ProcessTaskStateEnum.ABANDON)) .asc(ProcessTask::getUpdatedAt)); List res = new ArrayList<>(); processTaskList.forEach(processTask -> { diff --git a/src/main/java/com/budwk/app/flow/listenter/ProcessTaskStartEventListener.java b/src/main/java/com/budwk/app/flow/listenter/ProcessTaskStartEventListener.java index d030783..fecf2eb 100644 --- a/src/main/java/com/budwk/app/flow/listenter/ProcessTaskStartEventListener.java +++ b/src/main/java/com/budwk/app/flow/listenter/ProcessTaskStartEventListener.java @@ -59,12 +59,9 @@ public class ProcessTaskStartEventListener implements ProcessEventListener { for (ProcessTaskActor taskActor : taskActors) { // 模拟发送消息 - String message = StrUtil.format("您有一条待办任务,实例:{},处理环节:{}", taskActor.getActorName(), instanceName, taskDisplayName); + String message = StrUtil.format("您有一条待办任务,实例:{},处理环节:{}", instanceName, taskDisplayName); log.info(message); globalMessageSendService.sendMessage(taskDisplayName, message, 2, List.of(taskActor.getActorId()), null); } - - } - } diff --git a/src/main/java/com/budwk/app/sys/services/impl/SysDataUserAllUpdateServiceImpl.java b/src/main/java/com/budwk/app/sys/services/impl/SysDataUserAllUpdateServiceImpl.java index ed607d1..d4177ac 100644 --- a/src/main/java/com/budwk/app/sys/services/impl/SysDataUserAllUpdateServiceImpl.java +++ b/src/main/java/com/budwk/app/sys/services/impl/SysDataUserAllUpdateServiceImpl.java @@ -5,6 +5,7 @@ import cn.hutool.core.collection.ListUtil; import cn.hutool.core.date.DateField; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; import cn.hutool.http.HtmlUtil; import com.budwk.app.base.constant.RoleConstant; import com.budwk.app.base.event.role.RoleEventMsg; @@ -22,6 +23,7 @@ import com.budwk.app.sys.services.SysUserService; import com.budwk.app.zhgh.democratic.proposal.models.ProposalConfig; import com.budwk.app.zhgh.staffmanage.member.constant.MemberChangeOrigin; import com.budwk.app.zhgh.staffmanage.member.constant.MemberChangeType; +import com.google.common.collect.Sets; import lombok.extern.slf4j.Slf4j; import org.nutz.aop.interceptor.ioc.TransAop; import org.nutz.dao.Chain; @@ -380,6 +382,29 @@ public class SysDataUserAllUpdateServiceImpl implements SysDataUserUpdateService RoleEventPublisher.broadcast(new RoleEventMsg(unitId, RoleConstant.PROPOSAL_BRANCH_SCHOOL_LEADER.name(), RoleEventMsg.RENEW_ROLE)); } + Set sourceSet = sources.stream().map(Sys_user_source::getLoginname).filter(StrUtil::isNotBlank).collect(Collectors.toSet()); + Set userSet = userMap.keySet(); + Set notExist = Sets.difference(userSet, sourceSet).immutableCopy(); + if (Lang.isNotEmpty(notExist)) { + executorService.execute(() -> { + try { + log.info("用户表中有数据,但数据源没有数据: {} 个", notExist.size()); + // 批量处理,避免IN子句过长 + List> batches = ListUtil.split(notExist.stream().toList(), 500); + for (List batch : batches) { + try { + dao.update(Sys_user.class, Chain.make("userState", "退休").add("member", false), Cnd.where("id", "in", batch)); + dao.clear(Sys_user_role.class, Cnd.where("userId", "in", batch).and("roleId", "=", memberRole.getId())); + } catch (Exception e) { + log.error("设置退休异常(用户表中有数据,但数据源没有数据)", e); + } + } + } catch (Exception e) { + log.error("设置退休异常(用户表中有数据,但数据源没有数据)", e); + } + }); + } + long endTime = System.currentTimeMillis(); log.info("全量更新用户数据完成,耗时: {} 毫秒", (endTime - startTime)); diff --git a/src/main/java/com/budwk/app/task/job/SysUserAllRenewJob.java b/src/main/java/com/budwk/app/task/job/SysUserAllRenewJob.java index 6d20f36..4ca0a98 100644 --- a/src/main/java/com/budwk/app/task/job/SysUserAllRenewJob.java +++ b/src/main/java/com/budwk/app/task/job/SysUserAllRenewJob.java @@ -57,6 +57,6 @@ public class SysUserAllRenewJob implements Job { param.setUpdateMode(SysDataUpdateMode.ALL.name()); param.setConditionGroup(conditionGroup); - // sysDataUserUpdateService.update(param); + sysDataUserUpdateService.update(param); } } diff --git a/src/main/java/com/budwk/app/web/commons/proc/CspProcessor.java b/src/main/java/com/budwk/app/web/commons/proc/CspProcessor.java index 02534db..40051d1 100644 --- a/src/main/java/com/budwk/app/web/commons/proc/CspProcessor.java +++ b/src/main/java/com/budwk/app/web/commons/proc/CspProcessor.java @@ -15,7 +15,7 @@ import java.util.Base64; public class CspProcessor extends AbstractProcessor { public void process(ActionContext ac) throws Throwable { - // 1. 生成 nonce + /*// 1. 生成 nonce String nonce = Base64.getEncoder().encodeToString( java.security.SecureRandom.getInstanceStrong().generateSeed(16) ); @@ -34,7 +34,7 @@ public class CspProcessor extends AbstractProcessor { "frame-ancestors 'self'; " + "object-src 'self';"; - ac.getResponse().setHeader("Content-Security-Policy", csp); + ac.getResponse().setHeader("Content-Security-Policy", csp);*/ doNext(ac); } diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/message/strategy/impl/SmsMessageSendStrategy.java b/src/main/java/com/budwk/app/zhgh/dayofficework/message/strategy/impl/SmsMessageSendStrategy.java index 78e3834..98aea8f 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/message/strategy/impl/SmsMessageSendStrategy.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/message/strategy/impl/SmsMessageSendStrategy.java @@ -1,6 +1,7 @@ package com.budwk.app.zhgh.dayofficework.message.strategy.impl; import cn.hutool.json.JSONObject; +import com.budwk.app.base.sms.SmsService; import com.budwk.app.sys.models.Sys_user; import com.budwk.app.zhgh.dayofficework.message.enums.GlobalMessageChannel; import com.budwk.app.zhgh.dayofficework.message.strategy.GlobalMessageSendStrategy; @@ -21,6 +22,8 @@ public class SmsMessageSendStrategy implements GlobalMessageSendStrategy { @Inject private Dao dao; + @Inject + private SmsService smsService; @Override public GlobalMessageChannel getChannel() { @@ -32,10 +35,10 @@ public class SmsMessageSendStrategy implements GlobalMessageSendStrategy { return true; // 短信发送支持异步 } -// @Override -// public boolean isEnabled() { -// return true; -// } + @Override + public boolean isEnabled() { + return true; + } @Override public void send(String title, String content, Integer type, List receiverIds, JSONObject config) { @@ -80,51 +83,10 @@ public class SmsMessageSendStrategy implements GlobalMessageSendStrategy { log.warn("用户{}没有手机号,跳过短信发送", user.getUsername()); continue; } - - // 构建短信内容 - String smsContent = buildSmsContent(title, content, type); - - // 执行发送 - - boolean success = true; - - if (success) { - log.info("短信发送成功:用户{},手机号:{}", user.getUsername(), mobile); - } else { - log.warn("短信发送失败:用户{},手机号:{}", user.getUsername(), mobile); - } + smsService.send(mobile, content); } catch (Exception e) { log.error("发送短信给用户{}时出错:{}", user.getUsername(), e.getMessage(), e); } } } - - /** - * 构建短信内容 - */ - private String buildSmsContent(String title, String content, Integer type) { - StringBuilder sb = new StringBuilder(); - - // 根据消息类型添加前缀 - if (type != null && type == 2) { - sb.append("【待办通知】"); - } else { - sb.append("【系统通知】"); - } - - // 添加标题和内容 - sb.append(title); - if (content != null && !content.trim().isEmpty()) { - sb.append(":").append(content); - } - - // 限制短信长度(一般短信限制70个字符) - String smsContent = sb.toString(); - if (smsContent.length() > 67) { - smsContent = smsContent.substring(0, 67) + "..."; - } - - return smsContent; - } - } diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/condolence/controller/CondolenceMineController.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/condolence/controller/CondolenceMineController.java index 99cebbd..2e9c069 100644 --- a/src/main/java/com/budwk/app/zhgh/staffbenefit/condolence/controller/CondolenceMineController.java +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/condolence/controller/CondolenceMineController.java @@ -3,25 +3,41 @@ package com.budwk.app.zhgh.staffbenefit.condolence.controller; import cn.dev33.satoken.annotation.SaCheckLogin; import cn.dev33.satoken.annotation.SaCheckPermission; import cn.dev33.satoken.annotation.SaMode; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.lang.Dict; import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; import com.budwk.app.base.annotation.SLog; import com.budwk.app.base.constant.RoleConstant; import com.budwk.app.base.page.Pagination; import com.budwk.app.base.param.PageForm; import com.budwk.app.base.result.Result; import com.budwk.app.base.sms.SmsService; +import com.budwk.app.base.utils.CommonDownloadUtil; +import com.budwk.app.base.utils.MoneyUtil; import com.budwk.app.base.utils.PageUtil; +import com.budwk.app.base.utils.SysOfficeTemplateUtil; import com.budwk.app.flow.engine.FlowEngine; +import com.budwk.app.flow.entity.ProcessTask; +import com.budwk.app.flow.vo.ProcessTaskVO; import com.budwk.app.sys.views.View_user; import com.budwk.app.web.commons.auth.utils.AuthUtil; import com.budwk.app.web.commons.auth.utils.SecurityUtil; +import com.budwk.app.zhgh.dayofficework.unionReimburse.model.UnionReimburse; import com.budwk.app.zhgh.staffbenefit.condolence.model.Condolence; import com.budwk.app.zhgh.staffbenefit.condolence.model.CondolenceType; import com.budwk.app.zhgh.staffbenefit.condolence.service.CondolenceService; +import com.deepoove.poi.XWPFTemplate; +import com.deepoove.poi.config.Configure; +import com.deepoove.poi.data.PictureRenderData; +import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.beetl.ext.fn.Print; import org.nutz.aop.interceptor.ioc.TransAop; import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; import org.nutz.dao.Sqls; import org.nutz.dao.sql.Sql; import org.nutz.dao.util.cri.SqlExpressionGroup; @@ -34,6 +50,21 @@ import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.Ok; import org.nutz.mvc.annotation.Param; +import javax.servlet.http.HttpServletResponse; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.net.URLEncoder; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + /** * @ClassName CondolenceApplyController * @Author JyuHsin @@ -45,12 +76,19 @@ import org.nutz.mvc.annotation.Param; @At("/platform/condolence/mine") @Api("职工慰问我的") @Ok("json:full") +@Slf4j public class CondolenceMineController { @Inject private CondolenceService condolenceService; @Inject + private Dao dao; + @Inject private FlowEngine flowEngine; + @Inject + private SmsService smsService; + @Inject + private SysOfficeTemplateUtil sysOfficeTemplateUtil; @At("/") @Ok("beetl:/platform/zhgh/staffbenefit/condolence/mine/index.html") @@ -140,6 +178,220 @@ public class CondolenceMineController { //smsService.send("20182040", "这是一条由智慧工会系统发出的测试消息。"); return Result.success(nutMap); } - @Inject - private SmsService smsService; + + + @At + @Ok("void") + public void doExport(String id, HttpServletResponse response) throws Exception { + Condolence condolence = condolenceService.fetch(id); + if (condolence == null) { + throw new RuntimeException("慰问记录不存在"); + } + + Sql sql = Sqls.create(""" + SELECT + info.*, + ins.id AS instanceId + FROM + `condolence` info + LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id + WHERE + ins.state = 20 AND info.id = @id + """).setParam("id", id); + sql.setCallback(Sqls.callback.map()); + dao.execute(sql); + NutMap info = (NutMap) sql.getResult(); + + HashMap docData = new HashMap<>(); + HashMap docData2 = new HashMap<>(); + + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + LocalDateTime createTime = LocalDateTime.parse(condolence.getCreateTime(), formatter); + + docData.put("createTime", DateUtil.format(createTime, "yyyy年MM月dd日")); + docData.put("applyUnionName", condolence.getApplyUnionName()); + docData.put("info", info); + + docData2.put("createTime", DateUtil.format(createTime, "yyyy年MM月dd日")); + docData2.put("applyUnionName", condolence.getApplyUnionName()); + docData2.put("bankUserName", condolence.getBankUserName()); + docData2.put("bankCardNumber", condolence.getBankCardNumber()); + docData2.put("bankOfDeposit", condolence.getBankOfDeposit()); + docData2.put("info", info); + + // 金额转大写 +// if (condolence.getMoney() != null) { +// docData.put("money_big", MoneyUtil.toRMBUpper(String.valueOf(condolence.getMoney()))); +// } else { +// docData.put("money_big", ""); +// } +// docData.put("money", condolence.getMoney()); + + String fileName; + String templateName; + String type = condolence.getType(); + + if (("6fb2ae129e674c0dbadc21d9abc22943").equals(type)) { + fileName = "工会会员结婚慰问报销审批单"+ "_" + + DateUtil.format(createTime, "yyyyMMdd") + ".docx"; + templateName = "condolence_marry"; + + docData.put("type", "会员结婚慰问"); + docData.put("way", "现金"); + docData.put("occurTime", condolence.getOccurTime()); + + docData2.put("type", "会员结婚慰问"); + docData2.put("money", "1000"); + docData2.put("money_big", "壹仟元整"); + } else if (("cf4ce7af322d464f8f86d818fcc00203").equals(type)){ + fileName = "工会会员生病住院慰问报销审批单"+ "_" + + DateUtil.format(createTime, "yyyyMMdd") + ".docx"; + templateName = "condolence_hospitalization"; + + docData.put("type", "会员生病慰问"); + docData.put("way", "现金"); + docData.put("hospitalizationTime", condolence.getHospitalizationTime()); + docData.put("leaveHospitalTime", condolence.getLeaveHospitalTime()); + docData.put("thisYearHospitalizationNum", condolence.getThisYearHospitalizationNum()); + + docData2.put("type", "会员生病慰问"); + docData2.put("money", "1000"); + docData2.put("money_big", "壹仟元整"); + } else if (("c90cb10dce6542e99ae271bee6fe8cc0").equals(type)){ + fileName = "工会会员生育慰问报销审批单"+ "_" + + DateUtil.format(createTime, "yyyyMMdd") + ".docx"; + templateName = "condolence_birth"; + + docData.put("type", "会员生育慰问"); + docData.put("way", "现金"); + docData.put("occurTime", condolence.getOccurTime()); + docData.put("hospitalizationTime", condolence.getHospitalizationTime()); + docData.put("leaveHospitalTime", condolence.getLeaveHospitalTime()); + + docData2.put("type", "会员生育慰问"); + docData2.put("money", "1000"); + docData2.put("money_big", "壹仟元整"); + }else if (("4e316737e71047e0b01aea78524c1416").equals(type)){ + fileName = "工会会员直系亲属去世报销审批单"+ "_" + + DateUtil.format(createTime, "yyyyMMdd") + ".docx"; + templateName = "condolence_relative_died"; + + docData.put("type", "会员直系亲属去世慰问"); + docData.put("way", "现金"); + docData.put("relation", condolence.getRelation()); + docData.put("occurTime", condolence.getOccurTime()); + + docData2.put("type", "会员直系亲属去世慰问"); + docData2.put("money", "1000"); + docData2.put("money_big", "壹仟元整"); + }else if (("b8ee30faacb2469593dfedb5b52565aa").equals(type)){ + fileName = "工会会员职工去世慰问报销审批单"+ "_" + + DateUtil.format(createTime, "yyyyMMdd") + ".docx"; + templateName = "condolence_died"; + + docData.put("type", "会员职工去世慰问"); + docData.put("way", "现金"); + docData.put("occurTime", condolence.getOccurTime()); + + docData2.put("type", "会员职工去世慰问"); + docData2.put("money", "3000"); + docData2.put("money_big", "叁仟元整"); + }else if (("1a2f7e8decb649a6ba8ca76e2af07779").equals(type)){ + fileName = "工会会员退休慰问报销审批单"+ "_" + + DateUtil.format(createTime, "yyyyMMdd") + ".docx"; + templateName = "condolence_retirement"; + + docData.put("type", "会员退休慰问"); + docData.put("way", "工会统一发放慰问信及慰问卷"); + docData.put("occurTime", condolence.getOccurTime()); + + docData2.put("type", "会员退休慰问"); + docData2.put("money", "1000"); + docData2.put("money_big", "壹仟元整"); + } else { + fileName = "工会会员慰问报销审批单"+ "_" + + DateUtil.format(createTime, "yyyyMMdd") + ".docx"; + templateName = "condolence_other"; + + docData.put("type", "会员其他慰问"); + docData.put("way", "现金"); + docData.put("occurTime", condolence.getOccurTime()); + } + + List doneTaskVos = new ArrayList<>(); + List doneTaskList = flowEngine.processTaskService().getDoneTaskList(info.getLong("instanceId"), null); + for (ProcessTask doneTask : doneTaskList) { + ProcessTaskVO taskVO = flowEngine.processTaskService().findById(doneTask.getId()); + doneTaskVos.add(taskVO); + } + + // 分工会审核 + doneTaskVos.stream().filter(task -> "分工会审核".equals(task.getDisplayName())) + .max(Comparator.comparing(ProcessTaskVO::getCreatedAt)) + .ifPresent(v -> { + Dict taskFormData = v.getTaskFormData(); + HashMap approval = new HashMap<>(); + + approval.put("date", DateUtil.format(v.getFinishTime(), "yyyy年MM月dd日")); + approval.put("user", taskFormData.getStr("tf_userName")); + if (StrUtil.isNotBlank(taskFormData.getStr("tf_sign"))) { + approval.put("sign", sysOfficeTemplateUtil.createPictureRenderData(taskFormData.getStr("tf_sign"))); + } + approval.put("opinion", taskFormData.getStr("tf_opinion")); + docData.put("fgh", approval); + docData2.put("fgh", approval); + }); + + // 校工会副主席审核 + doneTaskVos.stream().filter(task -> "校工会审核".equals(task.getDisplayName())) + .max(Comparator.comparing(ProcessTaskVO::getCreatedAt)) + .ifPresent(v -> { + Dict taskFormData = v.getTaskFormData(); + HashMap approval = new HashMap<>(); + + approval.put("date", DateUtil.format(v.getFinishTime(), "yyyy年MM月dd日")); + approval.put("user", taskFormData.getStr("tf_userName")); + if (StrUtil.isNotBlank(taskFormData.getStr("tf_sign"))) { + approval.put("sign", sysOfficeTemplateUtil.createPictureRenderData(taskFormData.getStr("tf_sign"))); + } + approval.put("opinion", taskFormData.getStr("tf_opinion")); + docData.put("xzx", approval); + docData2.put("xzx", approval); + }); + + response.setContentType("application/octet-stream"); + response.setHeader("content-disposition", "attachment;filename=" + + URLEncoder.encode("报销审批单.zip", "UTF-8")); + + try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) { + ZipEntry zipEntry = new ZipEntry(fileName); + zipOut.putNextEntry(zipEntry); + + try (ByteArrayOutputStream wordOut = new ByteArrayOutputStream()) { + XWPFTemplate.compile(sysOfficeTemplateUtil.getTemplate(templateName)) + .render(docData) + .writeAndClose(wordOut); + zipOut.write(wordOut.toByteArray()); + } + + zipOut.closeEntry(); + + String fileName2 = "武汉城市职业学院报销审批单" + ".docx"; + ZipEntry zipEntry2 = new ZipEntry(fileName2); + zipOut.putNextEntry(zipEntry2); + + try (ByteArrayOutputStream wordOut2 = new ByteArrayOutputStream()) { + XWPFTemplate.compile(sysOfficeTemplateUtil.getTemplate("reimbursement_approval")) + .render(docData2) + .writeAndClose(wordOut2); + zipOut.write(wordOut2.toByteArray()); + } + + zipOut.closeEntry(); + zipOut.finish(); + } catch (IOException e) { + log.error("导出 ZIP 文件失败,ID: {}, 错误信息: {}", id, e.getMessage()); + throw e; + } + } } diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/condolence/model/Condolence.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/condolence/model/Condolence.java index 8d6ce49..724ea8f 100644 --- a/src/main/java/com/budwk/app/zhgh/staffbenefit/condolence/model/Condolence.java +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/condolence/model/Condolence.java @@ -293,4 +293,9 @@ public class Condolence extends BaseModel { @ColDefine(type = ColType.INT) private Integer thisYearHospitalizationNum; + @Column + @Comment("与会员的关系") + @ColDefine(type = ColType.VARCHAR, width = 20) + private String relation; + } diff --git a/src/main/resources/views/platform/flow/define/preview.html b/src/main/resources/views/platform/flow/define/preview.html index 41d1734..029f105 100644 --- a/src/main/resources/views/platform/flow/define/preview.html +++ b/src/main/resources/views/platform/flow/define/preview.html @@ -141,18 +141,18 @@
记录{{index + 1}}
@@ -221,7 +221,7 @@
-