feat: 职工慰问 整改

This commit is contained in:
2026-10-09 20:19:41 +08:00
parent b325e8a8f5
commit 783e751560
8 changed files with 180 additions and 17 deletions
@@ -17,6 +17,7 @@ import org.nutz.dao.Cnd;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.cri.SqlExpressionGroup;
import org.nutz.dao.util.cri.Static;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.util.NutMap;
@@ -90,6 +91,14 @@ public class CondolenceFirstApprovalController {
$condition
""");
Cnd cnd = Cnd.NEW();
cnd.and(new Static("""
NOT EXISTS (
SELECT 1 FROM wf_process_task newer
WHERE newer.processInstanceId = t.processInstanceId
AND newer.taskName = t.taskName
AND newer.id > t.id
)
"""));
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
SqlExpressionGroup seg = new SqlExpressionGroup();
seg.or(Condolence::getHelpUserName, "like", "%" + pageForm.getSearchKeyword() + "%");
@@ -98,6 +98,14 @@ public class CondolenceFourthApprovalController {
$condition
""");
Cnd cnd = Cnd.NEW();
cnd.and(new Static("""
NOT EXISTS (
SELECT 1 FROM wf_process_task newer
WHERE newer.processInstanceId = t.processInstanceId
AND newer.taskName = t.taskName
AND newer.id > t.id
)
"""));
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
SqlExpressionGroup seg = new SqlExpressionGroup();
seg.or(Condolence::getHelpUserName, "like", "%" + pageForm.getSearchKeyword() + "%");
@@ -3,21 +3,33 @@ 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 com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.exception.BaseException;
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.PageUtil;
import com.budwk.app.base.utils.CommonDownloadUtil;
import com.budwk.app.base.utils.SysOfficeTemplateUtil;
import com.budwk.app.flow.engine.FlowEngine;
import com.budwk.app.flow.entity.ProcessInstance;
import com.budwk.app.flow.entity.ProcessTask;
import com.budwk.app.flow.enums.ProcessInstanceStateEnum;
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
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.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.data.PictureRenderData;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.nutz.aop.interceptor.ioc.TransAop;
@@ -34,6 +46,12 @@ 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.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.List;
/**
* @ClassName CondolenceApplyController
* @Author JyuHsin
@@ -51,6 +69,8 @@ public class CondolenceMineController {
private CondolenceService condolenceService;
@Inject
private FlowEngine flowEngine;
@Inject
private SysOfficeTemplateUtil sysOfficeTemplateUtil;
@At("/")
@Ok("beetl:/platform/zhgh/staffbenefit/condolence/mine/index.html")
@@ -132,6 +152,91 @@ public class CondolenceMineController {
return Result.success(pagination);
}
@At
@Ok("void")
@ApiOperation("导出职工慰问申请表")
@SaCheckPermission("condolence.mine")
public void doExportApply(String id, HttpServletResponse response, Boolean print) throws Exception {
Condolence condolence = condolenceService.fetch(id);
if (condolence == null) throw new BaseException("该条记录不存在");
if (!SecurityUtil.getUserId().equals(condolence.getCreatedBy())) {
throw new BaseException("只能导出本人提交的申请");
}
ProcessInstance instance = condolenceService.dao().fetch(ProcessInstance.class,
Cnd.where("businessNo", "=", id).desc("id"));
if (instance == null || !ProcessInstanceStateEnum.FINISHED.getCode().equals(instance.getState())) {
throw new BaseException("只能导出已完成的申请");
}
NutMap docData = Lang.obj2nutmap(condolence);
docData.put("payUserName", StrUtil.nullToEmpty(condolence.getBankUserName()));
CondolenceType type = condolenceService.dao().fetch(CondolenceType.class, condolence.getType());
docData.put("typeName", type == null ? "" : type.getName());
docData.put("signature", "");
if (StrUtil.isNotBlank(condolence.getSignature())) {
PictureRenderData signature = sysOfficeTemplateUtil.createPictureRenderData(90, 40, condolence.getSignature());
if (signature == null) throw new BaseException("申请人签字图片读取失败");
docData.put("signature", signature);
}
fillApplyApprovals(docData, instance);
String fileName = "重庆工贸职业技术学院职工慰问申请表_" + StrUtil.nullToEmpty(condolence.getHelpUserName());
try (InputStream input = getClass().getResourceAsStream("/templates/condolence/重庆工贸职业技术学院职工慰问申请表.doc");
ByteArrayOutputStream templateOutput = new ByteArrayOutputStream();
ByteArrayOutputStream output = new ByteArrayOutputStream()) {
if (input == null) throw new BaseException("职工慰问申请表模板不存在");
com.aspose.words.Document document = new com.aspose.words.Document(input);
document.save(templateOutput, com.aspose.words.SaveFormat.DOCX);
try (ByteArrayInputStream templateInput = new ByteArrayInputStream(templateOutput.toByteArray())) {
XWPFTemplate.compile(templateInput).render(docData).writeAndClose(output);
}
if (Boolean.TRUE.equals(print)) {
try (ByteArrayInputStream wordInput = new ByteArrayInputStream(output.toByteArray());
ByteArrayOutputStream pdfOutput = new ByteArrayOutputStream()) {
new com.aspose.words.Document(wordInput).save(pdfOutput, com.aspose.words.SaveFormat.PDF);
CommonDownloadUtil.download(fileName + ".pdf", pdfOutput.toByteArray(), response);
}
} else {
CommonDownloadUtil.download(fileName + ".docx", output.toByteArray(), response);
}
}
}
private void fillApplyApprovals(NutMap docData, ProcessInstance instance) {
String[] taskKeys = {"4dad0bef-3cf2-4a7d-bba3-35020b9b216d", "34f7938e-47a3-4b3a-b4e0-92b7a3f47865",
"ecdaef3b-edf4-4143-9a96-887dd5921711", "cbd41337-3c87-4959-9027-809df5c7ef5e"};
String[] fields = {"firstApproval", "secondApproval", "thirdApproval", "fourthApproval"};
List<String> suffixes = List.of("Opinion", "Sign", "Year", "Month", "Day");
for (String field : fields) {
for (String suffix : suffixes) docData.put(field + suffix, "");
}
List<ProcessTask> tasks = condolenceService.dao().query(ProcessTask.class,
Cnd.where("processInstanceId", "=", instance.getId()).asc("id"));
for (ProcessTask task : tasks) {
ProcessTaskVO taskVO = flowEngine.processTaskService().findById(task.getId());
if ("startTask".equals(task.getTaskName()) || (taskVO.getExt() != null && Boolean.TRUE.equals(taskVO.getExt().getBool("isFirstTaskNode")))) {
// 重新申请后,仅导出本轮审批记录。
for (String field : fields) {
for (String suffix : suffixes) docData.put(field + suffix, "");
}
continue;
}
for (int i = 0; i < taskKeys.length; i++) {
if (!taskKeys[i].equals(task.getTaskName())) continue;
for (String suffix : suffixes) docData.put(fields[i] + suffix, "");
if (!ProcessTaskStateEnum.FINISHED.getCode().equals(task.getTaskState())) continue;
Dict data = taskVO.getExt() == null ? Dict.create() : taskVO.getTaskFormData();
docData.put(fields[i] + "Opinion", StrUtil.nullToEmpty(data.getStr("opinion")));
if (StrUtil.isNotBlank(data.getStr("sign"))) {
PictureRenderData signature = sysOfficeTemplateUtil.createPictureRenderData(90, 40, data.getStr("sign"));
if (signature == null) throw new BaseException("审批签字图片读取失败");
docData.put(fields[i] + "Sign", signature);
}
docData.put(fields[i] + "Year", task.getFinishTime() == null ? "" : DateUtil.format(task.getFinishTime(), "yyyy"));
docData.put(fields[i] + "Month", task.getFinishTime() == null ? "" : DateUtil.format(task.getFinishTime(), "M"));
docData.put(fields[i] + "Day", task.getFinishTime() == null ? "" : DateUtil.format(task.getFinishTime(), "d"));
}
}
}
@At
@ApiOperation("删除")
@Aop(TransAop.READ_COMMITTED)
@@ -17,6 +17,7 @@ import org.nutz.dao.Cnd;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.cri.SqlExpressionGroup;
import org.nutz.dao.util.cri.Static;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.util.NutMap;
@@ -90,6 +91,14 @@ public class CondolenceSecondApprovalController {
$condition
""");
Cnd cnd = Cnd.NEW();
cnd.and(new Static("""
NOT EXISTS (
SELECT 1 FROM wf_process_task newer
WHERE newer.processInstanceId = t.processInstanceId
AND newer.taskName = t.taskName
AND newer.id > t.id
)
"""));
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
SqlExpressionGroup seg = new SqlExpressionGroup();
seg.or(Condolence::getHelpUserName, "like", "%" + pageForm.getSearchKeyword() + "%");
@@ -17,6 +17,7 @@ import org.nutz.dao.Cnd;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.cri.SqlExpressionGroup;
import org.nutz.dao.util.cri.Static;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.util.NutMap;
@@ -92,6 +93,14 @@ public class CondolenceThirdApprovalController {
$condition
""");
Cnd cnd = Cnd.NEW();
cnd.and(new Static("""
NOT EXISTS (
SELECT 1 FROM wf_process_task newer
WHERE newer.processInstanceId = t.processInstanceId
AND newer.taskName = t.taskName
AND newer.id > t.id
)
"""));
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
SqlExpressionGroup seg = new SqlExpressionGroup();
seg.or(Condolence::getHelpUserName, "like", "%" + pageForm.getSearchKeyword() + "%");
@@ -22,14 +22,14 @@ SET name = '校工会办公室主任审批', initialPinyinName = 'x', note = '
permission = 'h5.condolence.secondApproval'
WHERE id = '87a2dcfac0da4ec4870b65693807a4d1';
-- 三级:分工会主席审批,节点 ecdaef3b-edf4-4143-9a96-887dd5921711。
-- 三级:校工会主席审批,节点 ecdaef3b-edf4-4143-9a96-887dd5921711。
UPDATE zhgh_cqgmy.sys_menu
SET name = '分工会主席审批', initialPinyinName = 'f', note = '分工会主席审批',
SET name = '校工会主席审批', initialPinyinName = 'x', note = '校工会主席审批',
permission = 'condolence.thirdApproval'
WHERE id = '0917928006574b2a99f7ef3e8804d873';
UPDATE zhgh_cqgmy.sys_menu
SET name = '分工会主席审批', initialPinyinName = 'f', note = '分工会主席审批',
SET name = '校工会主席审批', initialPinyinName = 'x', note = '校工会主席审批',
permission = 'h5.condolence.thirdApproval'
WHERE id = 'c269f94a5c8a4a4a8c8de0bb8f8f9f9a';
@@ -85,18 +85,18 @@ VALUES ('7f4a820d5a394bb8a0a92d6699afe7c8', '87a2dcfac0da4ec4870b65693807a4d1');
INSERT INTO zhgh_cqgmy.sys_role_menu (roleId, menuId)
VALUES ('494ac71eb8b44d0e99e19b7fde6bd469', '87a2dcfac0da4ec4870b65693807a4d1');
-- 三级:分工会主席审批,节点 ecdaef3b-edf4-4143-9a96-887dd5921711。
-- 三级:校工会主席审批,节点 ecdaef3b-edf4-4143-9a96-887dd5921711。
DELETE FROM zhgh_cqgmy.sys_role_menu WHERE menuId = '0917928006574b2a99f7ef3e8804d873';
INSERT INTO zhgh_cqgmy.sys_role_menu (roleId, menuId)
VALUES ('7f4a820d5a394bb8a0a92d6699afe7c8', '0917928006574b2a99f7ef3e8804d873');
INSERT INTO zhgh_cqgmy.sys_role_menu (roleId, menuId)
SELECT id, '0917928006574b2a99f7ef3e8804d873' FROM zhgh_cqgmy.sys_role WHERE code = 'BRANCH_UNION_CHAIRMAN' AND disabled = false AND delFlag = false;
VALUES ('6aece46b946e4fb9ac4cb15c0cd8c3e6', '0917928006574b2a99f7ef3e8804d873');
DELETE FROM zhgh_cqgmy.sys_role_menu WHERE menuId = 'c269f94a5c8a4a4a8c8de0bb8f8f9f9a';
INSERT INTO zhgh_cqgmy.sys_role_menu (roleId, menuId)
VALUES ('7f4a820d5a394bb8a0a92d6699afe7c8', 'c269f94a5c8a4a4a8c8de0bb8f8f9f9a');
INSERT INTO zhgh_cqgmy.sys_role_menu (roleId, menuId)
SELECT id, 'c269f94a5c8a4a4a8c8de0bb8f8f9f9a' FROM zhgh_cqgmy.sys_role WHERE code = 'BRANCH_UNION_CHAIRMAN' AND disabled = false AND delFlag = false;
VALUES ('6aece46b946e4fb9ac4cb15c0cd8c3e6', 'c269f94a5c8a4a4a8c8de0bb8f8f9f9a');
DELETE FROM zhgh_cqgmy.sys_role_menu WHERE menuId = '3561e97f44d14b47ae07f63ff8312a90';
INSERT INTO zhgh_cqgmy.sys_role_menu (roleId, menuId)
@@ -116,6 +116,8 @@ VALUES ('7f4a820d5a394bb8a0a92d6699afe7c8', '3b49290f7db44130b9f6394a8212321f');
INSERT IGNORE INTO zhgh_cqgmy.sys_role_menu (roleId, menuId)
VALUES ('494ac71eb8b44d0e99e19b7fde6bd469', '3b49290f7db44130b9f6394a8212321f');
INSERT IGNORE INTO zhgh_cqgmy.sys_role_menu (roleId, menuId)
VALUES ('6aece46b946e4fb9ac4cb15c0cd8c3e6', '3b49290f7db44130b9f6394a8212321f');
INSERT IGNORE INTO zhgh_cqgmy.sys_role_menu (roleId, menuId)
VALUES ('b3854469e6f44901b22bb791cb538431', '3b49290f7db44130b9f6394a8212321f');
INSERT IGNORE INTO zhgh_cqgmy.sys_role_menu (roleId, menuId)
SELECT id, '3b49290f7db44130b9f6394a8212321f' FROM zhgh_cqgmy.sys_role WHERE code = 'BRANCH_UNION_CHAIRMAN' AND disabled = false AND delFlag = false;
@@ -125,6 +127,8 @@ VALUES ('7f4a820d5a394bb8a0a92d6699afe7c8', '024811fd168e44948e6ab84911fc26bb');
INSERT IGNORE INTO zhgh_cqgmy.sys_role_menu (roleId, menuId)
VALUES ('494ac71eb8b44d0e99e19b7fde6bd469', '024811fd168e44948e6ab84911fc26bb');
INSERT IGNORE INTO zhgh_cqgmy.sys_role_menu (roleId, menuId)
VALUES ('6aece46b946e4fb9ac4cb15c0cd8c3e6', '024811fd168e44948e6ab84911fc26bb');
INSERT IGNORE INTO zhgh_cqgmy.sys_role_menu (roleId, menuId)
VALUES ('b3854469e6f44901b22bb791cb538431', '024811fd168e44948e6ab84911fc26bb');
INSERT IGNORE INTO zhgh_cqgmy.sys_role_menu (roleId, menuId)
SELECT id, '024811fd168e44948e6ab84911fc26bb' FROM zhgh_cqgmy.sys_role WHERE code = 'BRANCH_UNION_CHAIRMAN' AND disabled = false AND delFlag = false;
@@ -1,6 +1,6 @@
<template>
<div class="signature-wrap">
<canvas id="canvas"></canvas>
<canvas ref="canvas" @touchstart.stop @touchmove.stop></canvas>
<div :class="isLikelyMobile() ? 'action-buttons' : 'action-buttons pc-action-buttons'">
<button @click="clear" class="action-button-danger" type="button">清空</button>
<button @click="undo" class="action-button-warning" type="button">撤销</button>
@@ -30,23 +30,23 @@
// window.addEventListener("orientationchange", a)
// a()
let signature = null
module.exports = {
name: "sysSignature",
data() {
return {
content: null
content: null,
signature: null
}
},
methods: {
clear() {
signature.clear()
this.signature.clear()
},
undo() {
signature.undo()
this.signature.undo()
},
rotate() {
signature.getRotateCanvas(90)
this.signature.getRotateCanvas(90)
},
isLikelyMobile() {
const isTouchDevice = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
@@ -56,7 +56,7 @@ module.exports = {
return hasMobileUA || (isTouchDevice && isSmallScreen);
},
save() {
if (signature.isEmpty()) {
if (this.signature.isEmpty()) {
// H5 页面使用统一的 Vant 提示;未加载 Vant 的独立签字页保留原生提示作为兼容兜底。
if (typeof this.$toast === "function") {
this.$toast({
@@ -71,11 +71,11 @@ module.exports = {
}
// const png = signature.getPNG()
//旋转一下 横过来
const rotateCanvas = signature.getRotateCanvas(-90)
const rotateCanvas = this.signature.getRotateCanvas(-90)
if (this.isLikelyMobile()) {
this.$emit("save", rotateCanvas.toDataURL())
} else {
this.$emit("save", signature.toDataURL())
this.$emit("save", this.signature.toDataURL())
}
}
},
@@ -83,10 +83,10 @@ module.exports = {
const innerWidth = window.innerWidth
const innerHeight = window.innerHeight
const canvas = document.getElementById("canvas")
const canvas = this.$refs.canvas
canvas.width = window.innerWidth
canvas.height = window.innerHeight
signature = new SmoothSignature(canvas, {
this.signature = new SmoothSignature(canvas, {
width: innerWidth - 30,
height: innerHeight - 30,
scale: 2,
@@ -95,6 +95,15 @@ module.exports = {
color: "#000000"
// bgColor: "#f6f6f6"
})
canvas.addEventListener("touchstart", this.signature.onDrawStart, { passive: false })
canvas.addEventListener("touchmove", this.signature.onDrawMove, { passive: false })
document.addEventListener("touchend", this.signature.onDrawEnd, { passive: false })
document.addEventListener("touchcancel", this.signature.onDrawEnd, { passive: false })
},
beforeDestroy() {
if (this.signature) {
this.signature.removeListener()
}
}
}
</script>
@@ -62,6 +62,13 @@ layout("/layouts/platform.html"){
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
<el-button v-if="row.taskKey === 'startTask' || !row.instanceId" @click="onEdit(row)" size="mini" type="primary">编辑</el-button>
<el-button v-if="row.canRevoke" size="mini" type="danger" @click="onRevoke(row)">撤回</el-button>
<el-dropdown v-if="row.createdBy === $store.state.user.id && row.instanceState == 20" trigger="click" @command="format => doExportApply(row, format)">
<el-button size="mini" type="primary">导出</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="pdf">导出 PDF</el-dropdown-item>
<el-dropdown-item command="word">导出 Word</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<el-button v-if="row.taskKey === 'startTask' || !row.instanceId" @click="onDelete(row.id)" size="mini" type="danger">
删除
</el-button>
@@ -102,6 +109,9 @@ layout("/layouts/platform.html"){
}
},
methods: {
doExportApply(row, format) {
this.$downLoad('/platform/condolence/mine/doExportApply?id=' + row.id + '&print=' + (format === 'pdf'))
},
onAdd() {
commonUtil.pjaxPush('/platform/condolence/apply')
},