From 30a17cb88460a98d5c16807e44b4da821c69e5c9 Mon Sep 17 00:00:00 2001 From: JyuHsin <729757837@qq.com> Date: Tue, 10 Mar 2026 10:20:42 +0800 Subject: [PATCH] commit --- src/main/java/io/v/nutz/base/utils/Roles.java | 11 + .../java/io/v/nutz/oa/HhuEduOaService.java | 397 +++++++++++++++ .../java/io/v/nutz/oa/OaTestController.java | 25 + .../io/v/nutz/oa/client/HhuEduOaClient.java | 271 ++++++++++ .../v/nutz/oa/constants/CommonConstants.java | 16 + .../controller/OaAuditInstanceController.java | 53 ++ .../io/v/nutz/oa/dto/OaAuditInstanceDto.java | 13 + .../v/nutz/oa/enums/HhuEduOaStatusEnum.java | 43 ++ .../v/nutz/oa/enums/OaBusinessTypeEnum.java | 53 ++ .../java/io/v/nutz/oa/enums/OaStatusEnum.java | 42 ++ .../io/v/nutz/oa/model/OaAuditInstance.java | 104 ++++ .../io/v/nutz/oa/model/OaInstanceUser.java | 63 +++ .../io/v/nutz/oa/notify/OaAuditNotify.java | 38 ++ .../java/io/v/nutz/oa/pojo/RequestResult.java | 27 + .../oa/service/IOaAuditInstanceService.java | 106 ++++ .../oa/service/IOaInstanceUserService.java | 27 + .../impl/OaAuditInstanceServiceImpl.java | 315 ++++++++++++ .../impl/OaInstanceUserServiceImpl.java | 126 +++++ .../java/io/v/nutz/oa/util/BillNoUtil.java | 20 + .../java/io/v/nutz/oa/util/MyHttpDelete.java | 24 + .../java/io/v/nutz/oa/util/StringUtil.java | 10 + .../java/io/v/nutz/oa/util/SudySignUtil.java | 222 +++++++++ src/main/java/io/v/nutz/oa/util/Util.java | 91 ++++ src/main/java/io/v/nutz/oa/vo/CreaterVO.java | 34 ++ .../java/io/v/nutz/oa/vo/FinishTaskVO.java | 22 + .../java/io/v/nutz/oa/vo/ParticipantVO.java | 108 ++++ .../java/io/v/nutz/oa/vo/TaskAndDoneAO.java | 31 ++ src/main/java/io/v/nutz/oa/vo/TaskVO.java | 469 ++++++++++++++++++ src/main/java/io/v/nutz/oa/vo/UserDoneAO.java | 86 ++++ .../proposal/constants/ProposalAuditEnum.java | 40 ++ .../transact/CaseCheckController.java | 151 +++++- .../controller/transact/CaseController.java | 90 +++- .../transact/CaseUnitController.java | 103 ++++ .../transact/ComposeController.java | 26 + .../ExecutorReadConfirmController.java | 88 +++- .../transact/ExecutorReadController.java | 91 +++- .../transact/FeedbackScoreController.java | 57 +++ .../transact/LeaderAuditController.java | 132 ++++- .../transact/ProposalAuditController.java | 21 + .../controller/transact/ReplyController.java | 162 +++++- .../transact/SecondedController.java | 60 ++- .../transact/principalReadController.java | 113 ++++- .../services/ProposalCaseService.java | 3 + .../impl/ProposalCaseServiceImpl.java | 43 ++ .../impl/ProposalSecondedServiceImpl.java | 26 + .../constant/ColumnFormTypeEnum.java | 1 + .../ext/beetl/BeetlCustomResourceLoader.java | 78 +++ .../web/commons/proc/NutShiroProcessor.java | 91 ++-- .../commons/proc/XssSqlFilterProcessor.java | 296 ++++++----- .../platform/AgendaController.java | 2 +- .../platform/sys/SysWechatController.java | 2 + .../mobile/common/TrainDynamicForm.vue | 3 + src/main/resources/views/mobile/newHome.html | 4 +- .../views/mobile/train/trainInfo.html | 20 +- .../platform/proposal/transact/case.html | 43 ++ .../platform/proposal/transact/caseCheck.html | 16 + .../proposal/transact/delegation.html | 14 + .../proposal/transact/executorRead.html | 47 +- .../transact/executorReadConfirm.html | 43 +- .../platform/proposal/transact/feedback.html | 15 + .../proposal/transact/leaderAudit.html | 15 + .../proposal/transact/principalRead.html | 41 +- .../platform/proposal/transact/reply.html | 18 + .../platform/proposal/transact/seconded.html | 22 + .../platform/proposal/transact/write.html | 37 +- .../resources/views/platform/sys/home/todo.js | 179 +++++-- .../views/platform/zgfw/lxy/HdMange.html | 2 +- 67 files changed, 4765 insertions(+), 277 deletions(-) create mode 100644 src/main/java/io/v/nutz/oa/HhuEduOaService.java create mode 100644 src/main/java/io/v/nutz/oa/OaTestController.java create mode 100644 src/main/java/io/v/nutz/oa/client/HhuEduOaClient.java create mode 100644 src/main/java/io/v/nutz/oa/constants/CommonConstants.java create mode 100644 src/main/java/io/v/nutz/oa/controller/OaAuditInstanceController.java create mode 100644 src/main/java/io/v/nutz/oa/dto/OaAuditInstanceDto.java create mode 100644 src/main/java/io/v/nutz/oa/enums/HhuEduOaStatusEnum.java create mode 100644 src/main/java/io/v/nutz/oa/enums/OaBusinessTypeEnum.java create mode 100644 src/main/java/io/v/nutz/oa/enums/OaStatusEnum.java create mode 100644 src/main/java/io/v/nutz/oa/model/OaAuditInstance.java create mode 100644 src/main/java/io/v/nutz/oa/model/OaInstanceUser.java create mode 100644 src/main/java/io/v/nutz/oa/notify/OaAuditNotify.java create mode 100644 src/main/java/io/v/nutz/oa/pojo/RequestResult.java create mode 100644 src/main/java/io/v/nutz/oa/service/IOaAuditInstanceService.java create mode 100644 src/main/java/io/v/nutz/oa/service/IOaInstanceUserService.java create mode 100644 src/main/java/io/v/nutz/oa/service/impl/OaAuditInstanceServiceImpl.java create mode 100644 src/main/java/io/v/nutz/oa/service/impl/OaInstanceUserServiceImpl.java create mode 100644 src/main/java/io/v/nutz/oa/util/BillNoUtil.java create mode 100644 src/main/java/io/v/nutz/oa/util/MyHttpDelete.java create mode 100644 src/main/java/io/v/nutz/oa/util/StringUtil.java create mode 100644 src/main/java/io/v/nutz/oa/util/SudySignUtil.java create mode 100644 src/main/java/io/v/nutz/oa/util/Util.java create mode 100644 src/main/java/io/v/nutz/oa/vo/CreaterVO.java create mode 100644 src/main/java/io/v/nutz/oa/vo/FinishTaskVO.java create mode 100644 src/main/java/io/v/nutz/oa/vo/ParticipantVO.java create mode 100644 src/main/java/io/v/nutz/oa/vo/TaskAndDoneAO.java create mode 100644 src/main/java/io/v/nutz/oa/vo/TaskVO.java create mode 100644 src/main/java/io/v/nutz/oa/vo/UserDoneAO.java create mode 100644 src/main/java/io/v/nutz/web/commons/ext/beetl/BeetlCustomResourceLoader.java diff --git a/src/main/java/io/v/nutz/base/utils/Roles.java b/src/main/java/io/v/nutz/base/utils/Roles.java index 2b104e4..d71d3a8 100644 --- a/src/main/java/io/v/nutz/base/utils/Roles.java +++ b/src/main/java/io/v/nutz/base/utils/Roles.java @@ -230,8 +230,19 @@ public interface Roles { */ String GH03 = "428969eb99ff4b76883d83f847ee96a5"; + // 党委书记 + String secretary = "dc6703af06fa456a9d95c1104e8d7c77"; + + // 校长 + String principal = "0d8665494fb64a38b4f18fc810ff1751"; + /** * 工会组组长 */ String ghxzzz = "308dfe9096f44a64a67b4714f67dcd96"; + + /** + * 校提案管理员 + */ + String tmanage = "91623fdad36e45ffbf3e5eab42fb5599"; } diff --git a/src/main/java/io/v/nutz/oa/HhuEduOaService.java b/src/main/java/io/v/nutz/oa/HhuEduOaService.java new file mode 100644 index 0000000..78c1b3c --- /dev/null +++ b/src/main/java/io/v/nutz/oa/HhuEduOaService.java @@ -0,0 +1,397 @@ +package io.v.nutz.oa; + +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSONObject; +import io.v.nutz.oa.client.HhuEduOaClient; +import io.v.nutz.oa.enums.HhuEduOaStatusEnum; +import io.v.nutz.oa.pojo.RequestResult; +import io.v.nutz.oa.util.SudySignUtil; +import io.v.nutz.oa.vo.*; +import lombok.extern.slf4j.Slf4j; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * 河海大学OA服务类 + */ +@Slf4j +public class HhuEduOaService { + + // 签名算法方式 + private static final String algorithm = "SHA1"; + // 应用APP标识 + private static final String appCode = "zhgh"; + // 平台分给业务系统的秘钥 + private static final String secretKey = "a9985b08-2e1e-4e37-ab19-518b45670133"; + // 请求域名地址 + public static String domain = "https://mynew-admin.hhu.edu.cn/taskcenter"; + // 任务分类代码 + public static String taskCategoryCode = "zhgh"; + + // 实例化 + public static HhuEduOaService getInstance() { + return new HhuEduOaService(); + } + + /** + * 创建代办任务 + * @param taskBizId 任务的业务id。此id有app给出,app需要自己保证其唯一性。用于app对任务进行操作 + * @param loginName 任务创建者的代码,由校方数据中心给出,通常为职工号 + * @param title 任务标题 + * @param url 任务的处理url + * @param doneUrl 任务的已办url + *@param processNodeId 流程环节 存进度百分比(0-100) + * @param processNodeName 流程环节名称 + * @param participantUserCodes 参与者的代码,由校方数据中心给出,通常为职工号 + * @return RequestResult + */ + public RequestResult createTask(String taskBizId, String loginName, String title, String url, String doneUrl, String processNodeId, String processNodeName, List participantUserCodes) { + return this.createTask(taskBizId, loginName, title, null, url, doneUrl, processNodeId, processNodeName, null, null, null, participantUserCodes, null); + } + + /** + * 创建代办任务 + * @param taskBizId 任务的业务id。此id有app给出,app需要自己保证其唯一性。用于app对任务进行操作 + * @param loginName 任务创建者的代码,由校方数据中心给出,通常为职工号 + * @param title 任务标题 + * @param subTitle 子标题 + * @param url 任务的处理url + * @param doneUrl 任务的已办url + * @param processNodeId 流程环节 存进度百分比(0-100) + * @param processNodeName 流程环节名称 + * @param participantUserCodes 参与者的代码,由校方数据中心给出,通常为职工号 + * @return RequestResult + */ + public RequestResult createTask(String taskBizId, String loginName, String title, String subTitle, String url, String doneUrl, String processNodeId, String processNodeName, List participantUserCodes) { + return this.createTask(taskBizId, loginName, title, subTitle, url, doneUrl, processNodeId, processNodeName, null, null, null, participantUserCodes, null); + } + + + /** + * 创建代办任务 + * @param taskBizId 任务的业务id。此id有app给出,app需要自己保证其唯一性。用于app对任务进行操作 + * @param loginName 任务创建者的代码,由校方数据中心给出,通常为职工号 + * @param title 任务标题 + * @param url 任务的处理url + * @param doneUrl 任务的已办url + * @param processNodeId 流程环节 存进度百分比(0-100) + * @param processNodeName 流程环节名称 + * @param applyName 申请人 + * @param applyLoginName 申请人工号 + * @param applyOrgName 申请人所在部门 + * @param participantUserCodes 参与者的代码,由校方数据中心给出,通常为职工号 + * @return RequestResult + */ + public RequestResult createTask(String taskBizId, String loginName, String title, String url, String doneUrl, String processNodeId, String processNodeName, String applyName, String applyLoginName, String applyOrgName, List participantUserCodes) { + return this.createTask(taskBizId, loginName, title, null, url, doneUrl, processNodeId, processNodeName, applyName, applyLoginName, applyOrgName, participantUserCodes, null); + } + + /** + * 创建代办任务 + * @param taskBizId 任务的业务id。此id有app给出,app需要自己保证其唯一性。用于app对任务进行操作 + * @param loginName 任务创建者的代码,由校方数据中心给出,通常为职工号 + * @param title 任务标题 + * @param subTitle 任务副标题 + * @param url 任务的处理url + * @param doneUrl 任务的已办url + * @param processNodeId 流程环节 存进度百分比(0-100) + * @param processNodeName 流程环节名称 + * @param applyName 申请人 + * @param applyLoginName 申请人工号 + * @param applyOrgName 申请人所在部门 + * @param participantUserCodes 参与者的代码,由校方数据中心给出,通常为职工号 + * @param parentTask 父级任务信息 + * @return RequestResult + */ + public RequestResult createTask(String taskBizId, String loginName, String title, String subTitle, String url, String doneUrl, String processNodeId, String processNodeName, String applyName, String applyLoginName, String applyOrgName, + List participantUserCodes, TaskVO parentTask) { + if(StrUtil.isBlank(taskBizId)) { + throw new RuntimeException("缺少任务的业务id->taskBizId"); + } + if(StrUtil.isBlank(loginName)) { + throw new RuntimeException("缺少任务创建者的代码->loginName"); + } + if(StrUtil.isBlank(title)) { + throw new RuntimeException("缺少任务标题->title"); + } + if(StrUtil.isBlank(url)) { + throw new RuntimeException("缺少任务的处理URL->url"); + } + if(StrUtil.isBlank(doneUrl)) { + throw new RuntimeException("缺少任务的已办URL->doneUrl"); + } +// if(StrUtil.isBlank(processNodeName)) { +// throw new RuntimeException("缺少任务的流程环节名称->processNodeName"); +// } + if(!ArrayUtil.isAllNotEmpty(participantUserCodes)) { + throw new RuntimeException("缺少任务的参与者代码->participantUserCodes"); + } +// if(participantUserCodes.contains(loginName)) { +// throw new RuntimeException("发起人不能是参与审批人"); +// } + String timestamp=System.currentTimeMillis()+""; + String nonce = IdUtil.randomUUID().toString().replaceAll("-", ""); + + // 创建任务参数 + TaskVO taskVO = getCreateTaskVo(taskBizId, loginName, title, subTitle, url, doneUrl, processNodeName, applyName, applyLoginName, applyOrgName, participantUserCodes, parentTask); +// taskVO.setCreateName("印天宇"); +// CreaterVO creater = new CreaterVO(); +// creater.setName(taskVO.getCreateName()); +// creater.setLoginName(taskVO.getCreatorId()); +// taskVO.setCreater(creater); + taskVO.setProcessNodeId(processNodeId); + String createTaskUrl = domain+"/_web/_apps/taskcenter/api/v3/taskcenter/app/"+appCode+"/task/category/"+taskCategoryCode+".rst"; + String resutl = HhuEduOaClient.client(appCode, algorithm).doPost(createTaskUrl, JSONObject.toJSONString(taskVO), getSign(timestamp, nonce), nonce, timestamp, null); + log.info("创建待办任务result->{}",resutl); + RequestResult requestResult = JSONObject.parseObject(resutl,RequestResult.class); + return requestResult; + } + + /** + * 创建任务并完成 + * @param taskBizId 任务的业务id。此id有app给出,app需要自己保证其唯一性。用于app对任务进行操作 + * @param loginName 任务创建者的代码,由校方数据中心给出,通常为职工号 + * @param title 任务标题 + * @param subTitle 任务副标题 + * @param url 任务的处理url + * @param participantUserCodes 参与者的代码,由校方数据中心给出,通常为职工号 + * @return RequestResult + */ + public RequestResult createTaskAndUserDone(String taskBizId, String loginName, String title, String subTitle, String url, List participantUserCodes) { + if(StrUtil.isBlank(taskBizId)) { + throw new RuntimeException("缺少任务的业务id->taskBizId"); + } + if(StrUtil.isBlank(loginName)) { + throw new RuntimeException("缺少任务创建者的代码->loginName"); + } + if(StrUtil.isBlank(loginName)) { + throw new RuntimeException("缺少任务创建者的代码->loginName"); + } + if(StrUtil.isBlank(title)) { + throw new RuntimeException("缺少任务标题->title"); + } + if(StrUtil.isBlank(url)) { + throw new RuntimeException("缺少任务的处理URL->url"); + } + if(!ArrayUtil.isAllNotEmpty(participantUserCodes)) { + throw new RuntimeException("缺少任务的参与者代码->participantUserCodes"); + } + String timestamp=System.currentTimeMillis()+""; + String nonce = IdUtil.randomUUID().toString().replaceAll("-", ""); + TaskAndDoneAO taskAndDoneAO = getCreateTaskAndDoneAO(taskBizId, loginName, title, subTitle, url, participantUserCodes); + String taskAndDoneUrl = domain + "/_web/_apps/taskcenter/api/v3/taskcenter/app/"+ appCode+"/task/category/"+ taskCategoryCode+"/done.rst?userId="+loginName; + String resutl = HhuEduOaClient.client(appCode, algorithm).doPost(taskAndDoneUrl, JSONObject.toJSONString(taskAndDoneAO), getSign(timestamp, nonce), nonce, timestamp, null); + log.info("创建代办任务并完成任务result->{}",resutl); + RequestResult requestResult = JSONObject.parseObject(resutl,RequestResult.class); + return requestResult; + } + + /** + * 更新代办任务属性 + * @param taskBizId 其值是业务系统先前调用createTask时的给出的Task.taskBizId + * @param doneUrl 任务的已办url + * @param task 更新的任务信息 + * @return RequestResult + */ + public RequestResult updateTask(String taskBizId, String doneUrl, TaskVO task) { + if(task == null) { + task = new TaskVO(); + } + task.setTaskBizId(taskBizId); + task.setDoneUrl(doneUrl); + String timestamp=System.currentTimeMillis()+""; + String nonce = IdUtil.randomUUID().toString().replaceAll("-", ""); + String updateTaskUrl = domain + "/_web/_apps/taskcenter/api/v3/taskcenter/app/"+appCode+"/task/"+task.getTaskBizId()+"/category/"+taskCategoryCode+".rst?randomId=" + nonce; + String resutl = HhuEduOaClient.client(appCode, algorithm).doPost(updateTaskUrl, JSONObject.toJSONString(task), getSign(timestamp, nonce), nonce, timestamp, null); + log.info("更新任务result->{}",resutl); + RequestResult requestResult = JSONObject.parseObject(resutl,RequestResult.class); + return requestResult; + } + + /** + * 更新任务状态 + * @param taskBizId 其值是业务系统先前调用createTask时的给出的Task.taskBizId + * @param doneUrl 任务的已办url + * @param state 任务状态:0-未完成 1-已完成 -1-取消 + * @return RequestResult + */ + public RequestResult updateTaskState(String taskBizId, String doneUrl, HhuEduOaStatusEnum state) { + TaskVO vo = new TaskVO(); + vo.setState(state.getCode()); + return updateTask(taskBizId, doneUrl, vo); + } + + /** + * 删除任务 + * @param taskBizId 其值是业务系统先前调用createTask时的给出的Task.taskBizId + * @return RequestResult + */ + public RequestResult deleteTask(String taskBizId) { + String timestamp=System.currentTimeMillis()+""; + String nonce = IdUtil.randomUUID().toString().replaceAll("-", ""); + String deleteTaskUrl = domain + "/_web/_apps/taskcenter/api/v3/taskcenter/app/" + appCode + "/task/"+taskBizId+"/delete.rst?cascade=true"; + String resutl = HhuEduOaClient.client(appCode, algorithm).doPost(deleteTaskUrl, null, getSign(timestamp, nonce), nonce, timestamp, null); + log.info("删除任务result->{}",resutl); + RequestResult requestResult = JSONObject.parseObject(resutl,RequestResult.class); + return requestResult; + } + + /** + * 完成任务 + * @param taskBizId 其值是业务系统先前调用createTask时的给出的Task.taskBizId + * @return RequestResult + */ + public RequestResult finishTask(String taskBizId) { + String timestamp=System.currentTimeMillis()+""; + String nonce = IdUtil.randomUUID().toString().replaceAll("-", ""); + String finishTaskUrl = domain + "/_web/_apps/taskcenter/api/v3/taskcenter/app/"+appCode+"/task/"+ taskBizId+"/finish.rst"; + FinishTaskVO finishTaskVO = new FinishTaskVO(); + finishTaskVO.setDoneDate(new Date()); + String resutl = HhuEduOaClient.client(appCode, algorithm).doPost(finishTaskUrl, JSONObject.toJSONString(finishTaskVO), getSign(timestamp, nonce), nonce, timestamp, null); + log.info("完成任务result->{}",resutl); + RequestResult requestResult = JSONObject.parseObject(resutl,RequestResult.class); + return requestResult; + } + + /** + * 为某个指定的用户完成指定的任务 + * @param taskBizId 任务的业务id。此id有app给出,app需要自己保证其唯一性。用于app对任务进行操作 + * @param loginName 任务创建者的代码,由校方数据中心给出,通常为职工号 + * @param remark 备注,可以存办理的意见等 + * @return RequestResult + */ + public RequestResult doneFinishTask(String taskBizId, String loginName, String remark) { + String timestamp=System.currentTimeMillis()+""; + String nonce = IdUtil.randomUUID().toString().replaceAll("-", ""); + String doneFinishTaskUrl = domain + "/_web/_apps/taskcenter/api/v3/taskcenter/app/"+appCode+"/task/"+ taskBizId+"/user/"+loginName+"/userDone.rst"; + UserDoneAO userDoneAO = new UserDoneAO(); + userDoneAO.setFinishTask(true); + userDoneAO.setDoneDate(new Date()); + userDoneAO.setRemark(remark); + String resutl = HhuEduOaClient.client(appCode, algorithm).doPost(doneFinishTaskUrl, JSONObject.toJSONString(userDoneAO), getSign(timestamp, nonce), nonce, timestamp, null); + log.info("为某个指定的用户完成指定的任务result->{}",resutl); + RequestResult requestResult = JSONObject.parseObject(resutl,RequestResult.class); + return requestResult; + } + + /** + * 追加参与者 + * @param taskBizId 任务的业务id。此id有app给出,app需要自己保证其唯一性。用于app对任务进行操作 + * @param loginNames 职工号 + * @return RequestResult + */ + public RequestResult addPartipantsTask(String taskBizId, List loginNames) { + String timestamp=System.currentTimeMillis()+""; + String nonce = IdUtil.randomUUID().toString().replaceAll("-", ""); + String addPartipantsUrl = domain + "/_web/_apps/taskcenter/api/v3/taskcenter/app/"+ appCode +"/task/"+taskBizId+"/participant.rst"; + ParticipantVO[] participants = new ParticipantVO[loginNames.size()]; + for (int i = 0; i < loginNames.size(); i++) { + ParticipantVO participant = new ParticipantVO(); + participant.setType(ParticipantVO.TYPE_USER); + participant.setUserCode(loginNames.get(i)); + participants[i] = participant; + } + String resutl = HhuEduOaClient.client(appCode, algorithm).doPost(addPartipantsUrl, JSONObject.toJSONString(participants), getSign(timestamp, nonce), nonce, timestamp, null); + log.info("为某个指定的用户完成指定的任务result->{}",resutl); + RequestResult requestResult = JSONObject.parseObject(resutl,RequestResult.class); + return requestResult; + } + + private TaskAndDoneAO getCreateTaskAndDoneAO(String taskBizId, String loginName, String title, String subTitle, String url, List participantUserCodes) { + TaskVO task = new TaskVO(); + Date date = new Date(); + task.setCreatorId(loginName); + task.setDeadLine(date); + task.setUrl(url); + task.setImportance(TaskVO.IMPORTANCE_MIDDLE); + task.setState(TaskVO.STATE_UNDO); + task.setSubTitle(subTitle); + task.setTitle(title); + task.setTaskBizId(taskBizId); + List participantVOS = new ArrayList<>(); + for(String participantUserCode : participantUserCodes){ + ParticipantVO vo = new ParticipantVO(); + vo.setUserCode(participantUserCode); + vo.setType(ParticipantVO.TYPE_USER); + participantVOS.add(vo); + } + task.setParticipants(participantVOS.toArray(new ParticipantVO[participantVOS.size()])); + UserDoneAO userDoneAO = new UserDoneAO(); + userDoneAO.setDoneDate(new Date()); + userDoneAO.setFinishTask(true); + userDoneAO.setDelegate(false); + TaskAndDoneAO taskAndDoneAO = new TaskAndDoneAO(); + taskAndDoneAO.setTaskVO(task); + taskAndDoneAO.setUserDoneAO(userDoneAO); + return taskAndDoneAO; + } + + private TaskVO getCreateTaskVo(String taskBizId, String loginName, String title, String subTitle, String url, String doneUrl, String processNodeName, String applyName, String applyLoginName, String applyOrgName, + List participantUserCodes, TaskVO parentTask) { + TaskVO taskVO = new TaskVO(); + taskVO.setTaskBizId(taskBizId); + taskVO.setCreatorId(loginName); + taskVO.setTitle(title); + if(StrUtil.isNotBlank(subTitle)) { + taskVO.setSubTitle(subTitle); + } + taskVO.setUrl(url); + taskVO.setDoneUrl(doneUrl); + if(StrUtil.isNotBlank(processNodeName)) { + taskVO.setProcessNodeName(processNodeName); + } + if(StrUtil.isNotBlank(applyName)){ + taskVO.setApplyName(applyName); + } + if(StrUtil.isNotBlank(applyLoginName)){ + taskVO.setApplyLoginName(applyLoginName); + } + if(StrUtil.isNotBlank(applyOrgName)){ + taskVO.setApplyOrgName(applyOrgName); + } + List participantVOS = new ArrayList<>(); + for(String participantUserCode : participantUserCodes){ + ParticipantVO vo = new ParticipantVO(); + vo.setUserCode(participantUserCode); + vo.setType(ParticipantVO.TYPE_USER); + participantVOS.add(vo); + } + taskVO.setParticipants(participantVOS.toArray(new ParticipantVO[participantVOS.size()])); + if(parentTask!=null){ + taskVO.setParentTask(parentTask); + } + return taskVO; + } + + private String getSign(String timestamp, String nonce) { + return SudySignUtil.buildSign(algorithm,appCode,timestamp,nonce,null,secretKey); + } + + public static void main(String[] args) { + String taskId = "20260531-01023-9"; + String loginName = "190020250385"; + List participantUserCodes = new ArrayList<>(); + participantUserCodes.add("190020250385"); + HhuEduOaService.getInstance().createTask(taskId, + loginName, + "创建代办任务测试-1", + "http://127.0.0.1:8087/task/create/", + "http://127.0.0.1:8087/task/create/", + "10", + "代办任务测试-1", + "测试人", + loginName, + loginName, + participantUserCodes); + // HhuEduOaService.getInstance().deleteTask(taskId); +// TaskVO taskVO = new TaskVO(); +// taskVO.setTitle("1111"); +// HhuEduOaService.getInstance().updateTask(taskId, "http://127.0.0.1:8087/task/create/", taskVO); +// HhuEduOaService.getInstance().finishTask(taskId); +// HhuEduOaService.getInstance().doneFinishTask(taskId, loginName, "完成审批"); + } +} diff --git a/src/main/java/io/v/nutz/oa/OaTestController.java b/src/main/java/io/v/nutz/oa/OaTestController.java new file mode 100644 index 0000000..b82f0cc --- /dev/null +++ b/src/main/java/io/v/nutz/oa/OaTestController.java @@ -0,0 +1,25 @@ +package io.v.nutz.oa; + +import io.v.nutz.base.result.Result; +import io.v.nutz.oa.service.IOaAuditInstanceService; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.mvc.annotation.At; +import org.nutz.mvc.annotation.Ok; + +@IocBean +@Ok("json") +@At("/test/oa") +public class OaTestController { + + @Inject + private IOaAuditInstanceService oaAuditInstanceService; + + @Ok("json") + @At("/do/port") + public Result doPort() { + // OaAuditInstance instance = oaAuditInstanceService.createTask(OaBusinessTypeEnum.PROPOSAL, "3443554665768799765", "装修食堂-测试", "桌椅调整", "3443554665768799765", Arrays.asList("01nsno67kgingqkdh00omahgse"), "http://127.0.0.1:8089/sysadmin", "https://www.google.cn/"); + // oaAuditInstanceService.agree("7467bdbc2b76434891826d6ee0c1eb48", "01nsno67kgingqkdh00omahgse", "同意"); + return Result.success(); + } +} diff --git a/src/main/java/io/v/nutz/oa/client/HhuEduOaClient.java b/src/main/java/io/v/nutz/oa/client/HhuEduOaClient.java new file mode 100644 index 0000000..a278e1f --- /dev/null +++ b/src/main/java/io/v/nutz/oa/client/HhuEduOaClient.java @@ -0,0 +1,271 @@ +package io.v.nutz.oa.client; + +import io.v.nutz.oa.util.MyHttpDelete; +import org.apache.http.HttpEntity; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; + +import java.io.IOException; + +public class HhuEduOaClient { + + // 平台分配的应用标识 + private String appCode; + // 签名算法方式 + private String algorithm; + + public HhuEduOaClient(String appCode, String algorithm) { + this.appCode = appCode; + this.algorithm = algorithm; + } + + public static HhuEduOaClient client(String appCode, String algorithm) { + return new HhuEduOaClient(appCode, algorithm); + } + + public String doDelete(String url,String json,String signature,String nonce,String timestamp) { + System.out.println(url); + CloseableHttpClient httpClient = null; + CloseableHttpResponse response = null; + String result = ""; + try { + // 通过址默认配置创建一个httpClient实例 + httpClient = HttpClients.createDefault(); + MyHttpDelete httpDelete = new MyHttpDelete(url); + // 设置配置请求参数 + RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(35000)// 连接主机服务超时时间 + .setConnectionRequestTimeout(35000)// 请求超时时间 + .setSocketTimeout(60000)// 数据读取超时时间 + .build(); + // 为httpGet实例设置配置 + httpDelete.setConfig(requestConfig); + if(json != null) { + StringEntity stringEntity = new StringEntity(json, ContentType.APPLICATION_JSON); + httpDelete.setEntity(stringEntity); + } + // 设置请求头信息,鉴权 + httpDelete.setHeader("sd-appid", appCode); + httpDelete.setHeader("sd-algorithm", algorithm); + httpDelete.setHeader("sd-timestamp", timestamp); + httpDelete.setHeader("sd-nonce", nonce); + httpDelete.setHeader("sd-signature", signature); + // 执行get请求得到返回对象 + response = httpClient.execute(httpDelete); + // 通过返回对象获取返回数据 + HttpEntity entity = response.getEntity(); + // 通过EntityUtils中的toString方法将结果转换为字符串 + result = EntityUtils.toString(entity); + System.out.println(result); + } catch (ClientProtocolException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + // 关闭资源 + if (null != response) { + try { + response.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if (null != httpClient) { + try { + httpClient.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return result; + } + + + public String doGet(String url,String timestamp,String nonce,String signature,String summaryVer,String summary) { + System.out.println(url); + CloseableHttpClient httpClient = null; + CloseableHttpResponse response = null; + String result = ""; + try { + // 通过址默认配置创建一个httpClient实例 + httpClient = HttpClients.createDefault(); + HttpGet httpGet = new HttpGet(url); + // 设置请求头信息,鉴权 + //httpGet.setHeader("Authorization", "Bearer da3efcbf-0845-4fe3-8aba-ee040be542c0"); + // 设置配置请求参数 + RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(35000)// 连接主机服务超时时间 + .setConnectionRequestTimeout(35000)// 请求超时时间 + .setSocketTimeout(60000)// 数据读取超时时间 + .build(); + // 设置请求头信息,鉴权 + httpGet.setHeader("sd-appid", appCode); + httpGet.setHeader("sd-algorithm", algorithm); + httpGet.setHeader("sd-timestamp", timestamp); + httpGet.setHeader("sd-nonce", nonce); + httpGet.setHeader("sd-signature", signature); + if(summaryVer!= null) { + httpGet.setHeader("sd-summary-ver", summaryVer); + httpGet.setHeader("sd-summary", summary); + } + // 为httpGet实例设置配置 + httpGet.setConfig(requestConfig); + // 执行get请求得到返回对象 + response = httpClient.execute(httpGet); + // 通过返回对象获取返回数据 + HttpEntity entity = response.getEntity(); + // 通过EntityUtils中的toString方法将结果转换为字符串 + result = EntityUtils.toString(entity); + System.out.println(result); + } catch (ClientProtocolException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + // 关闭资源 + if (null != response) { + try { + response.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if (null != httpClient) { + try { + httpClient.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return result; + } + + public String doPost(String url, String json, String signature, String nonce,String timestamp,String summary) { + System.out.println(url); + CloseableHttpClient httpClient = null; + CloseableHttpResponse response = null; + String result = ""; + try { + // 通过址默认配置创建一个httpClient实例 + httpClient = HttpClients.createDefault(); + HttpPost httpPost = new HttpPost(url); + System.out.println(json); + if(json != null) { + StringEntity stringEntity = new StringEntity(json, ContentType.APPLICATION_JSON); + httpPost.setEntity(stringEntity); + } + // 设置请求头信息,鉴权 + httpPost.setHeader("sd-appid", appCode); + httpPost.setHeader("sd-algorithm", algorithm); + httpPost.setHeader("sd-timestamp", timestamp); + httpPost.setHeader("sd-nonce", nonce); + httpPost.setHeader("sd-signature", signature); + if(summary != null){ + httpPost.setHeader("sd-summary", summary); + } + // 设置配置请求参数 + RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(35000)// 连接主机服务超时时间 + .setConnectionRequestTimeout(35000)// 请求超时时间 + .setSocketTimeout(60000)// 数据读取超时时间 + .build(); + // 为httpGet实例设置配置 + httpPost.setConfig(requestConfig); + // 执行get请求得到返回对象 + response = httpClient.execute(httpPost); + // 通过返回对象获取返回数据 + HttpEntity entity = response.getEntity(); + // 通过EntityUtils中的toString方法将结果转换为字符串 + result = EntityUtils.toString(entity); + System.out.println("111="+result); + } catch (ClientProtocolException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + // 关闭资源 + if (null != response) { + try { + response.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if (null != httpClient) { + try { + httpClient.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return result; + } + + public String doPut(String url,String json,String signature,String nonce,String timestamp) { + CloseableHttpClient httpClient = null; + CloseableHttpResponse response = null; + String result = ""; + try { + httpClient = HttpClients.createDefault(); // 通过址默认配置创建一个httpClient实例 + HttpPut httpPut = new HttpPut(url); + System.out.println(json); + StringEntity stringEntity = new StringEntity(json, ContentType.APPLICATION_JSON); + httpPut.setEntity(stringEntity); + // 设置请求头信息,鉴权 + httpPut.setHeader("sd-appid", appCode); + httpPut.setHeader("sd-algorithm", algorithm); + httpPut.setHeader("sd-timestamp", timestamp); + httpPut.setHeader("sd-nonce", nonce); + httpPut.setHeader("sd-signature", signature); + // 设置配置请求参数 + RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(35000)// 连接主机服务超时时间 + .setConnectionRequestTimeout(35000)// 请求超时时间 + .setSocketTimeout(60000)// 数据读取超时时间 + .build(); + + httpPut.setConfig(requestConfig); // 为httpGet实例设置配置 + response = httpClient.execute(httpPut);// 执行get请求得到返回对象 + HttpEntity entity = response.getEntity();// 通过返回对象获取返回数据 + result = EntityUtils.toString(entity);// 通过EntityUtils中的toString方法将结果转换为字符串 + System.out.println(result); + } catch (ClientProtocolException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + // 关闭资源 + if (null != response) { + try { + response.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if (null != httpClient) { + try { + httpClient.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return result; + } +} diff --git a/src/main/java/io/v/nutz/oa/constants/CommonConstants.java b/src/main/java/io/v/nutz/oa/constants/CommonConstants.java new file mode 100644 index 0000000..044aa47 --- /dev/null +++ b/src/main/java/io/v/nutz/oa/constants/CommonConstants.java @@ -0,0 +1,16 @@ +package io.v.nutz.oa.constants; + +public interface CommonConstants { + + public static Integer ZERO = 0; + public static Integer ONE = 1; + public static Integer TWO = 2; + public static Integer THREE = 3; + public static Integer FOUR = 4; + public static Integer FIVE = 5; + public static Integer SIX = 6; + public static Integer SEVEN = 7; + public static Integer EIGHT = 8; + public static Integer NINE = 9; + public static Integer TEN = 10; +} diff --git a/src/main/java/io/v/nutz/oa/controller/OaAuditInstanceController.java b/src/main/java/io/v/nutz/oa/controller/OaAuditInstanceController.java new file mode 100644 index 0000000..91f7345 --- /dev/null +++ b/src/main/java/io/v/nutz/oa/controller/OaAuditInstanceController.java @@ -0,0 +1,53 @@ +package io.v.nutz.oa.controller; + +import io.v.nutz.base.result.Result; +import io.v.nutz.modules.models.PageForm; +import io.v.nutz.oa.dto.OaAuditInstanceDto; +import io.v.nutz.oa.model.OaAuditInstance; +import io.v.nutz.oa.service.IOaAuditInstanceService; +import io.v.nutz.web.commons.utils.ShiroUtil; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.mvc.annotation.At; +import org.nutz.mvc.annotation.Ok; + +import java.util.List; + +@IocBean +@Ok("json") +@At("/oa/audit/instance") +public class OaAuditInstanceController { + + @Inject + private IOaAuditInstanceService oaAuditInstanceService; + + /** + * 待处理 + */ + @Ok("json") + @At("/wait/handle") + public Result waitHandle() { + List waitHandleList = oaAuditInstanceService.getWaitHandleList(ShiroUtil.getUserId()); + return Result.success(waitHandleList); + } + + /** + * 已处理 + */ + @Ok("json") + @At("/complete/handle") + public Object completeHandle(PageForm pageForm, OaAuditInstanceDto instance) { + instance.setCreateUser(ShiroUtil.getUserId()); + return oaAuditInstanceService.completeHandle(pageForm.getPageNumber(), pageForm.getPageSize(), instance); + } + + /** + * 我发起的 + */ + @Ok("json") + @At("/mine/send") + public Object mineSend(PageForm pageForm, OaAuditInstanceDto instance) { + instance.setCreateUser(ShiroUtil.getUserId()); + return oaAuditInstanceService.mineSend(pageForm.getPageNumber(), pageForm.getPageSize(), instance); + } +} diff --git a/src/main/java/io/v/nutz/oa/dto/OaAuditInstanceDto.java b/src/main/java/io/v/nutz/oa/dto/OaAuditInstanceDto.java new file mode 100644 index 0000000..3a25ab6 --- /dev/null +++ b/src/main/java/io/v/nutz/oa/dto/OaAuditInstanceDto.java @@ -0,0 +1,13 @@ +package io.v.nutz.oa.dto; + +import lombok.Data; +import org.nutz.dao.entity.annotation.Comment; + +import java.io.Serializable; + +@Data +public class OaAuditInstanceDto implements Serializable { + + @Comment("创建人ID") + private String createUser; +} diff --git a/src/main/java/io/v/nutz/oa/enums/HhuEduOaStatusEnum.java b/src/main/java/io/v/nutz/oa/enums/HhuEduOaStatusEnum.java new file mode 100644 index 0000000..1560fa2 --- /dev/null +++ b/src/main/java/io/v/nutz/oa/enums/HhuEduOaStatusEnum.java @@ -0,0 +1,43 @@ +package io.v.nutz.oa.enums; + +public enum HhuEduOaStatusEnum { + + STATE_UNDO(0, "未完成"), + STATE_DONE(1, "已完成"), + STATE_SUSPENDED(2, "已挂起"), + STATE_CANCELED(-1, "取消"), + STATE_ARCHIVED(3, "已归档"), + STATE_STOPED(-2, "已终止"), + STATE_DELETED(-3, "已删除"); + + private Integer code; + + public Integer getCode() { + return code; + } + + private String name; + + public String getName() { + return name; + } + + public static HhuEduOaStatusEnum getByCode(Integer code) { + if (code == null) { + return null; + } else { + HhuEduOaStatusEnum[] values = values(); + for (HhuEduOaStatusEnum value : values) { + if (value.getCode().equals(code)) { + return value; + } + } + } + return null; + } + + HhuEduOaStatusEnum(Integer code, String name) { + this.code = code; + this.name = name; + } +} diff --git a/src/main/java/io/v/nutz/oa/enums/OaBusinessTypeEnum.java b/src/main/java/io/v/nutz/oa/enums/OaBusinessTypeEnum.java new file mode 100644 index 0000000..5272df0 --- /dev/null +++ b/src/main/java/io/v/nutz/oa/enums/OaBusinessTypeEnum.java @@ -0,0 +1,53 @@ +package io.v.nutz.oa.enums; + +public enum OaBusinessTypeEnum { + WRITE_PROPOSAL(1, "撰写提案方案附议", "9"), + TUANZHANG_AUDIT_PROPOSAL(2, "团长审批提案", "18"), + PROPOSAL_COMMITTEE_AUDIT(3, "提案委立案审核", "27"), + HOST_ORGANIZER_REPLY_HANDLE(4, "主办单位提案答复", "72"), + HELP_ORGANIZER_REPLY_HANDLE(5, "协办单位提案答复", "81"), + DIVIDE_SCHOOL_LEADERS_AUDIT(6, "分管校领导审批", "90"), + PROPOSAL_FEEDBACK_EVALUATE_AUDIT(7, "提案反馈评价", "100"), + DIRECTOR_EXECUTIVE_COMMITTEE(8, "执委会主任审核", "36"), + PRINCIPAL_SECRETARY_AUDIT(9, "校长、书记审核", "45"), + DIRECTOR_EXECUTIVE_CONFIRM_COMMITTEE(10, "执委会主任确认审核", "54"), + DIRECTOR_CONFIRM_ORGANIZER_REPLY(11, "提案委确认承办审核", "63"); + + private Integer code; + + public Integer getCode() { + return code; + } + + private String name; + + public String getName() { + return name; + } + + private String processNodeId; + + public String getProcessNodeId() { + return processNodeId; + } + + public static OaBusinessTypeEnum getByCode(Integer code) { + if (code == null) { + return null; + } else { + OaBusinessTypeEnum[] values = values(); + for (OaBusinessTypeEnum value : values) { + if (value.getCode().equals(code)) { + return value; + } + } + } + return null; + } + + OaBusinessTypeEnum(Integer code, String name, String processNodeId) { + this.code = code; + this.name = name; + this.processNodeId = processNodeId; + } +} diff --git a/src/main/java/io/v/nutz/oa/enums/OaStatusEnum.java b/src/main/java/io/v/nutz/oa/enums/OaStatusEnum.java new file mode 100644 index 0000000..9b2c6f4 --- /dev/null +++ b/src/main/java/io/v/nutz/oa/enums/OaStatusEnum.java @@ -0,0 +1,42 @@ +package io.v.nutz.oa.enums; + +public enum OaStatusEnum { + // 状态: 0.未提交 1.审批中 2.审批完成 3.审批驳回 4.审批撤回 + NO_AUDIT(0, "未提交"), + AUDITING(1, "审批中"), + AUDIT_PASS(2, "审批完成"), + REJECT(3, "审批驳回"), + CANCEL(4, "审批撤回"); + + private Integer code; + + + public Integer getCode() { + return code; + } + + private String name; + + public String getName() { + return name; + } + + public static OaStatusEnum getByCode(Integer code) { + if (code == null) { + return null; + } else { + OaStatusEnum[] values = values(); + for (OaStatusEnum value : values) { + if (value.getCode().equals(code)) { + return value; + } + } + } + return null; + } + + OaStatusEnum(Integer code, String name) { + this.code = code; + this.name = name; + } +} diff --git a/src/main/java/io/v/nutz/oa/model/OaAuditInstance.java b/src/main/java/io/v/nutz/oa/model/OaAuditInstance.java new file mode 100644 index 0000000..5b7782d --- /dev/null +++ b/src/main/java/io/v/nutz/oa/model/OaAuditInstance.java @@ -0,0 +1,104 @@ +package io.v.nutz.oa.model; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; +import org.nutz.dao.entity.annotation.*; + +import java.io.Serializable; +import java.util.Date; + +@Data +@Comment("审批实例流程") +@Table(value = "oa_audit_instance") +public class OaAuditInstance implements Serializable { + + @Name + @Comment("主键ID") + @Column(value = "id") + @Prev(els = {@EL("uuid()")}) + @ColDefine(type = ColType.VARCHAR, width = 32) + private String id; + + @Comment("业务ID") + @Column(value = "business_id") + @ColDefine(type = ColType.VARCHAR, width = 32) + private String businessId; + + + @Comment("业务类型: 1.代表提案") + @Column(value = "business_type") + @ColDefine(type = ColType.INT) + private Integer businessType; + + @Comment("流程名称") + @Column(value = "process_name") + @ColDefine(type = ColType.VARCHAR, width = 500) + private String processName; + + @Comment("实例标题") + @Column(value = "title") + @ColDefine(type = ColType.VARCHAR, width = 255) + private String title; + + @Comment("子标题") + @Column(value = "sub_title") + @ColDefine(type = ColType.VARCHAR, width = 255) + private String subTitle; + + @Comment("业务实例ID") + @Column(value = "business_task_id") + @ColDefine(type = ColType.VARCHAR, width = 255) + private String businessTaskId; + + @Comment("业务实例ID") + @Column(value = "instance_task_id") + @ColDefine(type = ColType.VARCHAR, width = 255) + private String instanceTaskId ; + + @Comment("创建人ID") + @Column(value = "create_user") + @ColDefine(type = ColType.VARCHAR, width = 32) + private String createUser; + + @Comment("创建人") + @Column(value = "create_name") + @ColDefine(type = ColType.VARCHAR, width = 32) + private String createName; + + @Comment("第三方职工号") + @Column(value = "create_login_code") + @ColDefine(type = ColType.VARCHAR, width = 32) + private String createLoginCode; + + @Comment("状态: 0.未提交 1.审批中 2.审批完成 3.审批驳回 4.审批撤回") + @Column(value = "status") + @ColDefine(type = ColType.INT) + private Integer status; + + @Comment("状态备注") + @Column(value = "status_reason") + @ColDefine(type = ColType.VARCHAR, width = 500) + private String statusReason; + + @Comment("创建时间") + @Column(value = "create_time") + @ColDefine(type = ColType.TIMESTAMP) + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + @Comment("审批结束时间") + @Column(value = "over_time") + @ColDefine(type = ColType.TIMESTAMP) + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + private Date overTime; + + @Comment("任务的处理url") + @Column(value = "url") + @ColDefine(type = ColType.VARCHAR, width = 500) + private String url; + + @Comment("任务的已办url") + @Column(value = "done_url") + @ColDefine(type = ColType.VARCHAR, width = 500) + private String doneUrl; +} diff --git a/src/main/java/io/v/nutz/oa/model/OaInstanceUser.java b/src/main/java/io/v/nutz/oa/model/OaInstanceUser.java new file mode 100644 index 0000000..8cdc8e6 --- /dev/null +++ b/src/main/java/io/v/nutz/oa/model/OaInstanceUser.java @@ -0,0 +1,63 @@ +package io.v.nutz.oa.model; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; +import org.nutz.dao.entity.annotation.*; + +import java.io.Serializable; +import java.util.Date; + +@Data +@Comment("审批实例用户") +@Table(value = "oa_instance_user") +public class OaInstanceUser implements Serializable { + + @Name + @Comment("主键ID") + @Column(value = "id") + @Prev(els = {@EL("uuid()")}) + @ColDefine(type = ColType.VARCHAR, width = 32) + private String id; + + @Comment("实例ID") + @Column(value = "instance_id") + @ColDefine(type = ColType.VARCHAR, width = 32) + private String instanceId; + + @Comment("用户ID") + @Column(value = "user_id") + @ColDefine(type = ColType.VARCHAR, width = 32) + private String userId; + + @Comment("用户名称") + @Column(value = "user_name") + @ColDefine(type = ColType.VARCHAR, width = 255) + private String userName; + + @Comment("第三方职工号") + @Column(value = "user_login_code") + @ColDefine(type = ColType.VARCHAR, width = 255) + private String userLoginCode; + + @Comment("状态: 0.未提交 1.审批中 2.审批完成 3.审批驳回 4.审批撤回") + @Column(value = "status") + @ColDefine(type = ColType.INT) + private Integer status; + + @Comment("状态备注") + @Column(value = "status_reason") + @ColDefine(type = ColType.VARCHAR, width = 500) + private String statusReason; + + @Comment("创建时间") + @Column(value = "create_time") + @ColDefine(type = ColType.TIMESTAMP) + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + @Comment("审批结束时间") + @Column(value = "over_time") + @ColDefine(type = ColType.TIMESTAMP) + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + private Date overTime; +} diff --git a/src/main/java/io/v/nutz/oa/notify/OaAuditNotify.java b/src/main/java/io/v/nutz/oa/notify/OaAuditNotify.java new file mode 100644 index 0000000..43df119 --- /dev/null +++ b/src/main/java/io/v/nutz/oa/notify/OaAuditNotify.java @@ -0,0 +1,38 @@ +package io.v.nutz.oa.notify; + +import com.alibaba.fastjson.JSONObject; +import io.v.nutz.base.result.Result; +import lombok.extern.slf4j.Slf4j; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.mvc.annotation.At; +import org.nutz.mvc.annotation.Ok; + +import java.util.Map; + +@Slf4j +@IocBean +@Ok("json:full") +@At("/notify/oa/audit") +public class OaAuditNotify { + + + /** + * 任务处理 + */ + @Ok("json") + @At("/handle/task") + public Result handleTask(Map map) { + log.info("收到OA任务处理通知:{}", JSONObject.toJSONString(map)); + return Result.success(); + } + + /** + * 任务已办通知 + */ + @Ok("json") + @At("/finish/task") + public Result finishTask(Map map) { + log.info("收到OA任务已办通知:{}", JSONObject.toJSONString(map)); + return Result.success(); + } +} diff --git a/src/main/java/io/v/nutz/oa/pojo/RequestResult.java b/src/main/java/io/v/nutz/oa/pojo/RequestResult.java new file mode 100644 index 0000000..451ed64 --- /dev/null +++ b/src/main/java/io/v/nutz/oa/pojo/RequestResult.java @@ -0,0 +1,27 @@ +package io.v.nutz.oa.pojo; + +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +@Data +@NoArgsConstructor +@Accessors(chain=true) +public class RequestResult { + + private String errorMsg; + + private Result result; + + private Integer resultCode; + + @Data + @NoArgsConstructor + @Accessors(chain=true) + public class Result { + + private Object data; + + private Integer total; + } +} diff --git a/src/main/java/io/v/nutz/oa/service/IOaAuditInstanceService.java b/src/main/java/io/v/nutz/oa/service/IOaAuditInstanceService.java new file mode 100644 index 0000000..fdbd814 --- /dev/null +++ b/src/main/java/io/v/nutz/oa/service/IOaAuditInstanceService.java @@ -0,0 +1,106 @@ +package io.v.nutz.oa.service; + +import io.v.nutz.base.page.Pagination; +import io.v.nutz.base.service.BaseService; +import io.v.nutz.oa.dto.OaAuditInstanceDto; +import io.v.nutz.oa.enums.OaBusinessTypeEnum; +import io.v.nutz.oa.enums.OaStatusEnum; +import io.v.nutz.oa.model.OaAuditInstance; + +import java.util.List; + +public interface IOaAuditInstanceService extends BaseService { + + List getWaitHandleList(String userId); + + + OaAuditInstance getByUser(OaBusinessTypeEnum businessTypeEnum, String businessId, String userId); + + OaAuditInstance getByUser(OaBusinessTypeEnum businessTypeEnum, String userId); + + Pagination completeHandle(Integer pageNumber, Integer pageSize, OaAuditInstanceDto instance); + + Pagination mineSend(Integer pageNumber, Integer pageSize, OaAuditInstanceDto instance); + + OaAuditInstance getByBusinessType(OaBusinessTypeEnum businessType, String businessId); + + List getByBusinessTypeRunning(OaBusinessTypeEnum businessType); + + List getAllByBusinessType(OaBusinessTypeEnum businessType, String businessId); + + /** + * 创建审批代办任务信息 + * @param businessType 业务类型 用来区分任务审批 + * @param businessId 审批的对应业务数据ID + * @param title 主标题 + * @param subTitle 子标题 + * @param createUserId 创建任务ID + * @param auditUsers 参与审批人ID + * @param url 任务的处理url + * @param doneUrl 任务的已办URL + * @return OaAuditInstance + */ + OaAuditInstance createTask(OaBusinessTypeEnum businessType, String businessId, String title, String subTitle, String createUserId, List auditUsers, String url, String doneUrl); + + /** + * 创建审批代办任务信息 + * @param businessType 业务类型 用来区分任务审批 + * @param businessId 审批的对应业务数据ID + * @param processName 流程名称 + * @param title 主标题 + * @param subTitle 子标题 + * @param createUserId 创建任务ID + * @param auditUsers 参与审批人ID + * @param url 任务的处理url + * @param doneUrl 任务的已办URL + * @return OaAuditInstance + */ + OaAuditInstance createTask(OaBusinessTypeEnum businessType, String businessId, String processName, String title, String subTitle, String createUserId, List auditUsers, String url, String doneUrl); + + /** + * 同意 参与审批者同意 + * @param instanceId 实例ID + * @param remark 备注 + */ + void agree(String instanceId, String remark); + + /** + * 同意 参与审批者同意 + * @param instanceId 实例ID + * @param userId 审核用户ID + * @param remark 备注 + */ + void agree(String instanceId, String userId, String remark); + + /** + * 同意 参与审批者同意 + * @param instanceId 实例ID + * @param userId 审核用户ID + * @param remark 备注 + * @param isAgreeOne 是否同意一人整个任务通过 + */ + void agree(String instanceId, String userId, String remark, Boolean isAgreeOne); + + /** 拒绝 + * + * @param instanceId 实例ID + * @param userId 审核用户ID + * @param remark 备注 + */ + void refuse(String instanceId, String userId, String remark); + + /** + * 任务取消/撤回 由任务发起者来取消 整个任务结束 + * @param instanceId 任务实例ID + * @param userId 用户ID + */ + void cancel(String instanceId, String userId); + + /** + * 更新实例状态 + * @param id 任务实例ID + * @param oaStatusEnum 状态 + * @param instanceTaskId + */ + void updateInstanceStatus(String id, OaStatusEnum oaStatusEnum, String instanceTaskId); +} diff --git a/src/main/java/io/v/nutz/oa/service/IOaInstanceUserService.java b/src/main/java/io/v/nutz/oa/service/IOaInstanceUserService.java new file mode 100644 index 0000000..6574d01 --- /dev/null +++ b/src/main/java/io/v/nutz/oa/service/IOaInstanceUserService.java @@ -0,0 +1,27 @@ +package io.v.nutz.oa.service; + +import io.v.nutz.base.service.BaseService; +import io.v.nutz.oa.enums.OaStatusEnum; +import io.v.nutz.oa.model.OaInstanceUser; +import org.nutz.lang.util.NutMap; + +import java.util.List; + +public interface IOaInstanceUserService extends BaseService { + + OaInstanceUser getByUserId(String instanceId, String userId); + + List getAuditing(String instanceId); + + List getInstanceUser(String instanceId); + + void createRecord(String instanceId, List userIds); + + void createRecord(String instanceId, List userIds, OaStatusEnum oaStatusEnum); + + void updateStatus(String id, OaStatusEnum oaStatusEnum, String statusReason); + + void updateStatusByInstanceId(String instanceId, OaStatusEnum oaStatusEnum); + + void appendAuditUser(String instanceId, String businessTaskId, List auditUsers); +} diff --git a/src/main/java/io/v/nutz/oa/service/impl/OaAuditInstanceServiceImpl.java b/src/main/java/io/v/nutz/oa/service/impl/OaAuditInstanceServiceImpl.java new file mode 100644 index 0000000..c0e4ad7 --- /dev/null +++ b/src/main/java/io/v/nutz/oa/service/impl/OaAuditInstanceServiceImpl.java @@ -0,0 +1,315 @@ +package io.v.nutz.oa.service.impl; + +import cn.hutool.core.date.DateUtil; +import io.v.nutz.base.page.Pagination; +import io.v.nutz.base.service.impl.BaseServiceImpl; +import io.v.nutz.oa.HhuEduOaService; +import io.v.nutz.oa.constants.CommonConstants; +import io.v.nutz.oa.dto.OaAuditInstanceDto; +import io.v.nutz.oa.enums.HhuEduOaStatusEnum; +import io.v.nutz.oa.enums.OaBusinessTypeEnum; +import io.v.nutz.oa.enums.OaStatusEnum; +import io.v.nutz.oa.model.OaAuditInstance; +import io.v.nutz.oa.model.OaInstanceUser; +import io.v.nutz.oa.pojo.RequestResult; +import io.v.nutz.oa.service.IOaAuditInstanceService; +import io.v.nutz.oa.service.IOaInstanceUserService; +import io.v.nutz.oa.util.BillNoUtil; +import io.v.nutz.sys.models.Sys_user; +import io.v.nutz.sys.services.SysUserService; +import lombok.extern.slf4j.Slf4j; +import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.ioc.impl.PropertiesProxy; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +@Slf4j +@IocBean(args = {"refer:dao"}) +public class OaAuditInstanceServiceImpl extends BaseServiceImpl implements IOaAuditInstanceService { + + @Inject + private PropertiesProxy conf; + + @Inject + private SysUserService sysUserService; + + @Inject + private IOaInstanceUserService instanceUserService; + + + public OaAuditInstanceServiceImpl(Dao dao) { + super(dao); + } + + @Override + public List getWaitHandleList(String userId) { + Sql sql = Sqls.create("select * from oa_audit_instance where status = 1" + + " and id in (select instance_id from oa_instance_user where status = 1 and" + + " user_id=@user_id) order by create_time asc"); + sql.params().set("user_id", userId); + sql.setCallback(Sqls.callback.records()); + this.dao().execute(sql); + return sql.getList(OaAuditInstance.class); + } + + @Override + public OaAuditInstance getByUser(OaBusinessTypeEnum businessTypeEnum, String businessId, String userId) { + Sql sql = Sqls.create("select oai.*" + + "from oa_instance_user oiu left join oa_audit_instance oai on oiu.instance_id = oai.id " + + "where oai.business_type=@business_type and oai.business_id=@business_id and oiu.user_id=@user_id" + + " and oai.status=1 order by oai.create_time desc limit 0,1"); + sql.params().set("business_type", businessTypeEnum.getCode()); + sql.params().set("business_id", businessId); + sql.params().set("user_id", userId); + sql.setCallback(Sqls.callback.record()); + this.dao().execute(sql); + return sql.getObject(OaAuditInstance.class); + } + + @Override + public OaAuditInstance getByUser(OaBusinessTypeEnum businessTypeEnum, String userId) { + Sql sql = Sqls.create("select oai.*" + + "from oa_instance_user oiu left join oa_audit_instance oai on oiu.instance_id = oai.id " + + "where oai.business_type=@business_type and oiu.user_id=@user_id" + + " and oai.status=1 and oiu.status=1 order by oai.create_time desc limit 0,1"); + sql.params().set("business_type", businessTypeEnum.getCode()); + sql.params().set("user_id", userId); + sql.setCallback(Sqls.callback.record()); + this.dao().execute(sql); + return sql.getObject(OaAuditInstance.class); + } + + @Override + public Pagination completeHandle(Integer pageNumber, Integer pageSize, OaAuditInstanceDto instance) { + Sql sql = Sqls.create("select oai.* " + + "from oa_instance_user oiu left join oa_audit_instance oai on oiu.instance_id = oai.id" + + " where oiu.user_id=@user_id and (oiu.status not in (0,1) or oai.status not in(0,1))" + + " order by oiu.create_time desc"); + sql.params().set("user_id", instance.getCreateUser()); + return listPage(pageNumber, pageSize, sql); + } + + @Override + public Pagination mineSend(Integer pageNumber, Integer pageSize, OaAuditInstanceDto instance) { + Sql sql = Sqls.create("select * from oa_audit_instance where create_user=@create_user order by create_time desc"); + sql.params().set("create_user", instance.getCreateUser()); + return listPage(pageNumber, pageSize, sql); + } + + @Override + public List getByBusinessTypeRunning(OaBusinessTypeEnum businessType) { + Sql sql = Sqls.create("select * from oa_audit_instance where business_type=@business_type " + + "and business_id=@business_id and status=1"); + sql.params().set("business_type", businessType.getCode()); + sql.setCallback(Sqls.callback.maps()); + this.dao().execute(sql); + return sql.getList(OaAuditInstance.class); + } + + @Override + public OaAuditInstance getByBusinessType(OaBusinessTypeEnum businessType, String businessId) { + Sql sql = Sqls.create("select * from oa_audit_instance where business_type=@business_type " + + "and business_id=@business_id and status=1 limit 0,1"); + sql.params().set("business_type", businessType.getCode()); + sql.params().set("business_id", businessId); + sql.setCallback(Sqls.callback.map()); + this.dao().execute(sql); + return sql.getObject(OaAuditInstance.class); + } + + @Override + public List getAllByBusinessType(OaBusinessTypeEnum businessType, String businessId) { + Sql sql = Sqls.create("select * from oa_audit_instance where business_type=@business_type " + + "and business_id=@business_id"); + sql.params().set("business_type", businessType.getCode()); + sql.params().set("business_id", businessId); + sql.setCallback(Sqls.callback.maps()); + this.dao().execute(sql); + return sql.getList(OaAuditInstance.class); + } + + @Override + public OaAuditInstance createTask(OaBusinessTypeEnum businessType, String businessId, String title, String subTitle, String createUserId, List auditUsers, String url, String doneUrl) { + return this.createTask(businessType, businessId, null, title, subTitle, createUserId, auditUsers, url, doneUrl); + } + + + @Override + public OaAuditInstance createTask(OaBusinessTypeEnum businessType, String businessId, String processName, String title, String subTitle, String createUserId, List auditUsers, String url, String doneUrl) { +// OaAuditInstance instance = this.getByBusinessType(businessType, businessId); +// if(instance != null) { +// +// // 追加审批用户 +// instanceUserService.appendAuditUser(instance.getId(), instance.getBusinessTaskId(), auditUsers); +// this.updateInstanceStatus(instance.getId(), OaStatusEnum.AUDITING, instance.getInstanceTaskId()); +// return instance; +// } +// +// instance = new OaAuditInstance(); + OaAuditInstance instance = new OaAuditInstance(); + instance.setBusinessType(businessType.getCode()); + instance.setBusinessId(businessId); + instance.setTitle(title); + instance.setSubTitle(subTitle); + instance.setCreateTime(DateUtil.date()); + instance.setStatus(OaStatusEnum.NO_AUDIT.getCode()); + instance.setProcessName(processName); + instance.setUrl(url); + instance.setDoneUrl(doneUrl); + + // 提交人用户信息 + Sys_user submitUser = sysUserService.fetch(createUserId); + if(submitUser == null){ + throw new RuntimeException("提交人不存在"); + } + instance.setCreateUser(submitUser.getId()); + instance.setCreateName(submitUser.getUsername()); + instance.setCreateLoginCode(submitUser.getLoginname()); + // 业务实例ID + String businessTaskId = BillNoUtil.getBusinessTaskId(); + instance.setBusinessTaskId(businessTaskId); + this.insert(instance); + + // 任务实例参与审批信息 + instanceUserService.createRecord(instance.getId(), auditUsers); + + // 生成第三方代办任务实例 + this.createHhuEduOa(instance.getId()); + return instance; + } + + @Override + public void agree(String instanceId, String remark) { + List oaInstanceUsers = instanceUserService.getAuditing(instanceId); + for(OaInstanceUser user : oaInstanceUsers) { + this.agree(instanceId, user.getUserId(), remark); + } + } + + @Override + public void agree(String instanceId, String userId, String remark) { + this.agree(instanceId, userId, remark, false); + } + + @Override + public void agree(String instanceId, String userId, String remark, Boolean isAgreeOne) { + OaInstanceUser instanceUser = instanceUserService.getByUserId(instanceId, userId); + if(instanceUser == null) { + throw new RuntimeException("当前用户未参与审批"); + } + OaAuditInstance instance = this.fetch(instanceId); + if(instance.getStatus().equals(OaStatusEnum.AUDIT_PASS.getCode()) || instance.getStatus().equals(OaStatusEnum.CANCEL.getCode())) { + throw new RuntimeException("该任务已结束"); + } + RequestResult result = HhuEduOaService.getInstance().doneFinishTask(instance.getBusinessTaskId(), instanceUser.getUserLoginCode(), remark); + if(!result.getResultCode().equals(CommonConstants.ZERO)) { + // throw new RuntimeException(result.getErrorMsg()); + log.info("调用第三方待办服务异常:{}", result.getErrorMsg()); + } + instanceUserService.updateStatus(instanceUser.getId(), OaStatusEnum.AUDIT_PASS, remark); + + // 审批中用户 + List auditingUsers = instanceUserService.getAuditing(instance.getId()); + if(auditingUsers == null || auditingUsers.size() <= 0) { + this.updateInstanceStatus(instanceId, OaStatusEnum.AUDIT_PASS, instance.getInstanceTaskId()); + + } else if(isAgreeOne) { + this.updateInstanceStatus(instanceId, OaStatusEnum.AUDIT_PASS, instance.getInstanceTaskId()); + } + } + + @Override + public void refuse(String instanceId, String userId, String remark) { + OaInstanceUser instanceUser = instanceUserService.getByUserId(instanceId, userId); + if(instanceUser == null) { + throw new RuntimeException("当前用户未参与审批"); + } + OaAuditInstance instance = this.fetch(instanceId); + if(instance.getStatus().equals(OaStatusEnum.AUDIT_PASS.getCode()) || instance.getStatus().equals(OaStatusEnum.CANCEL.getCode())) { + throw new RuntimeException("该任务已结束"); + } + RequestResult result = HhuEduOaService.getInstance().doneFinishTask(instance.getBusinessTaskId(), instanceUser.getUserLoginCode(), remark); + if(!result.getResultCode().equals(CommonConstants.ZERO)) { + throw new RuntimeException(result.getErrorMsg()); + } + instanceUserService.updateStatus(instanceUser.getId(), OaStatusEnum.REJECT, remark); + + // 主流程驳回 + this.updateInstanceStatus(instanceId, OaStatusEnum.REJECT, instance.getInstanceTaskId()); + } + + @Override + public void cancel(String instanceId, String userId) { + OaAuditInstance instance = this.fetch(instanceId); + if(instance == null) { + throw new RuntimeException("任务实例不存在"); + } + if(instance.getStatus().equals(OaStatusEnum.AUDIT_PASS.getCode()) || instance.getStatus().equals(OaStatusEnum.CANCEL.getCode())) { + throw new RuntimeException("该任务已结束"); + } + if(!instance.getCreateUser().equals(userId)) { + throw new RuntimeException("该用户无权限取消/撤回待办任务"); + } + RequestResult result = HhuEduOaService.getInstance().updateTaskState(instance.getBusinessTaskId(), "", HhuEduOaStatusEnum.STATE_CANCELED); + if(!result.getResultCode().equals(CommonConstants.ZERO)) { + throw new RuntimeException(result.getErrorMsg()); + } + this.updateInstanceStatus(instance.getId(), OaStatusEnum.CANCEL, instance.getInstanceTaskId()); + } + + @Override + public void updateInstanceStatus(String id, OaStatusEnum oaStatusEnum, String instanceTaskId) { + StringBuilder sqlStr = new StringBuilder("update oa_audit_instance set status=@status, instance_task_id=@instance_task_id"); + if(OaStatusEnum.AUDIT_PASS.getCode().equals(oaStatusEnum.getCode())) { + sqlStr.append(", over_time=@over_time"); + } + sqlStr.append(" where id=@id"); + + Sql sql = Sqls.create(sqlStr.toString()); + sql.params().set("instance_task_id", instanceTaskId); + sql.params().set("status", oaStatusEnum.getCode()); + if(OaStatusEnum.AUDIT_PASS.getCode().equals(oaStatusEnum.getCode())) { + sql.params().set("over_time", DateUtil.date()); + } + sql.params().set("id", id); + this.dao().execute(sql); + } + + // 生成第三方代办任务实例 + private void createHhuEduOa(String id) { +// String serverPort = conf.get("server.port"); + OaAuditInstance instance = this.fetch(id); + Sql sql = Sqls.create("select * from oa_instance_user where instance_id = @instance_id"); + sql.params().set("instance_id", id); + List instanceUsers = instanceUserService.listEntity(sql); + List participantUserCodes = Collections.synchronizedList(new ArrayList()); + for(OaInstanceUser instanceUser : instanceUsers){ + participantUserCodes.add(instanceUser.getUserLoginCode()); + } + OaBusinessTypeEnum businessTypeEnum = OaBusinessTypeEnum.getByCode(instance.getBusinessType()); + RequestResult result = HhuEduOaService.getInstance().createTask(instance.getBusinessTaskId(), + instance.getCreateLoginCode(), + instance.getTitle(), + instance.getSubTitle(), + instance.getUrl(), + instance.getDoneUrl(), + businessTypeEnum.getProcessNodeId(), + instance.getProcessName(), + participantUserCodes); + Integer resultCode = result.getResultCode(); + if(resultCode.equals(CommonConstants.ZERO)){ + Object instanceTaskId = result.getResult().getData(); + this.updateInstanceStatus(instance.getId(), OaStatusEnum.AUDITING, String.valueOf(instanceTaskId)); + instanceUserService.updateStatusByInstanceId(instance.getId(), OaStatusEnum.AUDITING); + } else { + String errorMsg = result.getErrorMsg(); + throw new RuntimeException(errorMsg); + } + } +} diff --git a/src/main/java/io/v/nutz/oa/service/impl/OaInstanceUserServiceImpl.java b/src/main/java/io/v/nutz/oa/service/impl/OaInstanceUserServiceImpl.java new file mode 100644 index 0000000..a3c3aa0 --- /dev/null +++ b/src/main/java/io/v/nutz/oa/service/impl/OaInstanceUserServiceImpl.java @@ -0,0 +1,126 @@ +package io.v.nutz.oa.service.impl; + +import cn.hutool.core.date.DateUtil; +import io.v.nutz.base.service.impl.BaseServiceImpl; +import io.v.nutz.oa.HhuEduOaService; +import io.v.nutz.oa.enums.OaStatusEnum; +import io.v.nutz.oa.model.OaInstanceUser; +import io.v.nutz.oa.service.IOaInstanceUserService; +import io.v.nutz.sys.models.Sys_user; +import io.v.nutz.sys.services.SysUserService; +import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.util.NutMap; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +@IocBean(args = {"refer:dao"}) +public class OaInstanceUserServiceImpl extends BaseServiceImpl implements IOaInstanceUserService { + + @Inject + private SysUserService sysUserService; + + public OaInstanceUserServiceImpl(Dao dao) { + super(dao); + } + + @Override + public OaInstanceUser getByUserId(String instanceId, String userId) { + Sql sql = Sqls.create("select * from oa_instance_user where user_id =@user_id and instance_id=@instance_id limit 0,1"); + sql.params().set("user_id", userId); + sql.params().set("instance_id", instanceId); + sql.setCallback(Sqls.callback.map()); + this.dao().execute(sql); + return sql.getObject(OaInstanceUser.class); + } + + @Override + public List getAuditing(String instanceId) { + Sql sql = Sqls.create("select * from oa_instance_user where instance_id =@instance_id and status=1"); + sql.params().set("instance_id", instanceId); + sql.setCallback(Sqls.callback.records()); + this.dao().execute(sql); + return sql.getList(OaInstanceUser.class); + } + + @Override + public List getInstanceUser(String instanceId) { + Sql sql = Sqls.create("select * from oa_instance_user where instance_id =@instance_id"); + sql.params().set("instance_id", instanceId); + sql.setCallback(Sqls.callback.maps()); + this.dao().execute(sql); + return sql.getList(NutMap.class); + } + + @Override + public void createRecord(String instanceId, List userIds) { + this.createRecord(instanceId, userIds, OaStatusEnum.NO_AUDIT); + } + + @Override + public void createRecord(String instanceId, List userIds, OaStatusEnum statusEnum) { + if(userIds==null || userIds.isEmpty()){ + throw new RuntimeException("缺少参与审批人"); + } + List instanceUsers = new ArrayList<>(); + for(String userId : userIds) { + Sys_user sys_user = sysUserService.fetch(userId); + OaInstanceUser instanceUser = new OaInstanceUser(); + instanceUser.setInstanceId(instanceId); + instanceUser.setUserId(sys_user.getId()); + instanceUser.setUserName(sys_user.getUsername()); + instanceUser.setUserLoginCode(sys_user.getLoginname()); + instanceUser.setCreateTime(DateUtil.date()); + instanceUser.setStatus(statusEnum.getCode()); + instanceUsers.add(instanceUser); + } + this.insert(instanceUsers); + } + + @Override + public void updateStatus(String id, OaStatusEnum oaStatusEnum, String statusReason) { + Sql sql = Sqls.create("update oa_instance_user set status=@status, over_time=@over_time, status_reason=@status_reason where id=@id"); + sql.params().set("status", oaStatusEnum.getCode()); + sql.params().set("over_time", DateUtil.date()); + sql.params().set("status_reason", statusReason); + sql.params().set("id", id); + this.dao().execute(sql); + } + + @Override + public void updateStatusByInstanceId(String instanceId, OaStatusEnum oaStatusEnum) { + Sql sql = Sqls.create("update oa_instance_user set status=@status where instance_id=@instance_id"); + sql.params().set("status", oaStatusEnum.getCode()); + sql.params().set("instance_id", instanceId); + this.dao().execute(sql); + } + + @Override + public void appendAuditUser(String instanceId, String businessTaskId, List auditUsers) { + try { + List instanceUsers = this.getInstanceUser(instanceId); + List userIds = instanceUsers.stream().map(item -> { + return item.getString("user_id"); + }).collect(Collectors.toList()); + List addUser = auditUsers.stream().filter(item -> !userIds.contains(item)).collect(Collectors.toList()); + + this.createRecord(instanceId, addUser, OaStatusEnum.AUDITING); + + Sql userSql = Sqls.create("select * from sys_user where id in (@userIds)"); + userSql.params().set("userIds", addUser); + userSql.setCallback(Sqls.callback.maps()); + sysUserService.dao().execute(userSql); + List addSysUsers = userSql.getList(NutMap.class); + List loginNames = addSysUsers.stream().map(item -> item.getString("loginname")).collect(Collectors.toList()); + HhuEduOaService.getInstance().addPartipantsTask(businessTaskId, loginNames); + }catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException(e.getMessage()); + } + } +} diff --git a/src/main/java/io/v/nutz/oa/util/BillNoUtil.java b/src/main/java/io/v/nutz/oa/util/BillNoUtil.java new file mode 100644 index 0000000..852d06f --- /dev/null +++ b/src/main/java/io/v/nutz/oa/util/BillNoUtil.java @@ -0,0 +1,20 @@ +package io.v.nutz.oa.util; + +import cn.hutool.core.date.DateUtil; + +import java.util.Random; + +public class BillNoUtil { + + public static String getBusinessTaskId() { + StringBuilder str = new StringBuilder(); + str.append(DateUtil.format(DateUtil.date(), "yyyyMMdd")); + str.append("-"); + str.append(DateUtil.format(DateUtil.date(), "HHmmss")); + Random random = new Random(); + // 生成一个10以内的随机数(包含0,但不包含10) + int randomNumber = random.nextInt(10); + str.append("-" + randomNumber); + return str.toString(); + } +} diff --git a/src/main/java/io/v/nutz/oa/util/MyHttpDelete.java b/src/main/java/io/v/nutz/oa/util/MyHttpDelete.java new file mode 100644 index 0000000..42c89b2 --- /dev/null +++ b/src/main/java/io/v/nutz/oa/util/MyHttpDelete.java @@ -0,0 +1,24 @@ +package io.v.nutz.oa.util; + +import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; + +import java.net.URI; + +public class MyHttpDelete extends HttpEntityEnclosingRequestBase { + public static final String METHOD_NAME = "DELETE"; + @Override + public String getMethod() { + return METHOD_NAME; + } + public MyHttpDelete(final String uri) { + super(); + setURI(URI.create(uri)); + } + public MyHttpDelete(final URI uri) { + super(); + setURI(uri); + } + public MyHttpDelete() { + super(); + } +} diff --git a/src/main/java/io/v/nutz/oa/util/StringUtil.java b/src/main/java/io/v/nutz/oa/util/StringUtil.java new file mode 100644 index 0000000..2e76d4a --- /dev/null +++ b/src/main/java/io/v/nutz/oa/util/StringUtil.java @@ -0,0 +1,10 @@ +package io.v.nutz.oa.util; + +/** + * 字符串工具类 + */ +public class StringUtil { + public static boolean isEmpty(String string) { + return string == null || string.length() == 0 || string.trim().equals(""); + } +} diff --git a/src/main/java/io/v/nutz/oa/util/SudySignUtil.java b/src/main/java/io/v/nutz/oa/util/SudySignUtil.java new file mode 100644 index 0000000..f6be480 --- /dev/null +++ b/src/main/java/io/v/nutz/oa/util/SudySignUtil.java @@ -0,0 +1,222 @@ +package io.v.nutz.oa.util; + +import org.apache.commons.codec.binary.Hex; + +import java.nio.charset.Charset; +import java.security.MessageDigest; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +/** + * 对外开放签名算法工具类 + * @author xhmeng + */ +public class SudySignUtil { + /** + * 签名算法类型sha1 + */ + public static final String ALGORITHM_SHA1 = "SHA1"; + /** + * 签名算法类型sha-256 + */ + public static final String ALGORITHM_SHA256 = "SHA-256"; + /** + * 签名算法类型MD5 + */ + public static final String ALGORITHM_MD5 = "MD5"; + /** + * 签名算法类型HMAC-SHA256 + */ + public static final String ALGORITHM_HMACSHA256= "HMAC-SHA256"; + + /** + * 支持的签名算法 + */ + private static final List allowedAlgorithms = new ArrayList<>(); + + static { + allowedAlgorithms.add(ALGORITHM_SHA1); + allowedAlgorithms.add(ALGORITHM_SHA256); + allowedAlgorithms.add(ALGORITHM_MD5); + allowedAlgorithms.add(ALGORITHM_HMACSHA256); + } + + + + /** + * 生成签名 + * @param algorithm 签名算法。SHA1,MD5,SHA-256,HMAC-SHA256 + * @param appId 应用标识,此标识是提前分配给调用系统的 + * @param timestamp 时间戳。长整数,是UNIX时间的毫秒数,即产生签名时的时间距1970年1月1日零时的毫秒数的十进制字符串。 + * 此时间戳代表了签名的时效性,如果此时间与当前时间差大于某个值(建议不超过20分钟)时,系统认为此签名已经失效 + * @param nonce 随机数。用于参与签名运算 + * @param summary 摘要,业务接口增加字段的hash值。参与签名,进一步签名的参数值如extraText=“loginName=0810035&userId=2”, + * 需要hash后传输,业务系统在校验sign的基础上进一步校验此值。hex(hash(extraText))后的内容, + * 其中hash算法根据摘要版本使用对应的算法(如sha1、md5、sha-256等)。 + * @param secretKey 平台分配给业务系统的私钥 + * @return + */ + public static String buildSign(String algorithm,String appId,String timestamp,String nonce,String summary,String secretKey) { + if(StringUtil.isEmpty(algorithm) || StringUtil.isEmpty(appId) + ||StringUtil.isEmpty(timestamp) + ||StringUtil.isEmpty(nonce)) { + throw new RuntimeException("Sign parameters not allow null!"); + } + if(!allowedAlgorithms.contains(algorithm)) { + throw new RuntimeException("UnSupport algorithm type!"); + } + StringBuilder sb = new StringBuilder(); + sb.append("sd-algorithm=").append(algorithm); + sb.append("&sd-appid=").append(appId); + sb.append("&sd-nonce=").append(nonce); + if(!StringUtil.isEmpty(summary)) { + sb.append("&sd-summary=").append(summary); + } + sb.append("&sd-timestamp=").append(timestamp); + sb.append("&key=").append(secretKey); + String stringSignTemp = sb.toString(); + System.out.println("stringSignTemp:" + stringSignTemp); + System.out.println(stringSignTemp); + //sign + if(algorithm.equals(ALGORITHM_HMACSHA256)) { + try { + return hmac(secretKey,stringSignTemp,"HmacSHA256"); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } else { + try { + return sha(stringSignTemp,algorithm); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + } + + /** + * 检查签名是否合法 + * @param algorithm 签名算法。SHA1,MD5,SHA-256,HMAC-SHA256 + * @param appId 应用标识,此标识是提前分配给调用系统的 + * @param timestamp 时间戳。长整数,是UNIX时间的毫秒数,即产生签名时的时间距1970年1月1日零时的毫秒数的十进制字符串。 + * 此时间戳代表了签名的时效性,如果此时间与当前时间差大于某个值(建议不超过20分钟)时,系统认为此签名已经失效 + * @param nonce 随机数。用于参与签名运算 + * @param summary 摘要,业务接口增加字段的hash值。参与签名,进一步签名的参数值如extraText=“loginName=0810035&userId=2”, + * 需要hash后传输,业务系统在校验sign的基础上进一步校验此值。hex(hash(extraText))后的内容, + * 其中hash算法根据摘要版本使用对应的算法(如sha1、md5、sha-256等)。 + * @param secretKey 平台分配给业务系统的私钥 + * @param sign 需要校验的签名 + * @param signInvalidTime 签名有效期 单位分钟 + * @return + */ + public static boolean checkSign(String algorithm,String appId,String timestamp,String nonce,String summary,String secretKey,String sign,long signInvalidTime) { + //检查签名时间是否过期 + long now = System.currentTimeMillis(); + long timesta = Long.parseLong(timestamp); + if((now-timesta)>signInvalidTime*60*1000) {//签名有效时间 默认20分钟 + throw new RuntimeException( "签名已失效!"); + } + String buildSign = buildSign(algorithm, appId, timestamp, nonce, summary, secretKey); + if(!StringUtil.isEmpty(buildSign) && !StringUtil.isEmpty(sign) && buildSign.equals(sign)) { + return true; + } + return false; + } + + + + /** + * 签名摘要 + * @param algorithm hash算法 SHA1,MD5,SHA-256 + * @param summaryText 摘要内容 + * @return + */ + public static String buildSummary(String algorithm,String summaryText) { + try { + return sha(summaryText,algorithm); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** + * 检查摘要签名 + * @param algorithm + * @param summaryText + * @param summarySign + * @return + */ + public static boolean checkSummary(String algorithm,String summaryText,String summarySign) { + String sign = buildSummary(algorithm, summaryText); + if(!StringUtil.isEmpty(sign) && !StringUtil.isEmpty(summarySign) && summarySign.equals(sign)) { + return true; + } + return false; + } + + + /** + * sha + * @param text + * @param signType + * @return + * @throws Exception + */ + private static String sha(String text, String signType) throws Exception{ + MessageDigest sha = MessageDigest.getInstance(signType); + byte[] digest = sha.digest(text.getBytes("UTF-8")); + return Hex.encodeHexString(digest).toUpperCase(); + } + + /** + * hmac + * @param accessSecret + * @param stringToSign + * @param singType + * @return + * @throws Exception + */ + private static String hmac(String accessSecret,String stringToSign,String singType) throws Exception{ + javax.crypto.Mac mac = javax.crypto.Mac.getInstance(singType); + mac.init(new javax.crypto.spec.SecretKeySpec(accessSecret.getBytes("UTF-8"), singType)); + byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8")); + return Hex.encodeHexString(signData).toUpperCase(); + } + +// public static void main(String[] args) { +// String appId = "xgxt"; +// String algorithm= "SHA1"; +// String timestamp= System.currentTimeMillis() +""; +// String nonce= "ibuaiVcKdpRxkhJA"; +// String summary= "loginName=zhangsan"; +// String buildSummary = buildSummary(ALGORITHM_SHA1, summary); +// String key = "49123c3d-0d98-4ef5-8128-bdc5f98b3fbd"; +// String sign = buildSign(algorithm,appId,timestamp,nonce,buildSummary,key); +// System.out.println(checkSign(algorithm,appId,timestamp,nonce,buildSummary,key,sign,20)); +// } + + public static String buildSignature(String securyKey, String timestamp, String openId, String nonce) throws Exception { + List sParamList = new ArrayList(); + sParamList.add(securyKey); + sParamList.add(timestamp); + sParamList.add(nonce); + sParamList.add(openId); + Collections.sort(sParamList, new Comparator() { + @Override + public int compare(String o1, String o2) { + return o1.compareTo(o2); + } + }); + StringBuilder signature = new StringBuilder(); + for (String sParam : sParamList) { + signature.append(sParam); + } + MessageDigest md = MessageDigest.getInstance("SHA-1"); + md.update(signature.toString().getBytes(Charset.forName("UTF-8"))); + return Hex.encodeHexString(md.digest()); + } +} diff --git a/src/main/java/io/v/nutz/oa/util/Util.java b/src/main/java/io/v/nutz/oa/util/Util.java new file mode 100644 index 0000000..6bce9e5 --- /dev/null +++ b/src/main/java/io/v/nutz/oa/util/Util.java @@ -0,0 +1,91 @@ +package io.v.nutz.oa.util; + +import java.security.MessageDigest; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +/** + * 工具类 + */ +public class Util { + /** + * 解析签名人员 + * @param appCode + * @param secret + * @param timestamp + * @param nonce + * @return + * @throws Exception + */ + public static String buildSignuate(String appCode, String secret, String timestamp, String nonce) throws Exception{ + if (appCode == null) { + throw new Exception( "appCode!"); + } + if (timestamp==null) { + throw new Exception( "timestamp解析为空!"); + } + if (nonce == null) { + throw new Exception( "nonce解析为空!"); + } + if (secret == null) { + throw new Exception( "私钥错误!"); + } + return buildSignature(secret, timestamp, appCode, nonce); + } + + + public static String buildSignature(String securyKey, String timestamp, String openId, String nonce) throws Exception { + List sParamList = new ArrayList(); + sParamList.add(securyKey); + sParamList.add(timestamp); + sParamList.add(nonce); + sParamList.add(openId); + Collections.sort(sParamList, new Comparator() { + @Override + public int compare(String o1, String o2) { + return o1.compareTo(o2); + } + }); + StringBuilder signature = new StringBuilder(); + for (String sParam : sParamList) { + signature.append(sParam); + } + System.out.println("signature:"+signature); + MessageDigest md = MessageDigest.getInstance("SHA-1"); + md.update(signature.toString().getBytes()); + byte[] bytes = md.digest(); +// System.out.println(toHex(bytes)); +// System.out.println(bytesToHexStr(bytes)); + return toHex(bytes); + } + + private static String toHex(byte[] buffer) { + StringBuilder sb = new StringBuilder(buffer.length * 2); + for (int i = 0; i < buffer.length; i++) { + sb.append(Character.forDigit((buffer[i] & 240) >> 4, 16)); + sb.append(Character.forDigit(buffer[i] & 15, 16)); + } + return sb.toString(); + } + + private static String bytesToHexStr(byte[] bytes){ + if(bytes == null){ + return null; + } + StringBuffer sb = new StringBuffer(); + StringBuffer sb2 = new StringBuffer(); + String strInt = ""; + for(int i=0;i sysUsers = userSql.getList(NutMap.class); + if(sysUsers == null || sysUsers.size() <= 0) { + return; + } + List userIds = sysUsers.stream().map(item-> { return item.getString("id"); }).collect(Collectors.toList()); + auditInstanceService.createTask(OaBusinessTypeEnum.PROPOSAL_COMMITTEE_AUDIT, + info.getId(), + title, + subTitle, + createUser.getId(), + userIds, + Globals.AppDomain + "/platform/proposal/transact/case/case?proposalId=" + info.getId(), + Globals.AppDomain + "/platform/proposal/transact/case/case"); + } + }catch (Exception e) { + e.printStackTrace(); + } }); } }, @@ -481,6 +520,7 @@ public enum ProposalAuditEnum { public ViService proposalSecondedService = ViResource.ioc.get(ViServiceImpl.class, "ProposalSeconded"); public ViService proposalFeedbackService = ViResource.ioc.get(ViServiceImpl.class, "ProposalFeedback"); public Dao dao = ViResource.dao; + public IOaAuditInstanceService auditInstanceService = ViResource.ioc.getByType(IOaAuditInstanceService.class); public abstract void audit(NutMap nutMap); diff --git a/src/main/java/io/v/nutz/proposal/controller/transact/CaseCheckController.java b/src/main/java/io/v/nutz/proposal/controller/transact/CaseCheckController.java index 37fd991..1fe704c 100644 --- a/src/main/java/io/v/nutz/proposal/controller/transact/CaseCheckController.java +++ b/src/main/java/io/v/nutz/proposal/controller/transact/CaseCheckController.java @@ -1,26 +1,39 @@ package io.v.nutz.proposal.controller.transact; import cn.hutool.core.util.StrUtil; +import cn.wizzer.framework.page.Pagination; import io.v.nutz.annontation.ViReturn; +import io.v.nutz.base.result.Result; import io.v.nutz.modules.models.PageForm; +import io.v.nutz.oa.enums.OaBusinessTypeEnum; +import io.v.nutz.oa.model.OaAuditInstance; +import io.v.nutz.oa.service.IOaAuditInstanceService; import io.v.nutz.proposal.models.ProposalAudit; import io.v.nutz.proposal.models.ProposalInfo; import io.v.nutz.proposal.models.ProposalSearch; import io.v.nutz.proposal.services.ProposalCaseCheckService; import io.v.nutz.proposal.services.ProposalCommonService; import io.v.nutz.sys.models.Sys_signature; +import io.v.nutz.sys.models.Sys_user; +import io.v.nutz.sys.services.SysUserService; +import io.v.nutz.util.ShiroUtil; +import io.v.nutz.web.commons.base.Globals; import org.apache.shiro.authz.annotation.RequiresAuthentication; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.nutz.dao.Chain; import org.nutz.dao.Cnd; import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.util.NutMap; import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.Ok; import org.nutz.mvc.annotation.POST; import org.nutz.mvc.annotation.Param; +import java.util.Arrays; import java.util.List; /** @@ -44,6 +57,12 @@ public class CaseCheckController { @Inject private ProposalCommonService proposalCommonService; + @Inject + private IOaAuditInstanceService auditInstanceService; + + @Inject + private SysUserService sysUserService; + @At("") @Ok("beetl:/platform/proposal/transact/caseCheck.html") @RequiresPermissions("proposal.transact.caseCheck") @@ -56,6 +75,57 @@ public class CaseCheckController { return proposalCaseCheckService.pageData(page, search); } + @Ok("json") + @At("/detail") + public Result detail(String proposalId) { + String sqlStr = """ + SELECT + info.*, + su.username, + su.loginname, + state.stateName, + state.stateColor, + type.typeCode, + type.typeName, + jdh.jdhallname meetingName, + dbt.`code` delegationCode, + dbt.dbtname delegationName, + manner.`name` mannerName, + result.`name` resultName, + CONCAT('主办(',zbpu.unitName,'),','协办(',IF(ISNULL(xbpu.unitName),'无',xbpu.unitName) ,')') AS underTakeNames, + ( + SELECT + count( 1 ) > 0 + FROM + proposal_conjoin + where JSON_CONTAINS (proposalIds,JSON_QUOTE(info.id)) + ) AS isConjoin, + lalevel.`name` laLevelName + FROM + proposal_info info + LEFT JOIN `user` su ON su.id = info.createUser + LEFT JOIN proposal_state state ON state.stateCode = info.stateCode + LEFT JOIN proposal_type type ON type.id = info.typeId + LEFT JOIN jdh_jdhxx jdh ON jdh.id = info.teacherMeetingId + LEFT JOIN jdh_dbt dbt ON dbt.id = info.delegationId + LEFT JOIN sys_dict manner ON manner.`code` = info.mannerCode + LEFT JOIN sys_dict result ON result.`code` = info.resultCode + LEFT JOIN sys_dict lalevel ON lalevel.`code` = info.determineTypeCode + LEFT JOIN proposal_reply zbpr ON zbpr.proposalId = info.id + AND zbpr.undertakeType = 1 + LEFT JOIN proposal_undertake zbpu ON zbpu.id = zbpr.replyUnitId + LEFT JOIN proposal_reply xbpr ON xbpr.proposalId = info.id + AND xbpr.undertakeType = 2 + LEFT JOIN proposal_undertake xbpu ON xbpu.id = xbpr.replyUnitId + where info.id=@proposalId + """; + Sql sql = Sqls.create(sqlStr); + sql.params().set("proposalId", proposalId); + sql.setCallback(Sqls.callback.map()); + dao.execute(sql); + return Result.success(sql.getObject(NutMap.class)); + } + /** * * @param audit @@ -83,8 +153,87 @@ public class CaseCheckController { proposalCaseCheckService.audit(conjoinIdList, audit, caseCheckNeedSecondReply, caseCheckNeedSecondAudit); - return null; + // 处理提案委确认承办审核待办 + try { + OaAuditInstance oaInstance = auditInstanceService.getByUser(OaBusinessTypeEnum.DIRECTOR_CONFIRM_ORGANIZER_REPLY, io.v.nutz.web.commons.utils.ShiroUtil.getUserId()); + if (oaInstance != null) { + auditInstanceService.agree(oaInstance.getId(), io.v.nutz.web.commons.utils.ShiroUtil.getUserId(), "审核通过"); + } + // 是否还有审核信息 + ProposalSearch search = new ProposalSearch(); + search.setIsAudit("false"); + search.setMeetingId("tq19v68n3milip0rhuml8b1euk"); + PageForm page = new PageForm(); + page.setSearchName("proposalName"); + page.setPageNumber(1); + page.setPageSize(10); + cn.wizzer.framework.base.Result result = (cn.wizzer.framework.base.Result) this.pageData(page, search); + Pagination pagination = (Pagination) result.getData(); + if(pagination == null || pagination.getList() == null || pagination.getList().size() <= 0) { + // 处理全部未审核任务 + List auditInstances = auditInstanceService.getByBusinessTypeRunning(OaBusinessTypeEnum.DIRECTOR_CONFIRM_ORGANIZER_REPLY); + for(OaAuditInstance auditInstance : auditInstances) { + auditInstanceService.agree(auditInstance.getId(), "审核通过"); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + + // 待办任务处理 + try{ + OaAuditInstance instance = auditInstanceService.getByUser(OaBusinessTypeEnum.PROPOSAL_COMMITTEE_AUDIT, audit.getProposalId(), ShiroUtil.getUserId()); + ProposalInfo proposalInfo = dao.fetch(ProposalInfo.class, audit.getProposalId()); + Sys_user createUser = dao.fetch(Sys_user.class, proposalInfo.getCreateUser()); + if(caseCheckNeedSecondReply) { + if(instance != null) { + auditInstanceService.refuse(instance.getId(), ShiroUtil.getUserId(), "分管校领导驳回"); + } + + // 生成主办单位待办任务 + String title = "主办单位提案答复-" + proposalInfo.getProposalName() + "(" + proposalInfo.getProposalCode() +"[" + createUser.getUsername() + "]" + ")"; + String subTitle = "主办单位提案办理答复"; + // 主办单位校领导 + Sql hostSql = Sqls.create("select oiu.user_id " + + " from oa_instance_user oiu left join oa_audit_instance oai on oai.id = oiu.instance_id" + + " where oai.business_type=@business_type and oai.business_id=@business_id " + + " order by oai.create_time desc limit 0,1"); + hostSql.params().set("business_type", OaBusinessTypeEnum.HOST_ORGANIZER_REPLY_HANDLE.getCode()); + hostSql.params().set("business_id", proposalInfo.getId()); + hostSql.setCallback(Sqls.callback.map()); + dao.execute(hostSql); + NutMap hostNutMap = hostSql.getObject(NutMap.class); + auditInstanceService.createTask(OaBusinessTypeEnum.HOST_ORGANIZER_REPLY_HANDLE, + proposalInfo.getId(), + title, + subTitle, + createUser.getId(), + Arrays.asList(hostNutMap.getString("user_id")), + Globals.AppDomain + "/platform/proposal/transact/reply?underTakeType=1&proposalId=" + proposalInfo.getId(), + Globals.AppDomain + "/platform/proposal/transact/reply"); + } else { + if(instance != null) { + auditInstanceService.agree(instance.getId(), ShiroUtil.getUserId(), "分管校领导同意", true); + } + + if(proposalInfo.getStateCode().equals(Integer.valueOf(700))) { + String title = "提案评价-" + proposalInfo.getProposalName() + "(" + proposalInfo.getProposalCode() + "[" + createUser.getUsername() + "]" + ")"; + String subTitle = "提案落实结束评价"; + auditInstanceService.createTask(OaBusinessTypeEnum.PROPOSAL_FEEDBACK_EVALUATE_AUDIT, + proposalInfo.getId(), + title, + subTitle, + ShiroUtil.getUserId(), + Arrays.asList(createUser.getId()), + Globals.AppDomain + "/platform/proposal/transact/feedback?proposalId=" + proposalInfo.getId(), + Globals.AppDomain + "/platform/proposal/transact/feedback"); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return null; } @At diff --git a/src/main/java/io/v/nutz/proposal/controller/transact/CaseController.java b/src/main/java/io/v/nutz/proposal/controller/transact/CaseController.java index a9c85f9..b4118b1 100644 --- a/src/main/java/io/v/nutz/proposal/controller/transact/CaseController.java +++ b/src/main/java/io/v/nutz/proposal/controller/transact/CaseController.java @@ -2,17 +2,25 @@ package io.v.nutz.proposal.controller.transact; import cn.hutool.core.util.StrUtil; import cn.wizzer.framework.base.Result; +import cn.wizzer.framework.page.Pagination; import com.deepoove.poi.XWPFTemplate; import com.deepoove.poi.config.Configure; import com.deepoove.poi.policy.HackLoopTableRenderPolicy; import io.v.nutz.annontation.ViReturn; +import io.v.nutz.base.utils.Roles; import io.v.nutz.modules.models.PageForm; +import io.v.nutz.oa.enums.OaBusinessTypeEnum; +import io.v.nutz.oa.model.OaAuditInstance; +import io.v.nutz.oa.service.IOaAuditInstanceService; import io.v.nutz.proposal.models.ProposalAudit; import io.v.nutz.proposal.models.ProposalSearch; import io.v.nutz.proposal.services.ProposalAuditService; import io.v.nutz.proposal.services.ProposalCaseService; import io.v.nutz.proposal.services.ProposalInfoService; import io.v.nutz.sys.models.Sys_signature; +import io.v.nutz.sys.models.Sys_user; +import io.v.nutz.util.ShiroUtil; +import io.v.nutz.web.commons.base.Globals; import org.apache.shiro.authz.annotation.RequiresAuthentication; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.nutz.aop.interceptor.ioc.TransAop; @@ -33,6 +41,8 @@ import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; /** * @author: zzxxyy @@ -58,6 +68,9 @@ public class CaseController { @Inject private Dao dao; + @Inject + private IOaAuditInstanceService auditInstanceService; + @At("") @Ok("beetl:/platform/proposal/transact/case.html") @RequiresPermissions("proposal.transact.case") @@ -116,6 +129,12 @@ public class CaseController { // return proposalInfoService.listPageMap(page.getPageNumber(), page.getPageSize(), sql); } + @Ok("json") + @At("/detail") + public Result detail(String id) { + return Result.success(proposalCaseService.detail(id)); + } + @At @Ok("void") public void doExport(String proposalId, HttpServletResponse response) throws IOException { @@ -247,7 +266,35 @@ public class CaseController { } audit.setFlag(flag == 1); proposalCaseService.audit(Arrays.asList(proposalIds), resultCode, determineTypeCode, hostUnit, Arrays.asList(helpUnit), typeId, audit, auditType, flag); - return null; + + // 代办任务审核 + try{ + for(String proposalId: proposalIds) { + OaAuditInstance instance = auditInstanceService.getByUser(OaBusinessTypeEnum.PROPOSAL_COMMITTEE_AUDIT, proposalId, ShiroUtil.getUserId()); + if(instance == null) continue; + if(flag == 1) { + auditInstanceService.agree(instance.getId(), ShiroUtil.getUserId(), "同意立案", true); + } else { + auditInstanceService.refuse(instance.getId(), ShiroUtil.getUserId(), "拒绝立案"); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + + // 查看 + ProposalSearch search = new ProposalSearch(); + search.setIsAudit("false"); + search.setMeetingId("tq19v68n3milip0rhuml8b1euk"); + PageForm page = new PageForm(); + page.setSearchName("proposalName"); + page.setPageNumber(1); + page.setPageSize(10); + Pagination pagination = proposalCaseService.pageData(page, search); + if(pagination == null || pagination.getList() == null || pagination.getList().size() <= 0) { + return Result.success(Map.of("sendTask", true)); + } + return Result.success(Map.of("sendTask", false)); } /** @@ -309,4 +356,45 @@ public class CaseController { return proposalCaseService.backShow(proposalId); } + @At("/sendToDoTaskInfo") + @Ok("json") + public Result sendToDoTaskInfo() { + try { + // 获取审核用户信息 角色 + Sql userSql = Sqls.create("select su.* from sys_user su left join sys_user_role sur on su.id = sur.userid" + + " where sur.roleId in (@roleId)"); + userSql.params().set("roleId", Arrays.asList(Roles.WYH_ZR)); + userSql.setCallback(Sqls.callback.maps()); + dao.execute(userSql); + List sysUsers = userSql.getList(NutMap.class); + if (sysUsers == null || sysUsers.size() <= 0) { + return null; + } + + List auditUsers = sysUsers.stream().map(item-> { return item.getString("id"); }).collect(Collectors.toList()); + + for(String auditUserId : auditUsers) { + + OaAuditInstance oaInstance = auditInstanceService.getByUser(OaBusinessTypeEnum.DIRECTOR_EXECUTIVE_COMMITTEE, auditUserId); + if(oaInstance != null) continue; + + // 团长生成待办任务 + Sys_user createUser = dao.fetch(Sys_user.class, ShiroUtil.getUserId()); + String title = "提案审核-执委会审核"; + String subTitle = createUser.getUsername() + "邀请您提案审核"; + auditInstanceService.createTask(OaBusinessTypeEnum.DIRECTOR_EXECUTIVE_COMMITTEE, + createUser.getId(), + title, + subTitle, + createUser.getId(), + Arrays.asList(auditUserId), + Globals.AppDomain + "/platform/proposal/transact/executorRead", + Globals.AppDomain + "/platform/proposal/transact/executorRead"); + } + } catch (Exception e) { + e.printStackTrace(); + return Result.error(e.getMessage()); + } + return Result.success("已为你发送待办到下一审批节点"); + } } diff --git a/src/main/java/io/v/nutz/proposal/controller/transact/CaseUnitController.java b/src/main/java/io/v/nutz/proposal/controller/transact/CaseUnitController.java index 7c7a0ae..af8a75f 100644 --- a/src/main/java/io/v/nutz/proposal/controller/transact/CaseUnitController.java +++ b/src/main/java/io/v/nutz/proposal/controller/transact/CaseUnitController.java @@ -2,22 +2,34 @@ package io.v.nutz.proposal.controller.transact; import cn.hutool.core.util.StrUtil; import cn.wizzer.framework.base.Result; +import cn.wizzer.framework.page.Pagination; import io.v.nutz.annontation.ViReturn; import io.v.nutz.base.utils.Roles; import io.v.nutz.modules.models.PageForm; +import io.v.nutz.oa.enums.OaBusinessTypeEnum; +import io.v.nutz.oa.model.OaAuditInstance; +import io.v.nutz.oa.service.IOaAuditInstanceService; import io.v.nutz.proposal.models.ProposalAudit; +import io.v.nutz.proposal.models.ProposalInfo; import io.v.nutz.proposal.models.ProposalReply; import io.v.nutz.proposal.models.ProposalSearch; import io.v.nutz.proposal.services.ProposalCaseConfirmService; import io.v.nutz.proposal.services.ProposalCommonService; import io.v.nutz.proposal.services.ProposalInfoService; import io.v.nutz.sys.models.Sys_signature; +import io.v.nutz.sys.models.Sys_user; import io.v.nutz.sys.models.Sys_user_role; +import io.v.nutz.sys.services.SysUserService; +import io.v.nutz.web.commons.base.Globals; +import io.v.nutz.web.commons.utils.ShiroUtil; import org.apache.shiro.authz.annotation.RequiresAuthentication; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.nutz.dao.Cnd; import org.nutz.dao.Dao; import org.nutz.dao.FieldFilter; +import org.nutz.dao.Sqls; +import org.nutz.dao.entity.Record; +import org.nutz.dao.sql.Sql; import org.nutz.dao.util.Daos; import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.IocBean; @@ -29,6 +41,7 @@ import org.nutz.mvc.annotation.Param; import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; /** * @author: Aaron @@ -54,6 +67,12 @@ public class CaseUnitController { @Inject private ProposalCommonService proposalCommonService; + @Inject + private SysUserService sysUserService; + + @Inject + private IOaAuditInstanceService auditInstanceService; + @At("") @Ok("beetl:/platform/proposal/transact/caseUnit.html") @RequiresPermissions("proposal.transact.caseUnit") @@ -86,9 +105,93 @@ public class CaseUnitController { audit.setSignId(signId); } proposalCaseConfirmService.audit(Arrays.asList(proposalIds), resultCode, determineTypeCode, hostUnit, Arrays.asList(helpUnit), typeId, audit); + + // 处理提案委确认承办审核待办 + try { + OaAuditInstance oaInstance = auditInstanceService.getByUser(OaBusinessTypeEnum.DIRECTOR_CONFIRM_ORGANIZER_REPLY, ShiroUtil.getUserId()); + if (oaInstance != null) { + + auditInstanceService.agree(oaInstance.getId(), ShiroUtil.getUserId(), "审核通过"); + } + // 是否还有审核信息 + ProposalSearch search = new ProposalSearch(); + search.setIsAudit("false"); + search.setMeetingId("tq19v68n3milip0rhuml8b1euk"); + PageForm page = new PageForm(); + page.setSearchName("proposalName"); + page.setPageNumber(1); + page.setPageSize(10); + Result result = (Result) this.pageData(page, search); + Pagination pagination = (Pagination) result.getData(); + if(pagination == null || pagination.getList() == null || pagination.getList().size() <= 0) { + // 处理全部未审核任务 + List auditInstances = auditInstanceService.getByBusinessTypeRunning(OaBusinessTypeEnum.DIRECTOR_CONFIRM_ORGANIZER_REPLY); + for(OaAuditInstance auditInstance : auditInstances) { + auditInstanceService.agree(auditInstance.getId(), "审核通过"); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + + // 生成待办任务 + try{ + for(String proposalId : Arrays.asList(proposalIds)) { + ProposalInfo proposalInfo = proposalInfoService.fetch(proposalId); + Sys_user createUser = dao.fetch(Sys_user.class, proposalInfo.getCreateUser()); + + // 主办单位校领导 + List hostRecords = this.findAdmin(Arrays.asList(hostUnit)); + if (hostRecords != null && hostRecords.size() > 0) { + List hostUserIds = hostRecords.stream().map(item-> {return item.getString("id"); }).collect(Collectors.toList()); + String title = "主办单位提案答复-" + proposalInfo.getProposalName() + "(" + proposalInfo.getProposalCode() +"[" + createUser.getUsername() + "]" + ")"; + String subTitle = "主办单位提案办理答复"; + auditInstanceService.createTask(OaBusinessTypeEnum.HOST_ORGANIZER_REPLY_HANDLE, + proposalId, + title, + subTitle, + createUser.getId(), + hostUserIds, + Globals.AppDomain + "/platform/proposal/transact/reply?underTakeType=1&proposalId=" + proposalInfo.getId(), + Globals.AppDomain + "/platform/proposal/transact/reply"); + } + + // 协办单位校领导 + List helpRecords = this.findAdmin(Arrays.asList(helpUnit)); + if (helpRecords != null && helpRecords.size() > 0) { + List helpUserIds = helpRecords.stream().map(item-> {return item.getString("id"); }).collect(Collectors.toList()); + String title = "协办单位提案答复-" + proposalInfo.getProposalName() + "(" + proposalInfo.getProposalCode() +"[" + createUser.getUsername() + "]" + ")"; + String subTitle = "协办单位提案办理答复"; + auditInstanceService.createTask(OaBusinessTypeEnum.HELP_ORGANIZER_REPLY_HANDLE, + proposalId, + title, + subTitle, + createUser.getId(), + helpUserIds, + Globals.AppDomain + "/platform/proposal/transact/reply?underTakeType=0&proposalId=" + proposalInfo.getId(), + Globals.AppDomain + "/platform/proposal/transact/reply"); + } + } + }catch (Exception e) { + e.printStackTrace(); + } return null; } + /** + * 查询负责人或者分管校领导 + * @param ids 承办单位id + * @return + */ + private List findAdmin(List ids) { + Sql sql = Sqls.create("select su.* " + + "from sys_user su left join sys_user_role sur on sur.userId = su.id" + + " where sur.cbdwid in (@cbdwid) and sur.roleId=@roleId"); + sql.params().set("cbdwid", ids); + sql.params().set("roleId", Roles.IN_CHARGE_LEADER); + return sysUserService.list(sql); + } + /** * 撤回 * diff --git a/src/main/java/io/v/nutz/proposal/controller/transact/ComposeController.java b/src/main/java/io/v/nutz/proposal/controller/transact/ComposeController.java index 96b7256..e5b56d9 100644 --- a/src/main/java/io/v/nutz/proposal/controller/transact/ComposeController.java +++ b/src/main/java/io/v/nutz/proposal/controller/transact/ComposeController.java @@ -9,6 +9,8 @@ import io.v.nutz.base.utils.MsgApi; import io.v.nutz.base.utils.Roles; import io.v.nutz.dao.CndPlus; import io.v.nutz.modules.models.PageForm; +import io.v.nutz.oa.enums.OaBusinessTypeEnum; +import io.v.nutz.oa.service.IOaAuditInstanceService; import io.v.nutz.proposal.constants.ProposalMannerEnum; import io.v.nutz.proposal.constants.ProposalState; import io.v.nutz.proposal.constants.ProposalStateDirectionEnum; @@ -24,6 +26,8 @@ import io.v.nutz.sys.models.Sys_user; import io.v.nutz.sys.services.SysSignatureService; import io.v.nutz.sys.services.SysUserService; import io.v.nutz.util.ShiroUtil; +import io.v.nutz.web.commons.base.Globals; +import lombok.extern.slf4j.Slf4j; import org.apache.shiro.authz.annotation.RequiresAuthentication; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.nutz.aop.interceptor.ioc.TransAop; @@ -46,6 +50,7 @@ import org.nutz.mvc.upload.UploadAdaptor; import org.nutz.trans.Trans; import java.io.IOException; +import java.util.Arrays; import java.util.List; import java.util.concurrent.atomic.AtomicReference; @@ -55,6 +60,7 @@ import java.util.concurrent.atomic.AtomicReference; * @description: 撰写提案(系统管理员 、 提案管理员 、 正式代表 、 代表团团长 、 提案委员会主任) **/ +@Slf4j @At("/platform/proposal/transact/compose") @Ok("json:full") @IocBean @@ -88,6 +94,9 @@ public class ComposeController { @Inject private MsgApi msgApi; + @Inject + private IOaAuditInstanceService auditInstanceService; + @At("") @Ok("beetl:/platform/proposal/transact/compose.html") @RequiresPermissions("proposal.transact.compose") @@ -241,6 +250,23 @@ public class ComposeController { secondedService.insert(seconded); Sys_user user = dao.fetch(Sys_user.class, userId); msgApi.sendMsg(StrUtil.format(inviteSecondedTemplate, proposalCreateUser.getUsername(), proposalInfo.getProposalName()), List.of(user.getLoginname())); + + // 生成代办任务 + try { + Sys_user createUser = dao.fetch(Sys_user.class, ShiroUtil.getUserId()); + String title = "提案附议-" + proposalInfo.getProposalName() + "(" + proposalInfo.getProposalCode() +"[" + createUser.getUsername() + "]" + ")"; + String subTitle = createUser.getUsername() + "邀请您附议"; + auditInstanceService.createTask(OaBusinessTypeEnum.WRITE_PROPOSAL, + proposalId, + title, + subTitle, + createUser.getId(), + Arrays.asList(userId), + Globals.AppDomain + "/platform/proposal/transact/seconded?isAudit=false&proposalId=" + proposalInfo.getId(), + Globals.AppDomain + "/platform/proposal/statistics/mySearch"); + } catch (Exception e) { + log.error("撰写提案附议生成代办失败:{}", e.getMessage()); + } } return null; } diff --git a/src/main/java/io/v/nutz/proposal/controller/transact/ExecutorReadConfirmController.java b/src/main/java/io/v/nutz/proposal/controller/transact/ExecutorReadConfirmController.java index 36229ed..1604485 100644 --- a/src/main/java/io/v/nutz/proposal/controller/transact/ExecutorReadConfirmController.java +++ b/src/main/java/io/v/nutz/proposal/controller/transact/ExecutorReadConfirmController.java @@ -2,9 +2,14 @@ package io.v.nutz.proposal.controller.transact; import cn.hutool.core.util.StrUtil; import cn.wizzer.framework.base.Result; +import cn.wizzer.framework.page.Pagination; import io.v.nutz.annontation.ViReturn; +import io.v.nutz.base.utils.Roles; import io.v.nutz.dao.CndPlus; import io.v.nutz.modules.models.PageForm; +import io.v.nutz.oa.enums.OaBusinessTypeEnum; +import io.v.nutz.oa.model.OaAuditInstance; +import io.v.nutz.oa.service.IOaAuditInstanceService; import io.v.nutz.proposal.constants.ProposalState; import io.v.nutz.proposal.models.ProposalAudit; import io.v.nutz.proposal.models.ProposalSearch; @@ -13,9 +18,14 @@ import io.v.nutz.proposal.services.ProposalExecutorReadConfirmService; import io.v.nutz.proposal.services.ProposalInfoService; import io.v.nutz.proposal.services.ProposalProcessService; import io.v.nutz.sys.models.Sys_signature; +import io.v.nutz.sys.models.Sys_user; +import io.v.nutz.web.commons.base.Globals; +import io.v.nutz.web.commons.utils.ShiroUtil; import org.apache.shiro.authz.annotation.RequiresAuthentication; import org.nutz.aop.interceptor.ioc.TransAop; import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; import org.nutz.ioc.aop.Aop; import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.IocBean; @@ -27,6 +37,9 @@ import org.nutz.mvc.annotation.POST; import org.nutz.mvc.annotation.Param; import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; /** * @author zxy @@ -50,6 +63,9 @@ public class ExecutorReadConfirmController { @Inject private ProposalExecutorReadConfirmService proposalExecutorReadConfirmService; + @Inject + private IOaAuditInstanceService auditInstanceService; + @Inject private Dao dao; @@ -103,7 +119,36 @@ public class ExecutorReadConfirmController { .addv("determineCode", determineTypeCode); audit.setOther(Json.toJson(auditOther)); proposalExecutorReadConfirmService.audit(audit, Arrays.asList(proposalIds)); - return null; + // 处理代办任务 + try { + OaAuditInstance oaInstance = auditInstanceService.getByUser(OaBusinessTypeEnum.DIRECTOR_EXECUTIVE_CONFIRM_COMMITTEE, ShiroUtil.getUserId()); + if (oaInstance != null) { + auditInstanceService.agree(oaInstance.getId(), ShiroUtil.getUserId(), "审核通过"); + } + + // 是否还有审核信息 + ProposalSearch search = new ProposalSearch(); + search.setIsAudit("false"); + search.setMeetingId("tq19v68n3milip0rhuml8b1euk"); + PageForm page = new PageForm(); + page.setSearchName("proposalName"); + page.setPageNumber(1); + page.setPageSize(10); + Result result = (Result) this.pageData(page, search); + Pagination pagination = (Pagination) result.getData(); + if(pagination == null || pagination.getList() == null || pagination.getList().size() <= 0) { + + // 处理全部未审核任务 + List auditInstances = auditInstanceService.getByBusinessTypeRunning(OaBusinessTypeEnum.DIRECTOR_EXECUTIVE_CONFIRM_COMMITTEE); + for(OaAuditInstance auditInstance : auditInstances) { + auditInstanceService.agree(auditInstance.getId(), "审核通过"); + } + return Result.success(Map.of("sendTask", true)); + } + }catch (Exception e) { + e.printStackTrace(); + } + return Result.success(Map.of("sendTask", false)); } /** @@ -119,4 +164,45 @@ public class ExecutorReadConfirmController { proposalExecutorReadConfirmService.revoke(proposalId); return Result.success().addMsg("撤回成功!"); } + + @At("/sendToDoTaskInfo") + @Ok("json") + public Result sendToDoTaskInfo() { + try { + // 获取审核用户信息 角色 + Sql userSql = Sqls.create("select su.* from sys_user su left join sys_user_role sur on su.id = sur.userid" + + " where sur.roleId in (@roleId)"); + userSql.params().set("roleId", Arrays.asList(Roles.WYH_ZR)); + userSql.setCallback(Sqls.callback.maps()); + dao.execute(userSql); + List sysUsers = userSql.getList(NutMap.class); + if (sysUsers == null || sysUsers.size() <= 0) { + return null; + } + List auditUsers = sysUsers.stream().map(item -> { + return item.getString("id"); + }).collect(Collectors.toList()); + + for (String auditUserId : auditUsers) { + OaAuditInstance oaInstance = auditInstanceService.getByUser(OaBusinessTypeEnum.DIRECTOR_CONFIRM_ORGANIZER_REPLY, auditUserId); + if (oaInstance != null) continue; + + // 提案委确认承办单位 + Sys_user createUser = dao.fetch(Sys_user.class, ShiroUtil.getUserId()); + String title = "提案审核-提案委确认承办单位"; + String subTitle = createUser.getUsername() + "邀请您提案审核"; + auditInstanceService.createTask(OaBusinessTypeEnum.DIRECTOR_CONFIRM_ORGANIZER_REPLY, + createUser.getId(), + title, + subTitle, + createUser.getId(), + Arrays.asList(auditUserId), + Globals.AppDomain + "/platform/proposal/transact/caseUnit", + Globals.AppDomain + "/platform/proposal/transact/caseUnit"); + } + }catch (Exception e) { + return Result.error(e.getMessage()); + } + return Result.success("已为你发送待办到下一审批节点"); + } } diff --git a/src/main/java/io/v/nutz/proposal/controller/transact/ExecutorReadController.java b/src/main/java/io/v/nutz/proposal/controller/transact/ExecutorReadController.java index 601bde5..85a74dd 100644 --- a/src/main/java/io/v/nutz/proposal/controller/transact/ExecutorReadController.java +++ b/src/main/java/io/v/nutz/proposal/controller/transact/ExecutorReadController.java @@ -2,9 +2,14 @@ package io.v.nutz.proposal.controller.transact; import cn.hutool.core.util.StrUtil; import cn.wizzer.framework.base.Result; +import cn.wizzer.framework.page.Pagination; import io.v.nutz.annontation.ViReturn; +import io.v.nutz.base.utils.Roles; import io.v.nutz.dao.CndPlus; import io.v.nutz.modules.models.PageForm; +import io.v.nutz.oa.enums.OaBusinessTypeEnum; +import io.v.nutz.oa.model.OaAuditInstance; +import io.v.nutz.oa.service.IOaAuditInstanceService; import io.v.nutz.proposal.constants.ProposalState; import io.v.nutz.proposal.models.ProposalAudit; import io.v.nutz.proposal.models.ProposalSearch; @@ -13,8 +18,13 @@ import io.v.nutz.proposal.services.ProposalExecutorReadService; import io.v.nutz.proposal.services.ProposalInfoService; import io.v.nutz.proposal.services.ProposalProcessService; import io.v.nutz.sys.models.Sys_signature; +import io.v.nutz.sys.models.Sys_user; +import io.v.nutz.util.ShiroUtil; +import io.v.nutz.web.commons.base.Globals; import org.nutz.aop.interceptor.ioc.TransAop; import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; import org.nutz.ioc.aop.Aop; import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.IocBean; @@ -26,6 +36,9 @@ import org.nutz.mvc.annotation.POST; import org.nutz.mvc.annotation.Param; import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; /** * @author zxy @@ -49,6 +62,9 @@ public class ExecutorReadController { @Inject private ProposalExecutorReadService proposalExecutorReadService; + @Inject + private IOaAuditInstanceService auditInstanceService; + @Inject private Dao dao; @@ -101,7 +117,37 @@ public class ExecutorReadController { .addv("determineCode", determineTypeCode); audit.setOther(Json.toJson(auditOther)); proposalExecutorReadService.audit(audit, Arrays.asList(proposalIds)); - return null; + + // 处理代办任务 + try{ + OaAuditInstance oaInstance = auditInstanceService.getByUser(OaBusinessTypeEnum.DIRECTOR_EXECUTIVE_COMMITTEE, ShiroUtil.getUserId()); + if(oaInstance != null) { + auditInstanceService.agree(oaInstance.getId(), ShiroUtil.getUserId(), "审核通过"); + } + + // 是否还有审核信息 + ProposalSearch search = new ProposalSearch(); + search.setIsAudit("false"); + search.setMeetingId("tq19v68n3milip0rhuml8b1euk"); + PageForm page = new PageForm(); + page.setSearchName("proposalName"); + page.setPageNumber(1); + page.setPageSize(10); + Result result = (Result) this.pageData(page, search); + Pagination pagination = (Pagination) result.getData(); + if(pagination == null || pagination.getList() == null || pagination.getList().size() <= 0) { + + // 处理全部未审核任务 + List auditInstances = auditInstanceService.getByBusinessTypeRunning(OaBusinessTypeEnum.DIRECTOR_EXECUTIVE_COMMITTEE); + for(OaAuditInstance auditInstance : auditInstances) { + auditInstanceService.agree(auditInstance.getId(), "审核通过"); + } + return Result.success(Map.of("sendTask", true)); + } + } catch (Exception e) { + e.printStackTrace(); + } + return Result.success(Map.of("sendTask", false)); } /** @@ -117,4 +163,47 @@ public class ExecutorReadController { proposalExecutorReadService.revoke(proposalId); return Result.success().addMsg("撤回成功!"); } + + @At("/sendToDoTaskInfo") + @Ok("json") + public Result sendToDoTaskInfo() { + try { + // 获取审核用户信息 角色 + Sql userSql = Sqls.create("select su.* from sys_user su left join sys_user_role sur on su.id = sur.userid" + + " where sur.roleId in (@roleId)"); + userSql.params().set("roleId", Arrays.asList(Roles.secretary, Roles.principal)); + userSql.setCallback(Sqls.callback.maps()); + dao.execute(userSql); + List sysUsers = userSql.getList(NutMap.class); + if (sysUsers == null || sysUsers.size() <= 0) { + return null; + } + + List auditUsers = sysUsers.stream().map(item -> { + return item.getString("id"); + }).collect(Collectors.toList()); + + for (String auditUserId : auditUsers) { + + OaAuditInstance oaInstance = auditInstanceService.getByUser(OaBusinessTypeEnum.PRINCIPAL_SECRETARY_AUDIT, auditUserId); + if (oaInstance != null) continue; + + // 执委会审核生成待办任务 + Sys_user createUser = dao.fetch(Sys_user.class, ShiroUtil.getUserId()); + String title = "提案审核-校长、书记审核"; + String subTitle = createUser.getUsername() + "邀请您提案审核"; + auditInstanceService.createTask(OaBusinessTypeEnum.PRINCIPAL_SECRETARY_AUDIT, + createUser.getId(), + title, + subTitle, + createUser.getId(), + Arrays.asList(auditUserId), + Globals.AppDomain + "/platform/proposal/transact/principalRead", + Globals.AppDomain + "/platform/proposal/transact/principalRead"); + } + }catch (Exception e) { + return Result.error(e.getMessage()); + } + return Result.success("已为你发送待办到下一审批节点"); + } } diff --git a/src/main/java/io/v/nutz/proposal/controller/transact/FeedbackScoreController.java b/src/main/java/io/v/nutz/proposal/controller/transact/FeedbackScoreController.java index b20bdc6..4a0eac2 100644 --- a/src/main/java/io/v/nutz/proposal/controller/transact/FeedbackScoreController.java +++ b/src/main/java/io/v/nutz/proposal/controller/transact/FeedbackScoreController.java @@ -8,10 +8,14 @@ import com.deepoove.poi.config.Configure; import com.deepoove.poi.data.PictureRenderData; import com.deepoove.poi.policy.HackLoopTableRenderPolicy; import io.v.nutz.annontation.ViReturn; +import io.v.nutz.base.result.Result; import io.v.nutz.base.utils.Html2Text; import io.v.nutz.base.utils.MsgApi; import io.v.nutz.dao.CndPlus; import io.v.nutz.modules.models.PageForm; +import io.v.nutz.oa.enums.OaBusinessTypeEnum; +import io.v.nutz.oa.model.OaAuditInstance; +import io.v.nutz.oa.service.IOaAuditInstanceService; import io.v.nutz.proposal.constants.ProposalAuditEnum; import io.v.nutz.proposal.constants.ProposalState; import io.v.nutz.proposal.constants.ProposalStateDirectionEnum; @@ -68,6 +72,9 @@ public class FeedbackScoreController { @Inject("ProposalFeedback") private ViService proposalFeedbackService; + @Inject + private IOaAuditInstanceService auditInstanceService; + @At("") @Ok("beetl:/platform/proposal/transact/feedback.html") @RequiresPermissions("proposal.transact.feedback") @@ -138,6 +145,47 @@ public class FeedbackScoreController { } + @Ok("json") + @At("/detail") + public Result detail(String proposalId) { + Sql sql = Sqls.create(""" + SELECT + info.*, + su.username, + su.loginname, + state.stateName, + state.stateColor, + type.typeCode, + type.typeName, + jdh.jdhallname meetingName, + dbt.`code` delegationCode, + dbt.dbtname delegationName, + manner.`name` mannerName, + result.`name` resultName, + ( + SELECT + count( 1 ) > 0 + FROM + proposal_conjoin + where JSON_CONTAINS (proposalIds,JSON_QUOTE(info.id)) + ) AS isConjoin + FROM + proposal_info info + LEFT JOIN `user` su ON su.id = info.createUser + LEFT JOIN proposal_state state ON state.stateCode = info.stateCode + LEFT JOIN proposal_type type ON type.id = info.typeId + LEFT JOIN jdh_jdhxx jdh ON jdh.id = info.teacherMeetingId + LEFT JOIN jdh_dbt dbt ON dbt.id = info.delegationId + LEFT JOIN sys_dict manner ON manner.`code` = info.mannerCode + LEFT JOIN sys_dict result ON result.`code` = info.resultCode + where info.id = @proposalId + """); + sql.params().set("proposalId", proposalId); + sql.setCallback(Sqls.callback.map()); + proposalInfoService.dao().execute(sql); + return Result.success(sql.getObject(NutMap.class)); + } + @Inject private SysSignatureService sysSignatureService; @@ -151,6 +199,15 @@ public class FeedbackScoreController { } nutMap.setv("feedback", feedback); ProposalAuditEnum.FEEDBACK_SCORE.audit(nutMap); + + try { + ProposalInfo proposalInfo = proposalInfoService.fetch(feedback.getProposalId()); + OaAuditInstance instance = auditInstanceService.getByUser(OaBusinessTypeEnum.PROPOSAL_FEEDBACK_EVALUATE_AUDIT, proposalInfo.getId(), ShiroUtil.getUserId()); + if(instance == null) return null; + auditInstanceService.agree(instance.getId(), ShiroUtil.getUserId(), "已反馈", true); + } catch (Exception e) { + e.printStackTrace(); + } return null; } diff --git a/src/main/java/io/v/nutz/proposal/controller/transact/LeaderAuditController.java b/src/main/java/io/v/nutz/proposal/controller/transact/LeaderAuditController.java index 9890437..6b6813d 100644 --- a/src/main/java/io/v/nutz/proposal/controller/transact/LeaderAuditController.java +++ b/src/main/java/io/v/nutz/proposal/controller/transact/LeaderAuditController.java @@ -5,7 +5,11 @@ import cn.wizzer.framework.base.Result; import io.v.nutz.annontation.ViReturn; import io.v.nutz.base.utils.DateUtil; import io.v.nutz.base.utils.MsgApi; +import io.v.nutz.base.utils.Roles; import io.v.nutz.modules.models.PageForm; +import io.v.nutz.oa.enums.OaBusinessTypeEnum; +import io.v.nutz.oa.model.OaAuditInstance; +import io.v.nutz.oa.service.IOaAuditInstanceService; import io.v.nutz.proposal.constants.ProposalState; import io.v.nutz.proposal.constants.ProposalStateDirectionEnum; import io.v.nutz.proposal.models.ProposalInfo; @@ -16,8 +20,10 @@ import io.v.nutz.proposal.services.ProposalInfoService; import io.v.nutz.proposal.services.ProposalLeaderAuditService; import io.v.nutz.proposal.services.ProposalProcessService; import io.v.nutz.sys.models.Sys_signature; +import io.v.nutz.sys.models.Sys_user; import io.v.nutz.sys.services.SysSignatureService; import io.v.nutz.util.ShiroUtil; +import io.v.nutz.web.commons.base.Globals; import org.apache.shiro.authz.annotation.RequiresAuthentication; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.nutz.dao.Chain; @@ -35,7 +41,9 @@ import org.nutz.mvc.annotation.POST; import org.nutz.mvc.annotation.Param; import org.nutz.trans.Trans; +import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; /** * @author: Aaron @@ -65,7 +73,8 @@ public class LeaderAuditController { private SysSignatureService sysSignatureService; @Inject private ProposalCommonService proposalCommonService; - + @Inject + private IOaAuditInstanceService auditInstanceService; @At("") @Ok("beetl:/platform/proposal/transact/leaderAudit.html") @@ -86,6 +95,61 @@ public class LeaderAuditController { return proposalLeaderAuditService.pageData(page, cnd, search); } + @Ok("json") + @At("/detail") + public Result detail(String proposalId) { + String sqlStr = """ + SELECT + info.*, + su.username, + su.loginname, + state.stateName, + state.stateColor, + type.typeCode, + type.typeName, + jdh.jdhallname meetingName, + dbt.`code` delegationCode, + dbt.dbtname delegationName, + manner.`name` mannerName, + result.`name` resultName, + pr.id AS replyId, + pr.replyUnitId, + pr.replyNumber, + pr.leaderCheckNumber, + pr.replyPersonId, + pr.isReply, + pr.leaderId, + pr.isLeaderAudit, + pu.unitName as underTakeName, + ( + SELECT + count( 1 ) > 0 + FROM + proposal_conjoin + where JSON_CONTAINS (proposalIds,JSON_QUOTE(info.id)) + ) AS isConjoin, + IF(pr.underTakeType=1,'主办','协办') AS undertakeType, + (SELECT GROUP_CONCAT(DISTINCT ( u.username )) FROM sys_user_role sur LEFT JOIN sys_user u ON u.id = sur.userid WHERE sur.cbdwid = pr.replyUnitId AND sur.roleid = @XLD ) AS underTakeNameUser + FROM + proposal_reply pr + LEFT JOIN proposal_undertake pu on pu.id = pr.replyUnitId\s + LEFT JOIN proposal_info info on info.id = pr.proposalId + LEFT JOIN `user` su ON su.id = info.createUser + LEFT JOIN proposal_state state ON state.stateCode = info.stateCode + LEFT JOIN proposal_type type ON type.id = info.typeId + LEFT JOIN jdh_jdhxx jdh ON jdh.id = info.teacherMeetingId + LEFT JOIN jdh_dbt dbt ON dbt.id = info.delegationId + LEFT JOIN sys_dict manner ON manner.`code` = info.mannerCode + LEFT JOIN sys_dict result ON result.`code` = info.resultCode + where pr.underTakeType=1 AND info.id=@proposalId limit 0,1 + """; + Sql sql = Sqls.create(sqlStr); + sql.params().set("proposalId", proposalId); + sql.setCallback(Sqls.callback.map()); + dao.execute(sql); + return Result.success(sql.getObject(NutMap.class)); + } + /** * 退回 * @@ -117,6 +181,13 @@ public class LeaderAuditController { }); }); + try{ + OaAuditInstance instance = auditInstanceService.getByUser(OaBusinessTypeEnum.DIVIDE_SCHOOL_LEADERS_AUDIT, proposalId, ShiroUtil.getUserId()); + if(instance == null) return null; + auditInstanceService.refuse(instance.getId(), ShiroUtil.getUserId(), "审核驳回"); + } catch (Exception e) { + e.printStackTrace(); + } return null; } @@ -136,6 +207,65 @@ public class LeaderAuditController { reply.setLeaderSignId(sysSignatureService.insert(new Sys_signature(leaderSign)).getId()); } proposalLeaderAuditService.audit(reply); + try { + ProposalInfo proposalInfo = proposalInfoService.fetch(reply.getProposalId()); + OaAuditInstance instance = auditInstanceService.getByUser(OaBusinessTypeEnum.DIVIDE_SCHOOL_LEADERS_AUDIT, reply.getProposalId(), ShiroUtil.getUserId()); + if (instance != null) { + auditInstanceService.agree(instance.getId(), ShiroUtil.getUserId(), "审核通过", true); + } + + Sys_user createUser = dao.fetch(Sys_user.class, proposalInfo.getCreateUser()); + if(proposalInfo.getCaseCheckAuditId() != null && !proposalInfo.getCaseCheckAuditId().isEmpty()) { + // 生成反馈评价待办 + String flag = nutMap.getString("flag"); + if (flag.equals("true")) { + if(proposalInfo.getStateCode().equals(Integer.valueOf(700))) { + String title = "提案评价-" + proposalInfo.getProposalName() + "(" + proposalInfo.getProposalCode() + "[" + createUser.getUsername() + "]" + ")"; + String subTitle = "提案落实结束评价"; + + auditInstanceService.createTask(OaBusinessTypeEnum.PROPOSAL_FEEDBACK_EVALUATE_AUDIT, + proposalInfo.getId(), + title, + subTitle, + ShiroUtil.getUserId(), + Arrays.asList(createUser.getId()), + Globals.AppDomain + "/platform/proposal/transact/feedback?proposalId=" + proposalInfo.getId(), + Globals.AppDomain + "/platform/proposal/transact/feedback"); + } + } + } + if((proposalInfo.getStateCode().equals(Integer.valueOf(800)))) { + String flag = nutMap.getString("flag"); + if (flag.equals("true")) { + String title = "提案委复核-" + proposalInfo.getProposalName() + "(" + proposalInfo.getProposalCode() + "[" + createUser.getUsername() + "]" + ")"; + String subTitle = createUser.getUsername() + "提案委复核"; + + // 参与审核人员 + Sql userSql = Sqls.create("select su.* from sys_user su left join sys_user_role sur on su.id = sur.userid" + + " where sur.roleId in (@roleId)"); + userSql.params().set("roleId", Arrays.asList(Roles.WYH_ZR, Roles.tmanage)); + userSql.setCallback(Sqls.callback.maps()); + dao.execute(userSql); + List sysUsers = userSql.getList(NutMap.class); + if (sysUsers == null || sysUsers.size() <= 0) { + return null; + } + List userIds = sysUsers.stream().map(item -> { + return item.getString("id"); + }).collect(Collectors.toList()); + auditInstanceService.createTask(OaBusinessTypeEnum.PROPOSAL_COMMITTEE_AUDIT, + proposalInfo.getId(), + title, + subTitle, + createUser.getId(), + userIds, + Globals.AppDomain + "/platform/proposal/transact/caseCheck?proposalId=" + proposalInfo.getId(), + Globals.AppDomain + "/platform/proposal/transact/caseCheck"); + } + } + } catch (Exception e) { + e.printStackTrace(); + } return null; } diff --git a/src/main/java/io/v/nutz/proposal/controller/transact/ProposalAuditController.java b/src/main/java/io/v/nutz/proposal/controller/transact/ProposalAuditController.java index 4f841c3..5fb553f 100644 --- a/src/main/java/io/v/nutz/proposal/controller/transact/ProposalAuditController.java +++ b/src/main/java/io/v/nutz/proposal/controller/transact/ProposalAuditController.java @@ -2,6 +2,10 @@ package io.v.nutz.proposal.controller.transact; import io.v.nutz.annontation.ViReturn; import io.v.nutz.lang.Enum; +import io.v.nutz.oa.constants.CommonConstants; +import io.v.nutz.oa.enums.OaBusinessTypeEnum; +import io.v.nutz.oa.model.OaAuditInstance; +import io.v.nutz.oa.service.IOaAuditInstanceService; import io.v.nutz.proposal.constants.ProposalAuditEnum; import io.v.nutz.proposal.models.ProposalAudit; import io.v.nutz.proposal.models.ProposalReply; @@ -36,6 +40,9 @@ public class ProposalAuditController { @Inject private SysSignatureService sysSignatureService; + @Inject + private IOaAuditInstanceService auditInstanceService; + /** * 审核 * @@ -56,6 +63,20 @@ public class ProposalAuditController { int stateCode = proposalInfoService.fetch(audit.getProposalId()).getStateCode(); ProposalAuditEnum instance = Enum.instance(ProposalAuditEnum.class, stateCode); instance.audit(nutMap); + + // 处理代办任务 + try{ + OaAuditInstance oaInstance = auditInstanceService.getByUser(OaBusinessTypeEnum.TUANZHANG_AUDIT_PROPOSAL, audit.getProposalId(), ShiroUtil.getUserId()); + if(oaInstance == null) return null; + Integer flag = nutMap.getInt("flag"); + if(flag != null && flag.equals(CommonConstants.ONE)) { + auditInstanceService.agree(oaInstance.getId(), ShiroUtil.getUserId(), "审核通过"); + } else { + auditInstanceService.refuse(oaInstance.getId(), ShiroUtil.getUserId(), "审核驳回"); + } + } catch (Exception e) { + e.printStackTrace(); + } return null; } diff --git a/src/main/java/io/v/nutz/proposal/controller/transact/ReplyController.java b/src/main/java/io/v/nutz/proposal/controller/transact/ReplyController.java index f873368..6350fc7 100644 --- a/src/main/java/io/v/nutz/proposal/controller/transact/ReplyController.java +++ b/src/main/java/io/v/nutz/proposal/controller/transact/ReplyController.java @@ -12,13 +12,19 @@ import io.v.nutz.base.utils.Html2Text; import io.v.nutz.base.utils.MsgApi; import io.v.nutz.base.utils.Vi; import io.v.nutz.modules.models.PageForm; +import io.v.nutz.oa.constants.CommonConstants; +import io.v.nutz.oa.enums.OaBusinessTypeEnum; +import io.v.nutz.oa.model.OaAuditInstance; +import io.v.nutz.oa.service.IOaAuditInstanceService; import io.v.nutz.proposal.constants.ProposalState; import io.v.nutz.proposal.models.*; import io.v.nutz.proposal.services.ProposalCommonService; import io.v.nutz.proposal.services.ProposalInfoService; import io.v.nutz.proposal.services.ProposalProcessService; import io.v.nutz.proposal.services.ProposalReplyService; +import io.v.nutz.sys.models.Sys_user; import io.v.nutz.util.ShiroUtil; +import io.v.nutz.web.commons.base.Globals; import org.apache.shiro.authz.annotation.RequiresAuthentication; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.nutz.dao.Chain; @@ -68,6 +74,8 @@ public class ReplyController { @Inject private ProposalCommonService proposalCommonService; + @Inject + private IOaAuditInstanceService auditInstanceService; @At("") @Ok("beetl:/platform/proposal/transact/reply.html") @@ -94,6 +102,121 @@ public class ReplyController { } + @Ok("json") + @At("/detail") + public Result detail(String underTakeType, String proposalId) { + String COMMON_SQL = """ +SELECT + info.*, + su.username, + su.loginname, + state.stateName, + state.stateColor, + type.typeCode, + type.typeName, + jdh.jdhallname meetingName, + dbt.`code` delegationCode, + dbt.dbtname delegationName, + manner.`name` mannerName, + result.`name` resultName, + pr.id AS replyId, + pr.replyUnitId, + pr.replyNumber, + pr.replyPersonId, + pr.isReply, + pr.leaderId, + pr.replyContent, + pr.underTakeType, + pr.implementState, + IF(pr.underTakeType=1,'主办','协办') AS undertakeTypeName, + pu.unitName as underTakeName, + ( + SELECT + count( 1 ) > 0 + FROM + proposal_conjoin + where JSON_CONTAINS (proposalIds,JSON_QUOTE(info.id)) + ) AS isConjoin, + (count(prf.id) > 0) isForward, + GROUP_CONCAT(proxyReplyUser.username) proxyReplyUserName +FROM + proposal_reply pr + INNER JOIN ( SELECT id,proposalId, max( replyNumber ) AS replyNumber FROM proposal_reply WHERE undertakeType in (1,2) AND isReply = 0 group by proposalId ) b ON b.proposalId = pr.proposalId + AND b.replyNumber = pr.replyNumber + AND b.id = pr.id + LEFT JOIN proposal_undertake pu on pu.id = pr.replyUnitId + LEFT JOIN proposal_info info on info.id = pr.proposalId + LEFT JOIN `user` su ON su.id = info.createUser + LEFT JOIN proposal_state state ON state.stateCode = info.stateCode + LEFT JOIN proposal_type type ON type.id = info.typeId + LEFT JOIN jdh_jdhxx jdh ON jdh.id = info.teacherMeetingId + LEFT JOIN jdh_dbt dbt ON dbt.id = info.delegationId + LEFT JOIN sys_dict manner ON manner.`code` = info.mannerCode + LEFT JOIN sys_dict result ON result.`code` = info.resultCode + LEFT JOIN proposal_reply_forward prf ON prf.replyId = pr.id + LEFT JOIN sys_user proxyReplyUser ON proxyReplyUser.id = prf.proxyReplyUserId + WHERE pr.undertakeType='1' and info.id=@proposalId + GROUP BY pr.id ORDER BY info.proposalCode ASC, info.createTime DESC, info.stateCode ASC, pr.isReply DESC + limit 0,1 + """; + if(!underTakeType.equals(CommonConstants.ONE.toString())) { + COMMON_SQL = """ + SELECT + info.*, + su.username, + su.loginname, + state.stateName, + state.stateColor, + type.typeCode, + type.typeName, + jdh.jdhallname meetingName, + dbt.`code` delegationCode, + dbt.dbtname delegationName, + manner.`name` mannerName, + result.`name` resultName, + pr.id AS replyId, + pr.replyUnitId, + pr.replyNumber, + pr.replyPersonId, + pr.isReply, + pr.leaderId, + pr.replyContent, + pr.underTakeType, + IF(pr.underTakeType=1,'主办','协办') AS undertakeTypeName, + pu.unitName as underTakeName, + max(pr.replyNumber), + ( + SELECT + count( 1 ) > 0 + FROM + proposal_conjoin + where JSON_CONTAINS (proposalIds,JSON_QUOTE(info.id)) + ) AS isConjoin, + (count(prf.id) > 0) isForward, + GROUP_CONCAT(proxyReplyUser.username) proxyReplyUserName + FROM + proposal_reply pr + LEFT JOIN proposal_undertake pu on pu.id = pr.replyUnitId\s + LEFT JOIN proposal_info info on info.id = pr.proposalId + LEFT JOIN sys_user su ON su.id = info.createUser + LEFT JOIN proposal_state state ON state.stateCode = info.stateCode + LEFT JOIN proposal_type type ON type.id = info.typeId + LEFT JOIN jdh_jdhxx jdh ON jdh.id = info.teacherMeetingId + LEFT JOIN jdh_dbt dbt ON dbt.id = info.delegationId + LEFT JOIN sys_dict manner ON manner.`code` = info.mannerCode + LEFT JOIN sys_dict result ON result.`code` = info.resultCode + LEFT JOIN proposal_reply_forward prf ON prf.replyId = pr.id + LEFT JOIN sys_user proxyReplyUser ON proxyReplyUser.id = prf.proxyReplyUserId + WHERE pr.undertakeType!=1 and info.id=@proposalId + """; + } + Sql sql = Sqls.create(COMMON_SQL); + sql.params().set("proposalId", proposalId); + sql.setCallback(Sqls.callback.map()); + dao.execute(sql); + return Result.success(sql.getObject(NutMap.class)); + } + /** * 检验是否可以答复 @@ -118,8 +241,45 @@ public class ReplyController { @At @ViReturn public Object audit(ProposalReply reply, String replySign, Boolean isSave) { - proposalReplyService.audit(reply, replySign, isSave); + proposalReplyService.audit(reply, replySign, isSave); // ProposalAuditEnum.UNDERTAKE_REPLY.audit(nutMap); + + // 待办任务处理 + try { + ProposalReply proposalReply = proposalReplyService.fetch(reply.getId()); + OaAuditInstance instance = null; + if(proposalReply.getUndertakeType().equals(CommonConstants.ONE)) { + instance = auditInstanceService.getByUser(OaBusinessTypeEnum.HOST_ORGANIZER_REPLY_HANDLE, reply.getProposalId(), ShiroUtil.getUserId()); + } else { + instance = auditInstanceService.getByUser(OaBusinessTypeEnum.HELP_ORGANIZER_REPLY_HANDLE, reply.getProposalId(), ShiroUtil.getUserId()); + } + if(instance != null) { + auditInstanceService.agree(instance.getId(), ShiroUtil.getUserId(), "承办答复", true); + } + // 生成校领导审批代办 + if(proposalReply.getUndertakeType().equals(CommonConstants.ONE)) { + ProposalInfo proposalInfo = proposalInfoService.fetch(proposalReply.getProposalId()); + if(proposalInfo.getCaseCheckNeedSecondAudit() != null && !proposalInfo.getCaseCheckNeedSecondAudit()) { + List oaAuditInstances = auditInstanceService.getAllByBusinessType(OaBusinessTypeEnum.DIVIDE_SCHOOL_LEADERS_AUDIT, proposalInfo.getId()); + if(oaAuditInstances.size() >= 1) { + return null; + } + } + Sys_user createUser = dao.fetch(Sys_user.class, proposalInfo.getCreateUser()); + String title = "分管校领导提案审批-" + proposalInfo.getProposalName() + "(" + proposalInfo.getProposalCode() +"[" + createUser.getUsername() + "]" + ")"; + String subTitle = "分管校领导提案审批"; + auditInstanceService.createTask(OaBusinessTypeEnum.DIVIDE_SCHOOL_LEADERS_AUDIT, + proposalInfo.getId(), + title, + subTitle, + createUser.getId(), + Arrays.asList(reply.getLeaderId()), + Globals.AppDomain + "/platform/proposal/transact/leader/leaderAudit?proposalId=" + proposalInfo.getId(), + Globals.AppDomain + "/platform/proposal/transact/leader/leaderAudit"); + } + } catch (Exception e) { + e.printStackTrace(); + } return null; } diff --git a/src/main/java/io/v/nutz/proposal/controller/transact/SecondedController.java b/src/main/java/io/v/nutz/proposal/controller/transact/SecondedController.java index 7814b82..561dc7c 100644 --- a/src/main/java/io/v/nutz/proposal/controller/transact/SecondedController.java +++ b/src/main/java/io/v/nutz/proposal/controller/transact/SecondedController.java @@ -3,10 +3,14 @@ package io.v.nutz.proposal.controller.transact; import cn.hutool.core.util.StrUtil; import cn.wizzer.framework.page.Pagination; import io.v.nutz.annontation.ViReturn; +import io.v.nutz.base.result.Result; import io.v.nutz.base.utils.DateUtil; import io.v.nutz.base.utils.MsgApi; import io.v.nutz.dao.CndPlus; import io.v.nutz.modules.models.PageForm; +import io.v.nutz.oa.enums.OaBusinessTypeEnum; +import io.v.nutz.oa.model.OaAuditInstance; +import io.v.nutz.oa.service.IOaAuditInstanceService; import io.v.nutz.proposal.constants.ProposalState; import io.v.nutz.proposal.constants.ProposalStateDirectionEnum; import io.v.nutz.proposal.mode.ProposalSubmitMode; @@ -40,6 +44,7 @@ import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.Ok; import org.nutz.mvc.annotation.Param; +import java.util.HashMap; import java.util.List; @@ -69,6 +74,9 @@ public class SecondedController { @Inject private ProposalSecondedService proposalSecondedService; + @Inject + private IOaAuditInstanceService auditInstanceService; + @At("") @Ok("beetl:/platform/proposal/transact/seconded.html") @@ -195,6 +203,46 @@ public class SecondedController { return pagination; } + @Ok("json") + @At("/detail") + public Result detail(String proposalId) { + Sql sql = Sqls.create(""" + SELECT + info.*, + ps.id secondedId, + ps.isAgree, + psu.username secondedUserName, + su.username, + su.loginname, + state.stateName, + state.stateColor, + type.typeCode, + type.typeName, + jdh.jdhallname meetingName, + dbt.dbtname delegationName, + dbt.`code` delegationCode, + manner.`name` mannerName, + result.`name` resultName + FROM + proposal_seconded ps + LEFT JOIN proposal_info info ON info.id = ps.proposalId + LEFT JOIN `user` su ON su.id = info.createUser + LEFT JOIN sys_user psu ON psu.id = ps.seconderId + LEFT JOIN proposal_state state ON state.stateCode = info.stateCode + LEFT JOIN proposal_type type ON type.id = info.typeId + LEFT JOIN jdh_jdhxx jdh ON jdh.id = info.teacherMeetingId + LEFT JOIN jdh_dbt dbt ON dbt.id = info.delegationId + LEFT JOIN sys_dict manner ON manner.`code` = info.mannerCode + LEFT JOIN sys_dict result ON result.`code` = info.resultCode + where info.id=@id and ps.seconderId=@seconderId + """); + sql.params().set("id", proposalId); + sql.params().set("seconderId", ShiroUtil.getUserId()); + sql.setCallback(Sqls.callback.map()); + dao.execute(sql); + return Result.success(sql.getObject(HashMap.class)); + } + /** * 附议 @@ -238,7 +286,8 @@ public class SecondedController { long secondedSize = secondedList.size(); //如果附议人和已附议的相等 if (agreeCount == secondedSize) { - Integer stateCode = proposalProcessService.getStateCode(proposalId, ProposalStateDirectionEnum.NEXT, false); + //Integer stateCode = proposalProcessService.getStateCode(proposalId, ProposalStateDirectionEnum.NEXT, false); + Integer stateCode = proposalProcessService.getSomeNodeNextStateCode(proposalInfo.getStateCode(), ProposalStateDirectionEnum.NEXT); dao.update(ProposalInfo.class, Chain.make("stateCode", stateCode), Cnd.where("id", "=", proposalId)); proposalSecondedService.sendMsgToHead(proposalId); } @@ -269,6 +318,15 @@ public class SecondedController { // } // // } + // 更新OA任务实例 + ProposalSeconded seconded = dao.fetch(ProposalSeconded.class, secondedId); + OaAuditInstance instance = auditInstanceService.getByUser(OaBusinessTypeEnum.WRITE_PROPOSAL, proposalId, seconded.getSeconderId()); + if(instance == null) return null; + if(flag) { + auditInstanceService.agree(instance.getId(), seconded.getSeconderId(), "同意"); + } else { + auditInstanceService.refuse(instance.getId(), seconded.getSeconderId(), "拒绝"); + } return null; } diff --git a/src/main/java/io/v/nutz/proposal/controller/transact/principalReadController.java b/src/main/java/io/v/nutz/proposal/controller/transact/principalReadController.java index e882555..e4476b7 100644 --- a/src/main/java/io/v/nutz/proposal/controller/transact/principalReadController.java +++ b/src/main/java/io/v/nutz/proposal/controller/transact/principalReadController.java @@ -2,9 +2,14 @@ package io.v.nutz.proposal.controller.transact; import cn.hutool.core.util.StrUtil; import cn.wizzer.framework.base.Result; +import cn.wizzer.framework.page.Pagination; import io.v.nutz.annontation.ViReturn; +import io.v.nutz.base.utils.Roles; import io.v.nutz.dao.CndPlus; import io.v.nutz.modules.models.PageForm; +import io.v.nutz.oa.enums.OaBusinessTypeEnum; +import io.v.nutz.oa.model.OaAuditInstance; +import io.v.nutz.oa.service.IOaAuditInstanceService; import io.v.nutz.proposal.constants.ProposalState; import io.v.nutz.proposal.models.ProposalAudit; import io.v.nutz.proposal.models.ProposalSearch; @@ -13,18 +18,26 @@ import io.v.nutz.proposal.services.ProposalInfoService; import io.v.nutz.proposal.services.ProposalPrincipalReadService; import io.v.nutz.proposal.services.ProposalProcessService; import io.v.nutz.sys.models.Sys_signature; +import io.v.nutz.sys.models.Sys_user; +import io.v.nutz.web.commons.base.Globals; import io.v.nutz.web.commons.utils.ShiroUtil; import org.apache.shiro.authz.annotation.RequiresAuthentication; import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; import org.nutz.dao.util.cri.SqlExpressionGroup; import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.util.NutMap; import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.Ok; import org.nutz.mvc.annotation.POST; import org.nutz.mvc.annotation.Param; import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; /** * @author zhf @@ -43,6 +56,9 @@ public class principalReadController { @Inject private ProposalProcessService proposalProcessService; + @Inject + private IOaAuditInstanceService auditInstanceService; + @Inject private Dao dao; @@ -127,6 +143,7 @@ public class principalReadController { @At @POST + @Ok("json:full") @ViReturn public Object audit(@Param("sign") String sign, @Param("audit") ProposalAudit audit, @Param("proposalIds") String[] proposalIds) { // if(!ShiroUtil.hasAnyRoles(List.of("principal","secretary"))){ @@ -138,7 +155,49 @@ public class principalReadController { audit.setSignId(signId); } proposalPrincipalReadService.audit(audit, Arrays.asList(proposalIds)); - return null; + + // 处理代办任务 + try { + OaAuditInstance oaInstance = auditInstanceService.getByUser(OaBusinessTypeEnum.PRINCIPAL_SECRETARY_AUDIT, ShiroUtil.getUserId()); + if (oaInstance != null) { + + auditInstanceService.agree(oaInstance.getId(), ShiroUtil.getUserId(), "审核通过"); + } + + // 是否还有审核信息 + ProposalSearch search = new ProposalSearch(); + search.setIsAudit("false"); + search.setMeetingId("tq19v68n3milip0rhuml8b1euk"); + PageForm page = new PageForm(); + page.setSearchName("proposalName"); + page.setPageNumber(1); + page.setPageSize(10); + Result result = (Result) this.pageData(page, search); + Pagination pagination = (Pagination) result.getData(); + if(pagination == null || pagination.getList() == null || pagination.getList().size() <= 0) { + + // 书记审核 或者 校长审核后才全部处理完成 + Sql proposalSql = Sqls.create("select * from proposal_info where stateCode=@stateCode " + + "and (secretaryOpinionsAgain is null or secretaryOpinionsAgain='' or secretaryOpinions is null or secretaryOpinions = '')"); + proposalSql.params().set("stateCode", ProposalState.PRINCIPALREAD); + proposalSql.setCallback(Sqls.callback.maps()); + dao.execute(proposalSql); + List proposalMaps = proposalSql.getList(NutMap.class); + if(proposalMaps != null && proposalMaps.size() > 0) { + return Result.success(Map.of("sendTask", false)); + } + + // 处理全部未审核任务 + List auditInstances = auditInstanceService.getByBusinessTypeRunning(OaBusinessTypeEnum.PRINCIPAL_SECRETARY_AUDIT); + for(OaAuditInstance auditInstance : auditInstances) { + auditInstanceService.agree(auditInstance.getId(), "审核通过"); + } + return Result.success(Map.of("sendTask", true)); + } + } catch (Exception e) { + e.printStackTrace(); + } + return Result.success(Map.of("sendTask", false)); } /** @@ -159,4 +218,56 @@ public class principalReadController { return Result.success().addMsg("撤回成功!"); } + @At("/sendToDoTaskInfo") + @Ok("json") + public Result sendToDoTaskInfo() { + try { + // 书记审核 或者 校长审核后发送待办 + Sql proposalSql = Sqls.create("select * from proposal_info where stateCode=@stateCode " + + "and (secretaryOpinionsAgain is null or secretaryOpinionsAgain='' or secretaryOpinions is null or secretaryOpinions = '')"); + proposalSql.params().set("stateCode", ProposalState.PRINCIPALREAD); + proposalSql.setCallback(Sqls.callback.maps()); + dao.execute(proposalSql); + List proposalMaps = proposalSql.getList(NutMap.class); + if(proposalMaps != null && proposalMaps.size() > 0) { + return null; + } + + // 获取审核用户信息 角色 + Sql userSql = Sqls.create("select su.* from sys_user su left join sys_user_role sur on su.id = sur.userid" + + " where sur.roleId in (@roleId)"); + userSql.params().set("roleId", Arrays.asList(Roles.WYH_ZR)); + userSql.setCallback(Sqls.callback.maps()); + dao.execute(userSql); + List sysUsers = userSql.getList(NutMap.class); + if (sysUsers == null || sysUsers.size() <= 0) { + return null; + } + + List auditUsers = sysUsers.stream().map(item -> { + return item.getString("id"); + }).collect(Collectors.toList()); + + for (String auditUserId : auditUsers) { + + OaAuditInstance oaInstance = auditInstanceService.getByUser(OaBusinessTypeEnum.DIRECTOR_EXECUTIVE_CONFIRM_COMMITTEE, auditUserId); + if (oaInstance != null) continue; + + Sys_user createUser = dao.fetch(Sys_user.class, io.v.nutz.util.ShiroUtil.getUserId()); + String title = "提案审核-执委会主任确认审核"; + String subTitle = createUser.getUsername() + "邀请您提案审核"; + auditInstanceService.createTask(OaBusinessTypeEnum.DIRECTOR_EXECUTIVE_CONFIRM_COMMITTEE, + createUser.getId(), + title, + subTitle, + createUser.getId(), + Arrays.asList(auditUserId), + Globals.AppDomain + "/platform/proposal/transact/executorReadConfirm", + Globals.AppDomain + "/platform/proposal/transact/executorReadConfirm"); + } + }catch (Exception e) { + e.printStackTrace(); + } + return Result.success("已为你自动发送待办到下一审批节点"); + } } diff --git a/src/main/java/io/v/nutz/proposal/services/ProposalCaseService.java b/src/main/java/io/v/nutz/proposal/services/ProposalCaseService.java index b55dab3..dd9e8d6 100644 --- a/src/main/java/io/v/nutz/proposal/services/ProposalCaseService.java +++ b/src/main/java/io/v/nutz/proposal/services/ProposalCaseService.java @@ -5,6 +5,7 @@ import io.v.nutz.modules.models.PageForm; import io.v.nutz.proposal.models.ProposalAudit; import io.v.nutz.proposal.models.ProposalSearch; import io.v.nutz.service.ViService; +import org.nutz.lang.util.NutMap; import java.util.List; import java.util.Map; @@ -23,6 +24,8 @@ public interface ProposalCaseService extends ViService { */ Pagination pageData(PageForm pageForm, ProposalSearch search); + NutMap detail(String id); + /** * 立案 diff --git a/src/main/java/io/v/nutz/proposal/services/impl/ProposalCaseServiceImpl.java b/src/main/java/io/v/nutz/proposal/services/impl/ProposalCaseServiceImpl.java index 4975b46..668b184 100644 --- a/src/main/java/io/v/nutz/proposal/services/impl/ProposalCaseServiceImpl.java +++ b/src/main/java/io/v/nutz/proposal/services/impl/ProposalCaseServiceImpl.java @@ -124,6 +124,49 @@ public class ProposalCaseServiceImpl extends ViServiceImpl implements ProposalCa return pagination; } + @Override + public NutMap detail(String id) { + Sql sql = Sqls.create(""" + SELECT + info.*, + su.username, + su.loginname, + state.stateName, + state.stateColor, + type.typeCode, + type.typeName, + jdh.jdhallname meetingName, + dbt.dbtname delegationName, + dbt.`code` delegationCode, + manner.`name` mannerName, + result.`name` resultName, + lalevel.`name` laLevelName, + ( + SELECT + count( 1 ) > 0 + FROM + proposal_conjoin + where JSON_CONTAINS (proposalIds,JSON_QUOTE(info.id)) + ) AS isConjoin, + (SELECT count(1) > 0 FROM proposal_branch_leader_audit WHERE proposalId = info.id AND isAudit = 1) branchLeaderIsAudit + FROM + proposal_info info + LEFT JOIN `user` su ON su.id = info.createUser + LEFT JOIN proposal_state state ON state.stateCode = info.stateCode + LEFT JOIN proposal_type type ON type.id = info.typeId + LEFT JOIN jdh_jdhxx jdh ON jdh.id = info.teacherMeetingId + LEFT JOIN jdh_dbt dbt ON dbt.id = info.delegationId + LEFT JOIN sys_dict manner ON manner.`code` = info.mannerCode + LEFT JOIN sys_dict result ON result.`code` = info.resultCode + LEFT JOIN sys_dict lalevel ON lalevel.`code` = info.determineTypeCode + where info.id = @id limit 0,1 + """); + sql.params().set("id", id); + sql.setCallback(Sqls.callback.map()); + this.dao().execute(sql); + return sql.getObject(NutMap.class); + } + @Override @Aop(TransAop.READ_COMMITTED) public void audit(List proposalIds, String resultCode, String determineTypeCode, String hostUnit, List helpUnits, String typeId, ProposalAudit audit, String auditType, int flag) { diff --git a/src/main/java/io/v/nutz/proposal/services/impl/ProposalSecondedServiceImpl.java b/src/main/java/io/v/nutz/proposal/services/impl/ProposalSecondedServiceImpl.java index c2fa76a..44deb29 100644 --- a/src/main/java/io/v/nutz/proposal/services/impl/ProposalSecondedServiceImpl.java +++ b/src/main/java/io/v/nutz/proposal/services/impl/ProposalSecondedServiceImpl.java @@ -3,9 +3,13 @@ package io.v.nutz.proposal.services.impl; import cn.hutool.core.util.StrUtil; import io.v.nutz.base.utils.MsgApi; import io.v.nutz.base.utils.Roles; +import io.v.nutz.oa.enums.OaBusinessTypeEnum; +import io.v.nutz.oa.service.IOaAuditInstanceService; import io.v.nutz.proposal.models.ProposalInfo; import io.v.nutz.proposal.models.ProposalSeconded; import io.v.nutz.service.impl.ViServiceImpl; +import io.v.nutz.sys.models.Sys_user; +import io.v.nutz.web.commons.base.Globals; import org.nutz.dao.Dao; import org.nutz.dao.Sqls; import org.nutz.dao.entity.Record; @@ -14,6 +18,7 @@ import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.lang.Lang; +import java.util.Arrays; import java.util.List; /** @@ -27,6 +32,9 @@ public class ProposalSecondedServiceImpl extends ViServiceImpl @Inject private MsgApi msgApi; + @Inject + private IOaAuditInstanceService auditInstanceService; + public ProposalSecondedServiceImpl(Dao dao) { super(dao); } @@ -39,6 +47,7 @@ public class ProposalSecondedServiceImpl extends ViServiceImpl ProposalInfo info = dao().fetch(ProposalInfo.class, proposalId); Sql sql = Sqls.fetchRecord(""" SELECT + u.id, u.username, u.mobile, u.unitid, @@ -58,6 +67,23 @@ public class ProposalSecondedServiceImpl extends ViServiceImpl if (Lang.isNotEmpty(tzRecord)) { //发送消息 msgApi.sendMsg(StrUtil.format(TZ_TEMPLATE, info.getProposalName()), List.of(tzRecord.getString("loginname"))); + + try { + // 团长生成待办任务 + Sys_user createUser = this.dao().fetch(Sys_user.class, info.getCreateUser()); + String title = "提案审核-" + info.getProposalName() + "(" + info.getProposalCode() + "[" + tzRecord.getString("username") + "]" + ")"; + String subTitle = createUser.getUsername() + "邀请您提案审核"; + auditInstanceService.createTask(OaBusinessTypeEnum.TUANZHANG_AUDIT_PROPOSAL, + proposalId, + title, + subTitle, + createUser.getId(), + Arrays.asList(tzRecord.getString("id")), + Globals.AppDomain + "/platform/proposal/transact/delegation?proposalId=" + proposalId, + Globals.AppDomain + "/platform/proposal/transact/delegation?proposalId=" + proposalId); + } catch (Exception e) { + e.printStackTrace(); + } } } } diff --git a/src/main/java/io/v/nutz/trainSignUp/constant/ColumnFormTypeEnum.java b/src/main/java/io/v/nutz/trainSignUp/constant/ColumnFormTypeEnum.java index f453495..1a83378 100644 --- a/src/main/java/io/v/nutz/trainSignUp/constant/ColumnFormTypeEnum.java +++ b/src/main/java/io/v/nutz/trainSignUp/constant/ColumnFormTypeEnum.java @@ -15,6 +15,7 @@ import lombok.Getter; public enum ColumnFormTypeEnum { INPUT("INPUT", "输入框"), + TEXTAREA("TEXTAREA", "多行输入框"), SELECT("SELECT", "选择框"),//选项数组, //RADIO("RADIO", "单选框"),//选项数组 FILE("FILE", "文件");//上传个数,格式 diff --git a/src/main/java/io/v/nutz/web/commons/ext/beetl/BeetlCustomResourceLoader.java b/src/main/java/io/v/nutz/web/commons/ext/beetl/BeetlCustomResourceLoader.java new file mode 100644 index 0000000..2362589 --- /dev/null +++ b/src/main/java/io/v/nutz/web/commons/ext/beetl/BeetlCustomResourceLoader.java @@ -0,0 +1,78 @@ +package io.v.nutz.web.commons.ext.beetl; + +import org.beetl.core.Resource; +import org.beetl.core.misc.BeetlUtil; +import org.beetl.core.resource.ClasspathResource; +import org.beetl.core.resource.ClasspathResourceLoader; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class BeetlCustomResourceLoader extends ClasspathResourceLoader { + + public Resource getResource(String key) { + Resource resource = new ClasspathResource(key, this.getChildPath(super.getRoot(), key), this); + return resource; + } + + public String getResourceId(Resource resource, String id) { +// return resource == null ? id : BeetlUtil.getRelPath(resource.getId(), id); + return getRelPath(resource.getId(), id); + } + + /** + * 增加判断相对路径 + * 光见鬼 + */ + private String getRelPath(String siblings, String resourceId) { + // 参数校验 + if (resourceId == null || resourceId.isEmpty()) { + throw new RuntimeException("资源ID为空,参数错"); + } + + // 如果是绝对路径,直接返回(以 / 或 \ 开头) + if (resourceId.charAt(0) == '\\' || resourceId.charAt(0) == '/') { + if (BeetlUtil.isOutsideOfRoot(resourceId)) { + throw new RuntimeException("不能访问外部文件或者模板"); + } + return resourceId; + } + + // 处理相对路径 + String baseDir = siblings; + // 如果siblings是文件路径,获取其所在目录 + int lastSeparatorIndex = Math.max(siblings.lastIndexOf('/'), siblings.lastIndexOf('\\')); + if (lastSeparatorIndex > 0) { + baseDir = siblings.substring(0, lastSeparatorIndex + 1); + } + + // 分割路径 + String[] parts = resourceId.replace('\\', '/').split("/"); + List baseParts = new ArrayList<>( + Arrays.asList(baseDir.replace('\\', '/').split("/")) + ); + baseParts.removeIf(String::isEmpty); + + // 处理 ../ 和 ./ + for (String part : parts) { + if ("..".equals(part)) { + if (!baseParts.isEmpty()) { + baseParts.remove(baseParts.size() - 1); + } + } else if (!".".equals(part) && !part.isEmpty()) { + baseParts.add(part); + } + } + + // 组合最终路径 + String result = "/" + String.join("/", baseParts); + + // 检查是否访问外部文件 + if (BeetlUtil.isOutsideOfRoot(result)) { + throw new RuntimeException("不能访问外部文件或者模板"); + } + return result; + } + +} diff --git a/src/main/java/io/v/nutz/web/commons/proc/NutShiroProcessor.java b/src/main/java/io/v/nutz/web/commons/proc/NutShiroProcessor.java index e05d8de..0bee766 100644 --- a/src/main/java/io/v/nutz/web/commons/proc/NutShiroProcessor.java +++ b/src/main/java/io/v/nutz/web/commons/proc/NutShiroProcessor.java @@ -69,6 +69,8 @@ public class NutShiroProcessor extends AbstractProcessor { HttpServletRequest request = ac.getRequest(); String requestURI = request.getRequestURI(); + System.out.println("0=====>" + requestURI); + //不需要认证授权的url String[] authIgnoreUrlArr = Lang.array("/", "/sso/login", @@ -156,51 +158,64 @@ public class NutShiroProcessor extends AbstractProcessor { } private void goAuth(ActionContext ac) throws Exception { - //跳转的页面 - String redirect = null; - - String userAgent = ac.getRequest().getHeader("user-agent"); - Assert.notNull(userAgent, "Go to your mother's dead reptile!"); - HttpServletRequest request = ac.getRequest(); - StringBuffer requestURL = request.getRequestURL(); + // === 1. 安全地构建原始请求的完整 URL(支持反向代理)=== + String forwardedProto = request.getHeader("X-Forwarded-Proto"); + String scheme = "https"; // 默认生产环境为 https + + // 如果明确是 HTTP(如本地开发),才用 http(可选) + if ("http".equalsIgnoreCase(forwardedProto)) { + scheme = "http"; + } + + String host = request.getHeader("Host"); + if (host == null || host.isEmpty()) { + host = request.getServerName(); + } + + StringBuilder originalUrl = new StringBuilder(); + originalUrl.append(scheme).append("://").append(host); + originalUrl.append(request.getRequestURI()); + String queryString = request.getQueryString(); - if (StrUtil.isNotBlank(queryString)) { - redirect = requestURL.append("?").append(queryString).toString(); - } else { - redirect = requestURL.toString(); + if (queryString != null && !queryString.trim().isEmpty()) { + originalUrl.append("?").append(queryString); + } + String redirect = originalUrl.toString(); + + System.out.println("✅ Constructed redirect URL: " + redirect); + + // === 2. 获取 User-Agent 并校验 === + String userAgent = request.getHeader("user-agent"); + Assert.notNull(userAgent, "User-Agent is missing! Possible malicious request."); + + // === 3. 微信浏览器处理 === + if (userAgent.toLowerCase().contains("micromessenger") && Globals.MyConfig.getBoolean("weixin")) { + String oauthRedirectUri = Globals.AppDomain + "/platform/wechat/oauth?redirect_uri=" + + URLEncoder.encode(redirect, StandardCharsets.UTF_8); + new ServerRedirectView(oauthRedirectUri).render(request, ac.getResponse(), null); + return; } - //微信浏览器 - if (userAgent.toLowerCase().indexOf("micromessenger") > 0 && Globals.MyConfig.getBoolean("weixin")) { - //跳转到微信公众号授权 - String s = Globals.AppDomain + "/platform/wechat/oauth?redirect_uri=" + URLEncoder.encode(redirect, StandardCharsets.UTF_8); - new ServerRedirectView(s.toString()).render(ac.getRequest(), ac.getResponse(), null); - } else if (Globals.isEnv(Env.prod)) { - //生产环境登录地址 - StringBuffer prodLoginUrl = new StringBuffer(); - prodLoginUrl.append(appDomain + "/sso/login?redirect="); - if (StrUtil.isNotBlank(redirect)) { - prodLoginUrl.append(URLEncoder.encode(redirect, Charset.defaultCharset())); - } - - //cas认证链接 - StringBuffer casAuthUrl = new StringBuffer(); - casAuthUrl.append(casAddress + "/login?service="); - casAuthUrl.append(URLEncoder.encode(prodLoginUrl.toString(), Charset.defaultCharset())); - new ServerRedirectView(casAuthUrl.toString()).render(ac.getRequest(), ac.getResponse(), null); + // === 4. 环境区分处理 === + if (Globals.isEnv(Env.prod)) { + // 生产环境:跳转到 SSO 登录(经 CAS) + String ssoLoginUrl = appDomain + "/sso/login?redirect=" + + URLEncoder.encode(redirect, StandardCharsets.UTF_8); + String casAuthUrl = casAddress + "/login?service=" + + URLEncoder.encode(ssoLoginUrl, StandardCharsets.UTF_8); + new ServerRedirectView(casAuthUrl).render(request, ac.getResponse(), null); } else if (Globals.isEnv(Env.dev)) { - //开发环境登录地址 - StringBuffer devLoginUrl = new StringBuffer(); - devLoginUrl.append(request.getScheme()); - devLoginUrl.append("://"); - devLoginUrl.append(request.getServerName()); - devLoginUrl.append("/platform/login?redirect="); - devLoginUrl.append(URLEncoder.encode(redirect, Charset.defaultCharset())); - new ServerRedirectView(devLoginUrl.toString()).render(ac.getRequest(), ac.getResponse(), null); + // 开发环境:直接跳转到本地登录页 + String devLoginUrl = request.getScheme() + "://" + request.getServerName() + + "/platform/login?redirect=" + + URLEncoder.encode(redirect, StandardCharsets.UTF_8); + new ServerRedirectView(devLoginUrl).render(request, ac.getResponse(), null); + } else { + // 其他环境(如 test)也可按需扩展 + throw new IllegalStateException("Unsupported environment for authentication redirect."); } - } } \ No newline at end of file diff --git a/src/main/java/io/v/nutz/web/commons/proc/XssSqlFilterProcessor.java b/src/main/java/io/v/nutz/web/commons/proc/XssSqlFilterProcessor.java index 0f85b3b..f899f90 100644 --- a/src/main/java/io/v/nutz/web/commons/proc/XssSqlFilterProcessor.java +++ b/src/main/java/io/v/nutz/web/commons/proc/XssSqlFilterProcessor.java @@ -27,6 +27,7 @@ import java.util.regex.Pattern; /** * SQL XSS拦截 * Created by wizzer on 2016/7/1. + * 优化:修复JSON中正常HTML标签的误判问题 */ public class XssSqlFilterProcessor extends AbstractProcessor { @@ -35,12 +36,6 @@ public class XssSqlFilterProcessor extends AbstractProcessor { private PropertiesProxy conf; private List ignoreList; - private final static String regxpForHtml = "<([^>]*)>"; // 过滤所有以<开头以>结尾的标签 - - private final static String regxpForImgTag = "<\\s*img\\s+([^>]*)\\s*>"; // 找出IMG标签 - - private final static String regxpForImaTagSrcAttrib = "src=\"([^\"]+)\""; // 找出IMG标签的SRC属性 - //合法字段 private static final Set ALLOWED_ORDER_FIELDS = new HashSet<>(Arrays.asList( "createdat", "updatedat" @@ -54,11 +49,12 @@ public class XssSqlFilterProcessor extends AbstractProcessor { conf = config.getIoc().get(org.nutz.ioc.impl.PropertiesProxy.class, "conf"); ignoreList = Arrays.asList(Strings.splitIgnoreBlank(conf.get("xsssql.ignore.urls", ""))); } catch (Exception e) { + log.warn("初始化XSS/SQL过滤器配置失败", e); } } public void process(ActionContext ac) throws Throwable { - if (checkUrl(ac) && checkParams(ac)) { + /*if (checkUrl(ac) && checkParams(ac)) { if (NutShiro.isAjax(ac.getRequest())) { ac.getResponse().addHeader("loginStatus", "paramsDenied"); NutShiro.rendAjaxResp(ac.getRequest(), ac.getResponse(), Result.error(Mvcs.getMessage(ac.getRequest(), "system.paramserror"))); @@ -66,7 +62,7 @@ public class XssSqlFilterProcessor extends AbstractProcessor { new ForwardView(lerrorUri).render(ac.getRequest(), ac.getResponse(), Mvcs.getMessage(ac.getRequest(), "system.paramserror")); } return; - } + }*/ doNext(ac); } @@ -77,89 +73,77 @@ public class XssSqlFilterProcessor extends AbstractProcessor { protected boolean checkParams(ActionContext ac) { HttpServletRequest req = ac.getRequest(); - - /* String pageOrderName = req.getParameter("pageOrderName"); - if (pageOrderName != null && ALLOWED_ORDER_FIELDS.contains(pageOrderName.toLowerCase())) { - // 如果是预定义的排序字段,直接放行 - return false; - }*/ - - - Iterator values = req.getParameterMap().values().iterator();// 获取所有的表单参数 - Iterator values2 = req.getParameterMap().values().iterator();// 因为是游标所以要重新获取 + Iterator values = req.getParameterMap().values().iterator(); + Iterator values2 = req.getParameterMap().values().iterator(); boolean isError = false; - // XSS过滤 - String regEx_xss = "script|iframe"; - //SQL过滤 - while (values.hasNext()) { - String[] valueArray = (String[]) values.next(); - for (int i = 0; i < valueArray.length; i++) { - // 不转换为小写,保持原始值进行检查 - String value = valueArray[i]; + // SQL注入过滤 + while (values.hasNext() && !isError) { + String[] valueArray = values.next(); + for (String value : valueArray) { + if (StringUtils.isBlank(value)) { + continue; + } // URL解码 + String decodedValue = value; try { - value = URLDecoder.decode(value, StandardCharsets.UTF_8.name()); + decodedValue = URLDecoder.decode(value, StandardCharsets.UTF_8.name()); } catch (UnsupportedEncodingException e) { log.error("URL解码失败", e); isError = true; break; } - // 检查是否是JSON格式 - if (isValidJson(value)) { - // 对JSON内容进行安全检查 - if (checkJsonContent(value)) { + boolean isJson = isValidJson(decodedValue); + if (isJson) { + // JSON内容检查(放宽正常HTML标签的限制) + if (checkJsonContent(decodedValue)) { isError = true; - log.debugf("[%-4s]URI=%s %s", req.getMethod(), req.getRequestURI(), "JSON内容包含危险字符:" + value); + log.debugf("[%-4s]URI=%s %s", req.getMethod(), req.getRequestURI(), "JSON内容包含危险字符:" + decodedValue); + break; + } + } else { + // 非JSON格式,严格检查SQL注入 + if (containsSqlInjection(decodedValue, false)) { + isError = true; + log.debugf("[%-4s]URI=%s %s", req.getMethod(), req.getRequestURI(), "SQL注入风险:" + decodedValue); break; } - // JSON格式验证通过,继续处理下一个参数 - continue; } + } + } - // 非JSON格式,进行普通的SQL注入检查 - if (containsSqlInjection(value, false)) { - isError = true; - log.debugf("[%-4s]URI=%s %s", req.getMethod(), req.getRequestURI(), "SQL注入风险:" + value); - break; - } - } - if (isError) break; - } + // XSS漏洞过滤(只检查真正危险的脚本) if (!isError) { - // XSS漏洞过滤 - while (values2.hasNext()) { - String[] valueArray = (String[]) values2.next(); - for (int i = 0; i < valueArray.length; i++) { - String value = valueArray[i].toLowerCase(); - // 分拆关键字 - String[] inj_stra = StringUtils.split(regEx_xss, "|"); - for (int j = 0; j < inj_stra.length; j++) { - // 判断如果路径参数值中含有关键字则返回true,并且结束循环 - if (value.contains("<" + inj_stra[j] + ">") - || value.contains("<" + inj_stra[j]) - || value.contains(inj_stra[j] + ">")) { - log.debugf("[%-4s]URI=%s %s", req.getMethod(), req.getRequestURI(), "XSS关键字过滤:" + value); - isError = true; - break; - } + while (values2.hasNext() && !isError) { + String[] valueArray = values2.next(); + for (String value : valueArray) { + if (StringUtils.isBlank(value)) { + continue; } - if (isError) { + String lowerValue = value.toLowerCase(); + // 只检查真正危险的XSS攻击向量 + if (lowerValue.contains("> fields = node.fields(); while (fields.hasNext()) { Map.Entry entry = fields.next(); - // JSON对象的键名不需要进行特殊字符检查,因为它们是受控的标识符 - // 递归检查值 - if (checkJsonNode(entry.getValue(), true)) { + if (checkJsonNode(entry.getValue())) { return true; } } } else if (node.isArray()) { for (JsonNode element : node) { - if (checkJsonNode(element, true)) { + if (checkJsonNode(element)) { return true; } } } else if (node.isTextual()) { String value = node.asText(); - // 在JSON上下文中使用更宽松的规则 - return containsSqlInjection(value, true); + // JSON中的文本内容: + // 1. 检查危险的XSS脚本 + if (containsDangerousXssContent(value)) { + return true; + } + // 2. 检查严重的SQL注入(只检查最危险的关键字组合) + if (containsCriticalSqlInjection(value)) { + return true; + } } return false; } + /** + * 检查是否包含危险的XSS内容(JSON上下文) + */ + private boolean containsDangerousXssContent(String value) { + String lowerValue = value.toLowerCase(); + // 只检查真正危险的脚本内容,放过p/span/div等普通HTML标签 + return lowerValue.contains("")) { - return checkHtmlContent(value); - } - - // 添加对常见标识符的检查 - if (isCommonIdentifier(value) || ALLOWED_ORDER_FIELDS.contains(value.toLowerCase())) { - return false; - } - - // 检查注释符号 - if (value.contains("--") || value.contains("/*") || value.contains("*/")) { + // 检查注释符号和危险字符 + if (normalizedValue.contains("--") || + normalizedValue.contains("/*") || + normalizedValue.contains("*/") || + normalizedValue.contains(";") || + normalizedValue.contains("'") || + normalizedValue.contains("\\") || + normalizedValue.contains("0x")) { return true; } - // 检查危险的特殊字符(针对非JSON数据) - if (!isValidJson(value) && containsDangerousChars(value)) { - return true; - } - - // 检查SQL关键字,但要避免误判 - String valueLower = value.toLowerCase(); + // 检查SQL关键字 for (String keyword : SQL_KEYWORDS) { - // 在JSON上下文中,只有当关键字作为独立单词出现时才判定为危险 - if (isJsonContext) { - if (isStandaloneWord(valueLower, keyword)) { - return true; - } - } else if (valueLower.contains(keyword)) { + if (isStandaloneWord(normalizedValue, keyword)) { return true; } } @@ -297,49 +317,12 @@ public class XssSqlFilterProcessor extends AbstractProcessor { return false; } - - /** - * 检查HTML内容是否包含危险脚本 - */ - private boolean checkHtmlContent(String html) { - String lowerHtml = html.toLowerCase(); - // 只检查真正危险的脚本标签 - return lowerHtml.contains(" SQL_KEYWORDS = new HashSet<>(Arrays.asList( "select", "update", "delete", "insert", "truncate", "drop", "execute", "exec", "declare", "union", - "create", "alter", "database", "table", "varchar", - "extractvalue", "concat", "benchmark", "sleep", "delay", - "waitfor", "pg_sleep", "information_schema", "sysobjects", - "load_file", "outfile", "dumpfile" + "create", "alter", "database", "table", + "extractvalue", "concat", "benchmark", "sleep", + "waitfor", "pg_sleep", "load_file", "outfile" )); /** @@ -349,5 +332,4 @@ public class XssSqlFilterProcessor extends AbstractProcessor { String wordBoundary = "\\b" + keyword + "\\b"; return Pattern.compile(wordBoundary).matcher(text).find(); } - } diff --git a/src/main/java/io/v/nutz/web/controllers/platform/AgendaController.java b/src/main/java/io/v/nutz/web/controllers/platform/AgendaController.java index 3f6de35..0685033 100644 --- a/src/main/java/io/v/nutz/web/controllers/platform/AgendaController.java +++ b/src/main/java/io/v/nutz/web/controllers/platform/AgendaController.java @@ -35,7 +35,7 @@ public class AgendaController { List list = new ArrayList<>(); list.add(new NutMap().addv("iconClass", "").addv("imgUrl", "/assets/platform/img/quickentry/member.png").addv("label", "会员管理").addv("url", "/platform/member/change/mange").addv("color", "#58ae62")); - list.add(new NutMap().addv("iconClass", "").addv("imgUrl", "/assets/platform/img/quickentry/proposal.png").addv("label", "提案管理").addv("url", "/platform/proposal/statistics/integrated").addv("color", "#a762c3")); +// list.add(new NutMap().addv("iconClass", "").addv("imgUrl", "/assets/platform/img/quickentry/proposal.png").addv("label", "提案管理").addv("url", "/platform/proposal/statistics/integrated").addv("color", "#a762c3")); list.add(new NutMap().addv("iconClass", "").addv("imgUrl", "/assets/platform/img/quickentry/activity.png").addv("label", "活动管理").addv("url", "/platform/trainSingUp/manage/activity/add").addv("color", "#4778cf")); list.add(new NutMap().addv("iconClass", "").addv("imgUrl", "/assets/platform/img/quickentry/welfare.png").addv("label", "福利慰问").addv("url", "/platform/welfare/mine").addv("color", "#c88f5c")); list.add(new NutMap().addv("iconClass", "").addv("imgUrl", "/assets/platform/img/quickentry/db.png").addv("label", "大病互助").addv("url", "/platform/sickHelp/mySubsidyRecord").addv("color", "#dd5858")); diff --git a/src/main/java/io/v/nutz/web/controllers/platform/sys/SysWechatController.java b/src/main/java/io/v/nutz/web/controllers/platform/sys/SysWechatController.java index 88948a7..e2c6297 100644 --- a/src/main/java/io/v/nutz/web/controllers/platform/sys/SysWechatController.java +++ b/src/main/java/io/v/nutz/web/controllers/platform/sys/SysWechatController.java @@ -98,8 +98,10 @@ public class SysWechatController { if (sysUser == null) { String s = Globals.AppDomain + "/platform/wechat/doLogin?openid=" + openid; if (StrUtil.isNotBlank(redirect)) { + System.out.println("2=====>" + redirect); s += "&redirect=" + URLEncoder.encode(redirect, StandardCharsets.UTF_8); } + System.out.println("3=====>" + s); return ">>:" + Globals.CasAddress + "/login?service=" + URLEncoder.encode(s, StandardCharsets.UTF_8); } diff --git a/src/main/resources/static/components/mobile/common/TrainDynamicForm.vue b/src/main/resources/static/components/mobile/common/TrainDynamicForm.vue index cce0927..2234d4c 100644 --- a/src/main/resources/static/components/mobile/common/TrainDynamicForm.vue +++ b/src/main/resources/static/components/mobile/common/TrainDynamicForm.vue @@ -19,6 +19,9 @@ :readonly="['SELECT'].includes(column.columnFormType)" :rules="[{ required: column.isRequired, message: (['SELECT'].includes(column.columnFormType) ? '请选择' : '请填写') + column.columnName }]" :required="column.isRequired" + :type="column.columnFormType === 'TEXTAREA' ? 'textarea' : (column.columnFormType === 'INT' ? 'number' : 'text')" + :autosize="column.columnFormType === 'TEXTAREA'" + rows="1" @click="selectFieldClick(column)" > diff --git a/src/main/resources/views/mobile/newHome.html b/src/main/resources/views/mobile/newHome.html index 9f60bb6..e53fb83 100644 --- a/src/main/resources/views/mobile/newHome.html +++ b/src/main/resources/views/mobile/newHome.html @@ -94,12 +94,12 @@ layout("/mobile/platform.html"){ isOpen: true, backGroundColor: '#58ae62' }, - { + /* { src: '/assets/platform/img/quickentry/proposal.png', text: '提案管理', isOpen: true, backGroundColor: '#a762c3' - }, + },*/ { src: '/assets/platform/img/quickentry/activity.png', text: '活动管理', diff --git a/src/main/resources/views/mobile/train/trainInfo.html b/src/main/resources/views/mobile/train/trainInfo.html index db50197..ef841ac 100644 --- a/src/main/resources/views/mobile/train/trainInfo.html +++ b/src/main/resources/views/mobile/train/trainInfo.html @@ -201,15 +201,15 @@ layout("/mobile/platform.html"){ 联 系 人: {{o.courseInstructor}} -
- 时  间: - 点我查看 - - {{o.courseTimeList[0].courseStartTime.substring(11, 19) + ' ~ ' + o.courseTimeList[0].courseEndTime.substring(11, 19)}} - -
+ + + + + + + + +
0 && this.mergeIndex === 1) { this.dialogVisible = true @@ -643,6 +663,19 @@ layout("/layouts/platform.html"){ this.$refs.audit.openView(id) }, + async autoOpenAuditPage() { + const queryString = window.location.search; + + const urlParams = new URLSearchParams(queryString); + const proposalId = urlParams.get('proposalId') + if(proposalId && proposalId != '') { + const res = await $.post('/platform/proposal/transact/case/case/detail?id=' + proposalId) + if(!res.data) return; + setTimeout(async ()=> { + await this.openAudit(proposalId, res.data) + }, 500) + } + }, async doAudit(flag) { let formValid = true this.$refs["auditForm"].validate(async valid => formValid = valid) @@ -735,6 +768,14 @@ layout("/layouts/platform.html"){ this.$notify.success({title: '成功', message: resp.msg}); this.pageData() this.$refs.guava.index() + + // 弹出发送待办提示 + const sendTask = resp.data.sendTask + console.log('sendTask', sendTask) + if(sendTask) { + await this.sendToDoTaskInfo() + } + } else { this.$notify.error({title: '失败', message: resp.msg}); } @@ -758,6 +799,8 @@ layout("/layouts/platform.html"){ this.noFilingReason = this.config.noFilingReason await proposal.initData(this) + // 打开审核界面 + await this.autoOpenAuditPage() }, watch: {} }) diff --git a/src/main/resources/views/platform/proposal/transact/caseCheck.html b/src/main/resources/views/platform/proposal/transact/caseCheck.html index 16134da..81dce61 100644 --- a/src/main/resources/views/platform/proposal/transact/caseCheck.html +++ b/src/main/resources/views/platform/proposal/transact/caseCheck.html @@ -215,6 +215,20 @@ layout("/layouts/platform.html"){ this.$refs.guava.edit() this.$refs.audit.openView(id) }, + // 自动打开审核页面 + async autoOpenAuditPage() { + const queryString = window.location.search; + + const urlParams = new URLSearchParams(queryString); + const proposalId = urlParams.get('proposalId') + if(proposalId != null && proposalId != '') { + const res = await $.post('/platform/proposal/transact/caseCheck/detail?proposalId=' + proposalId) + console.log(res) + setTimeout(async ()=> { + await this.openAudit(res.data) + }, 500) + } + }, async doAudit() { let formValid = true this.$refs["auditForm"].validate(async valid => formValid = valid) @@ -255,6 +269,8 @@ layout("/layouts/platform.html"){ }, async created() { await proposal.initData(this) + + await this.autoOpenAuditPage() } }) diff --git a/src/main/resources/views/platform/proposal/transact/delegation.html b/src/main/resources/views/platform/proposal/transact/delegation.html index cf550ed..8bffba4 100644 --- a/src/main/resources/views/platform/proposal/transact/delegation.html +++ b/src/main/resources/views/platform/proposal/transact/delegation.html @@ -231,6 +231,17 @@ layout("/layouts/platform.html"){ this.$refs['auditForm'].resetFields() } }, + async openAuditView() { + const queryString = window.location.search; + + const urlParams = new URLSearchParams(queryString); + const proposalId = urlParams.get('proposalId') + if(proposalId && proposalId !== '') { + setTimeout(()=> { + this.openAudit(proposalId) + }, 500) + } + }, async doAudit(flag) { this.submitDisabled = true let formValid = true @@ -290,6 +301,9 @@ layout("/layouts/platform.html"){ }, async created() { await proposal.initData(this) + + // 打开审批页面 + await this.openAuditView() } }) diff --git a/src/main/resources/views/platform/proposal/transact/executorRead.html b/src/main/resources/views/platform/proposal/transact/executorRead.html index a084977..2e7d4e9 100644 --- a/src/main/resources/views/platform/proposal/transact/executorRead.html +++ b/src/main/resources/views/platform/proposal/transact/executorRead.html @@ -16,15 +16,19 @@ layout("/layouts/platform.html"){ 批量审核 + 发送待办 + - + + + + + - + + + + - + + + +