diff --git a/src/main/java/com/budwk/app/zhgh/activity/declarereimbursement/reimbursement/controller/ActivityReimbursementApplyController.java b/src/main/java/com/budwk/app/zhgh/activity/declarereimbursement/reimbursement/controller/ActivityReimbursementApplyController.java index 3c531789..ae70b0d5 100644 --- a/src/main/java/com/budwk/app/zhgh/activity/declarereimbursement/reimbursement/controller/ActivityReimbursementApplyController.java +++ b/src/main/java/com/budwk/app/zhgh/activity/declarereimbursement/reimbursement/controller/ActivityReimbursementApplyController.java @@ -87,6 +87,9 @@ public class ActivityReimbursementApplyController { .mapToDouble(v -> ObjectUtil.defaultIfNull(v.getActualPrice(), 0D)) .sum(); activityReimbursementInfo.setActualMoney(new BigDecimal(sum)); + if (StrUtil.isBlank(activityReimbursementInfo.getDeclareId())) { + activityReimbursementInfo.setDeclareId(activityReimbursementInfo.getId()); + } dao.insertOrUpdate(activityReimbursementInfo); return Result.success(); } @@ -107,6 +110,9 @@ public class ActivityReimbursementApplyController { .mapToDouble(v -> ObjectUtil.defaultIfNull(v.getActualPrice(), 0D)) .sum(); activityReimbursementInfo.setActualMoney(new BigDecimal(sum)); + if (StrUtil.isBlank(activityReimbursementInfo.getDeclareId())) { + activityReimbursementInfo.setDeclareId(activityReimbursementInfo.getId()); + } dao.insertOrUpdate(activityReimbursementInfo); // 开启流程实例 @@ -140,6 +146,9 @@ public class ActivityReimbursementApplyController { .mapToDouble(v -> ObjectUtil.defaultIfNull(v.getActualPrice(), 0D)) .sum(); activityReimbursementInfo.setActualMoney(new BigDecimal(sum)); + if (StrUtil.isBlank(activityReimbursementInfo.getDeclareId())) { + activityReimbursementInfo.setDeclareId(activityReimbursementInfo.getId()); + } dao.insertOrUpdate(activityReimbursementInfo); Dict dict = Dict.create(); diff --git a/src/main/java/com/budwk/app/zhgh/activity/declarereimbursement/reimbursement/controller/ActivityReimbursementMineController.java b/src/main/java/com/budwk/app/zhgh/activity/declarereimbursement/reimbursement/controller/ActivityReimbursementMineController.java index aec710a0..a20b75d4 100644 --- a/src/main/java/com/budwk/app/zhgh/activity/declarereimbursement/reimbursement/controller/ActivityReimbursementMineController.java +++ b/src/main/java/com/budwk/app/zhgh/activity/declarereimbursement/reimbursement/controller/ActivityReimbursementMineController.java @@ -1,19 +1,34 @@ package com.budwk.app.zhgh.activity.declarereimbursement.reimbursement.controller; import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.convert.NumberChineseFormatter; +import cn.hutool.core.convert.NumberWordFormatter; +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.result.Result; +import com.budwk.app.base.utils.CommonDownloadUtil; 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.web.commons.auth.utils.AuthUtil; import com.budwk.app.web.commons.auth.utils.SecurityUtil; +import com.budwk.app.web.commons.base.Globals; import com.budwk.app.zhgh.activity.declarereimbursement.reimbursement.models.ActivityReimbursementInfo; import com.budwk.app.zhgh.activity.declarereimbursement.reimbursement.service.ActivityReimbursementService; +import com.budwk.app.zhgh.activity.declarereimbursement.vo.ActivityBudgetVO; import com.budwk.app.zhgh.activity.declarereimbursement.vo.CommonPageParam; +import com.deepoove.poi.XWPFTemplate; +import com.deepoove.poi.config.Configure; +import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy; import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; import org.nutz.aop.interceptor.ioc.TransAop; import org.nutz.dao.Cnd; import org.nutz.dao.Dao; @@ -28,6 +43,11 @@ import org.nutz.mvc.annotation.Ok; import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.*; /** * @version 1.0 @@ -38,6 +58,7 @@ import javax.validation.Valid; */ @IocBean @Ok("json") +@Slf4j @ApiOperation("我的活动报销") @At("/platform/activityReimbursement/mine") public class ActivityReimbursementMineController { @@ -47,6 +68,8 @@ public class ActivityReimbursementMineController { @Inject private FlowEngine flowEngine; @Inject + private SysOfficeTemplateUtil sysOfficeTemplateUtil; + @Inject private ActivityReimbursementService activityReimbursementService; @At("") @@ -62,6 +85,7 @@ public class ActivityReimbursementMineController { Sql sql = Sqls.create(""" SELECT info.id, + info.declareId, info.userName, info.loginName, info.applyTime, @@ -136,4 +160,185 @@ public class ActivityReimbursementMineController { flowEngine.processInstanceService().deleteProcessInstanceByBusinessKey(id); return Result.success(); } + + + @At + @Ok("void") + @SaCheckPermission("activityReimbursement.mine") + @SLog(tag = "活动报销", msg = "导出报销凭证") + public void doExportReimbursement(@Valid String id, HttpServletResponse response) { + HashMap docData = new HashMap<>(); + + Sql sql = Sqls.create(""" + SELECT + info.*, + ins.id AS instanceId + FROM + `activity_reimbursement_info` 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(); + + String activityContent = info.getString("activityContent"); + info.put("activityContent", sysOfficeTemplateUtil.convertRichTextToDocText(activityContent)); + + double actualMoneyNum = info.getDouble("actualMoney"); + + // 添加预算金额转换逻辑 + String actualMoneyChinese = NumberChineseFormatter.format(info.getDouble("actualMoney"), false); + info.put("actualMoney", actualMoneyChinese); + + docData.put("schoolName", Globals.AppName); + docData.put("info", info); + // 使用BigDecimal确保精确处理 + BigDecimal bd = BigDecimal.valueOf(actualMoneyNum).setScale(2, RoundingMode.HALF_UP); + String moneyStr = bd.toPlainString(); + + // 分割整数和小数部分 + String[] parts = moneyStr.split("\\."); + String integerPart = parts[0]; + String decimalPart = parts.length > 1 ? parts[1] : "00"; + + // 确保小数部分是两位 + if (decimalPart.length() < 2) { + decimalPart = String.format("%-2s", decimalPart).replace(' ', '0'); + } else if (decimalPart.length() > 2) { + decimalPart = decimalPart.substring(0, 2); + } + + // 处理小数部分(角和分) + int jiao = 0, fen = 0; + if (decimalPart.length() >= 1) jiao = Character.getNumericValue(decimalPart.charAt(0)); + if (decimalPart.length() >= 2) fen = Character.getNumericValue(decimalPart.charAt(1)); + + // 处理整数部分(各位数值) + String reversed = new StringBuilder(integerPart).reverse().toString(); + String[] units = {"元", "十位", "百位", "千位", "万位", "十万位", "百万位"}; + Map digits = new HashMap<>(); + + for (int i = 0; i < reversed.length(); i++) { + if (i >= units.length) break; + digits.put(units[i], Character.getNumericValue(reversed.charAt(i))); + } + + // 按照one到nine的顺序设置字段(从百万位到分位) + Map digitFields = new HashMap<>(); + + // one: 百万位 + digitFields.put("one", digits.getOrDefault("百万位", 0)); + // two: 十万位 + digitFields.put("two", digits.getOrDefault("十万位", 0)); + // three: 万位 + digitFields.put("three", digits.getOrDefault("万位", 0)); + // four: 千位 + digitFields.put("four", digits.getOrDefault("千位", 0)); + // five: 百位 + digitFields.put("five", digits.getOrDefault("百位", 0)); + // six: 十位 + digitFields.put("six", digits.getOrDefault("十位", 0)); + // seven: 元位 + digitFields.put("seven", digits.getOrDefault("元", 0)); + // eight: 角 + digitFields.put("eight", jiao); + // nine: 分 + digitFields.put("nine", fen); + + // 将数字字段添加到info中 + info.putAll(digitFields); + + + 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); + }); + + // 协会负责人审核 + 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("xh", 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("xfzr", 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); + }); + + String budgetsStr2 = info.getString("budgets"); + List list = JSONUtil.parseArray(budgetsStr2).toList(ActivityReimbursementInfo.class); + + docData.put("budgets", list); + + LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy(); + Configure config = Configure.builder() + .bind("budgets", policy) + .build(); + + String fileName = Globals.AppName + "【" + info.getString("activityName") + "】报销凭证表.docx"; + + try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) { + XWPFTemplate.compile(sysOfficeTemplateUtil.getTemplate("activity_reimbursement_voucher"), config).render(docData).writeAndClose(byteArrayOutputStream); + CommonDownloadUtil.download(fileName, byteArrayOutputStream.toByteArray(), response); + } catch (IOException e) { + log.error("报销凭证表导出失败,id:{},错误信息:{}", id, e.getMessage()); + } + } } diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/article/controller/ArticleExamineController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/article/controller/ArticleExamineController.java index a64099e0..2d4a51bb 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/article/controller/ArticleExamineController.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/article/controller/ArticleExamineController.java @@ -102,7 +102,9 @@ public class ArticleExamineController { """); Cnd cnd = Cnd.NEW(); cnd.and("t.taskName", "=", "27f618b9-bff8-4382-87c9-d9abd9f5963c"); - cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId())); + if(!AuthUtil.hasRole(RoleConstant.SYSADMIN.name())){ + cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId())); + } if (approval) { cnd.and("t.taskState", "in", List.of(ProcessTaskStateEnum.FINISHED.getCode(), ProcessTaskStateEnum.INTERRUPT.getCode())); diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/article/controller/ArticleMineController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/article/controller/ArticleMineController.java index 0cd38833..72fa1134 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/article/controller/ArticleMineController.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/article/controller/ArticleMineController.java @@ -86,6 +86,10 @@ public class ArticleMineController { Cnd cnd = Cnd.NEW(); cnd.and("info.createdBy", "=", SecurityUtil.getUserId()); cnd.andEX("YEAR(info.submitTime)", "=", pageForm.getYear()); + // 添加标题模糊查询,仅当标题不为空时 + if (pageForm.getTitle() != null && !pageForm.getTitle().trim().isEmpty()) { + cnd.andEX("info.title", "LIKE", "%" + pageForm.getTitle().trim() + "%"); + } cnd.desc("info.submitTime"); sql.setCondition(cnd); Pagination pageVO = articleService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/article/controller/ArticleSchoolUnionApprovalController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/article/controller/ArticleSchoolUnionApprovalController.java index 6d84a7ff..270143fe 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/article/controller/ArticleSchoolUnionApprovalController.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/article/controller/ArticleSchoolUnionApprovalController.java @@ -2,12 +2,14 @@ package com.budwk.app.zhgh.dayofficework.article.controller; import cn.dev33.satoken.annotation.SaCheckPermission; import cn.hutool.core.util.StrUtil; +import com.budwk.app.base.constant.RoleConstant; import com.budwk.app.base.page.Pagination; import com.budwk.app.base.result.Result; import com.budwk.app.base.utils.PageUtil; import com.budwk.app.bpm.service.BpmService; import com.budwk.app.flow.engine.FlowEngine; import com.budwk.app.flow.enums.ProcessTaskStateEnum; +import com.budwk.app.web.commons.auth.utils.AuthUtil; import com.budwk.app.web.commons.auth.utils.SecurityUtil; import com.budwk.app.web.controllers.open.commons.service.CommonService; import com.budwk.app.zhgh.dayofficework.article.param.ArticleInfoPageParam; @@ -87,7 +89,9 @@ public class ArticleSchoolUnionApprovalController { """); Cnd cnd = Cnd.NEW(); cnd.and("t.taskName", "=", "749b6917-58ba-4564-8701-4bd2491fcb98"); - cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId())); + if(!AuthUtil.hasRole(RoleConstant.SYSADMIN.name())){ + cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId())); + } if (approval) { cnd.and("t.taskState", "in", List.of(ProcessTaskStateEnum.FINISHED.getCode(), ProcessTaskStateEnum.INTERRUPT.getCode())); diff --git a/src/main/resources/views/platform/zhgh/activity/declarereimbursement/declare/mine/index.html b/src/main/resources/views/platform/zhgh/activity/declarereimbursement/declare/mine/index.html index c63fbe49..42b75d4b 100644 --- a/src/main/resources/views/platform/zhgh/activity/declarereimbursement/declare/mine/index.html +++ b/src/main/resources/views/platform/zhgh/activity/declarereimbursement/declare/mine/index.html @@ -14,11 +14,11 @@ layout("/layouts/platform.html"){ value-format="yyyy"> - + - + - + - + - +