This commit is contained in:
@jyuhsin
2025-12-10 14:08:18 +08:00
parent 3008813cd1
commit 58882c6fe6
6 changed files with 341 additions and 7 deletions
@@ -1,11 +1,16 @@
package io.v.nutz.zhgh.proposal.controller.transact;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.wizzer.framework.base.Result;
import io.v.nutz.base.annontation.ViReturn;
import io.v.nutz.base.utils.MsgApi;
import io.v.nutz.base.query.PageForm;
import io.v.nutz.base.utils.Roles;
import io.v.nutz.sys.models.Sys_user;
import io.v.nutz.sys.models.Sys_user_role;
import io.v.nutz.sys.services.SysLocalProcessService;
import io.v.nutz.web.commons.base.Globals;
import io.v.nutz.web.commons.utils.ShiroUtil;
import io.v.nutz.web.commons.slog.annotation.SLog;
import io.v.nutz.zhgh.proposal.constants.ProposalState;
@@ -22,9 +27,12 @@ import org.nutz.aop.interceptor.ioc.TransAop;
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.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
@@ -33,6 +41,8 @@ import org.nutz.mvc.annotation.Param;
import org.nutz.trans.Trans;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
@@ -271,4 +281,62 @@ public class ProposalBranchLeaderSuffixAuditController {
return null;
}
@At
@ViReturn
@RequiresPermissions("proposal.transact.branchLeaderSuffixAudit")
public Result sendNotify(@Param("sessionId") String sessionId, @Param("proposalId") String proposalId,
@Param("title") String title, @Param("content") String content) {
if (StrUtil.isBlank(sessionId)) {
return Result.error("教代会届次信息为空");
}
try {
// 找待校领导审核的提案
List<ProposalInfo> list = dao.query(
ProposalInfo.class,
Cnd.where("teacherMeetingId", "=", sessionId)
.andEX("id", "=", proposalId)
.and("stateCode", "=", ProposalState.LEADER_SUFFIX_AUDIT)
);
// 再找承办单位id
List<ProposalBranchLeaderSuffixAudit> auditList = dao.query(
ProposalBranchLeaderSuffixAudit.class,
Cnd.where("proposalId", "in", list.stream().map(ProposalInfo::getId).toList())
.and("isAudit", "=", 0)
);
if(Lang.isEmpty(auditList)) {
return Result.success();
}
List<String> undertakes = auditList.stream().map(ProposalBranchLeaderSuffixAudit::getUnderTakeId).distinct().toList();
// 根据承办单位id找承办单位
List<ProposalUndertake> undertakeList = dao.query(ProposalUndertake.class, Cnd.where("id", "in", undertakes));
// 根据承办单位id找校领导
List<Sys_user_role> userRoles = dao.query(Sys_user_role.class, Cnd.where("roleid", "=", Roles.XLD).and("cbdwid", "in", undertakes));
Map<String, List<Sys_user_role>> userRoleMap = userRoles.stream().collect(Collectors.groupingBy(Sys_user_role::getCbdwid));
// 找人
List<Sys_user> userList = dao.query(Sys_user.class, Cnd.where("id", "in", userRoles.stream().map(Sys_user_role::getUserId).toList()));
Map<String, Sys_user> userMap = userList.stream().collect(Collectors.toMap(Sys_user::getId, o -> o));
String linkUrl = Globals.AppDomain + "/platform/proposal/transact/branchLeaderSuffixAudit";
for (ProposalUndertake undertake : undertakeList) {
// 可能有多个
List<Sys_user_role> userRoleList = userRoleMap.get(undertake.getId());
for (Sys_user_role userRole : userRoleList) {
Sys_user user = userMap.get(userRole.getUserId());
String loginname = user.getLoginname();
if(content.contains("****") && StrUtil.isBlank(proposalId)) {
content = content.replace("****", undertake.getUnitName());
}
msgApi.sendMsg(List.of("DingTalk"), loginname, 2, title, content, "", linkUrl);
}
}
return Result.success();
} catch (Exception e) {
e.printStackTrace();
return Result.error();
}
}
}
@@ -2,6 +2,8 @@ package io.v.nutz.zhgh.proposal.controller.transact;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.wizzer.framework.base.Result;
import cn.wizzer.framework.page.Pagination;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
@@ -13,6 +15,7 @@ import io.v.nutz.base.utils.Html2Text;
import io.v.nutz.base.utils.MsgApi;
import io.v.nutz.base.dao.CndPlus;
import io.v.nutz.base.query.PageForm;
import io.v.nutz.base.utils.Roles;
import io.v.nutz.sys.services.SysLocalProcessService;
import io.v.nutz.web.commons.slog.annotation.SLog;
import io.v.nutz.zhgh.proposal.constants.ProposalConstant;
@@ -410,5 +413,45 @@ public class ProposalFeedbackScoreController {
return null;
}
@At
@ViReturn
@RequiresPermissions("proposal.transact.feedback")
public Result sendNotify(@Param("sessionId") String sessionId, @Param("proposalId") String proposalId,
@Param("title") String title, @Param("content") String content) {
if(StrUtil.isBlank(sessionId)) {
return Result.error("教代会届次信息为空");
}
try {
Sql sql = Sqls.create("""
SELECT
info.id,
info.proposalCode,
info.proposalName,
u.username,
u.loginname
FROM
proposal_info info
left join sys_user u on u.id = info.createUser
$condition
""");
Cnd cnd = Cnd.NEW();
cnd.and("info.teacherMeetingId", "=", sessionId);
cnd.and("info.stateCode", "=", ProposalState.FEEDBACKSCORE);
cnd.andEX("info.id", "=", proposalId);
cnd.asc("info.proposalCode");
sql.setCondition(cnd);
List<NutMap> list = proposalFeedbackService.listMap(sql);
String linkUrl = Globals.AppDomain + "/platform/proposal/transact/feedback";
for (NutMap user : list) {
String loginname = user.getString("loginname");
System.out.println(JSONUtil.toJsonStr(user));
msgApi.sendMsg(List.of("DingTalk"), loginname, 2, title, content, "", linkUrl);
}
return Result.success();
} catch (Exception e) {
e.printStackTrace();
return Result.error();
}
}
}
@@ -3,6 +3,9 @@ package io.v.nutz.zhgh.proposal.services.impl;
import cn.wizzer.framework.page.Pagination;
import io.v.nutz.base.query.PageForm;
import io.v.nutz.base.service.impl.ViServiceImpl;
import io.v.nutz.base.utils.Roles;
import io.v.nutz.sys.models.Sys_user_role;
import io.v.nutz.web.commons.utils.ShiroUtil;
import io.v.nutz.zhgh.proposal.constants.ProposalState;
import io.v.nutz.zhgh.proposal.models.ProposalReply;
import io.v.nutz.zhgh.proposal.models.ProposalSearch;
@@ -83,6 +86,13 @@ public class ProposalBranchLeaderSuffixAuditServiceImpl extends ViServiceImpl<Pr
LEFT JOIN proposal_reply pr ON pr.replyUnitId=pbla.underTakeId AND pbla.proposalId=pr.proposalId
$condition
""");
if(!ShiroUtil.hasAnyRoles("sysadmin, A06, tamange, jdh10")) {
List<Sys_user_role> userRoles = dao().query(Sys_user_role.class, Cnd.where("roleid", "=", Roles.XLD).and("userId", "=", ShiroUtil.getUserId()));
List<String> list = userRoles.stream().map(Sys_user_role::getCbdwid).distinct().toList();
cnd.and("pbla.underTakeId", "in", list);
}
cnd.and("pr.undertakeType", "=", 1);
cnd.desc("pbla.isMaster");
cnd.groupBy("pbla.proposalId");
@@ -6,10 +6,13 @@ layout("/layouts/platform.html"){
.el-select {
width: 100%;
}
.pro_table {
padding-left: 65px;
}
.tooltip-alert,.el-alert{
padding: 0;
margin-top: 6px;
}
</style>
<div id="app" v-cloak>
@@ -20,6 +23,10 @@ layout("/layouts/platform.html"){
<el-card shadow="never" class="mt10">
<table-tool label="分管领导审批办理" :app="this">
<template #func>
<el-button v-if="$auth.hasRole('sysadmin')" type="primary"
@click="openSendMsg(null, 'oneKey')" size="small">
一键提醒
</el-button>
</template>
</table-tool>
<el-table :data="tableData" align="center" header-align="center" row-key="replyId"
@@ -63,6 +70,10 @@ layout("/layouts/platform.html"){
v-if="!row.isAudit"
@click="openAudit(row)" type="primary" size="mini">审核
</el-button>
<el-button
v-if="!row.isAudit && $auth.hasRoleOr('sysadmin, A06, tamange, jdh10')"
@click="openSendMsg(row, 'normal')" type="warning" size="mini">催办
</el-button>
</template>
</el-table-column>
</el-table>
@@ -136,12 +147,55 @@ layout("/layouts/platform.html"){
</template>
</guava>
<el-dialog
:close-on-click-modal="false"
:visible.sync="sendMsgDialogVisible"
title="请在下方填写需要发送的内容"
width="50%"
>
<el-form :model="sendFormData" label-width="80px" ref="sendForm">
<el-form-item label="提案名称" prop="userInfo" v-if="sendFormData.proposalName">
<el-input placeholder="请选择提案名称" readonly v-model="sendFormData.proposalName"></el-input>
</el-form-item>
<el-form-item
:rules="[{required: true, message: '请输入发送标题', trigger: ['blur', 'change']}]"
label="发送标题"
prop="title">
<el-input
placeholder="请输入发送标题"
v-model="sendFormData.title">
</el-input>
</el-form-item>
<el-form-item
:rules="[{required: true, message: '请选择发送内容', trigger: ['blur', 'change']}]"
label="发送内容"
prop="content">
<el-input
:rows="6"
placeholder="请输入内容"
type="textarea"
v-model="sendFormData.content">
</el-input>
<el-alert
v-if="sendFormData.content.includes('****')"
class="tooltip-alert"
title="****会自动替换为每条提案的承办单位名称,请勿修改和删除!!!"
type="warning">
</el-alert>
</el-form-item>
</el-form>
<span class="dialog-footer" slot="footer">
<el-button @click="sendMsgDialogVisible = false">取 消</el-button>
<el-button @click="sendMsg" type="primary">确 定</el-button>
</span>
</el-dialog>
</div>
<script>
<!--#include("/platform/proposal/include/proposal_include.js"){}#-->
const vue = new Vue({
el: '#app',
mixins: [initTableMixins],
@@ -191,10 +245,64 @@ layout("/layouts/platform.html"){
},
isNode: false,
oneKeyRemindDialogVisible: false,
oneKeyTableData: []
oneKeyTableData: [],
/**
* 发送通知相关
*/
sendMsgDialogVisible: false,
sendFormData: {
sessionId: "",
proposalId: "",
proposalName: "",
title: "提案审批通知",
content: "尊敬的校领导,****有一个承办提案需要分管校领导审核同意,请点击审核。"
},
}
},
methods: {
openSendMsg(row, type) {
this.sendFormData.proposalId = row ? row.id : null
this.sendFormData.proposalName = row ? row.proposalName : null
if(type === 'normal') {
this.sendFormData.content = this.sendFormData.content.replace('****', row ? row.underTakeNames : '')
} else {
this.sendFormData.content = "尊敬的校领导,****有一个承办提案需要分管校领导审核同意,请点击审核。"
}
this.sendMsgDialogVisible = true
},
async sendMsg() {
const valid = await this.$refs["sendForm"].validate()
if (!valid) return
const confirm = await this.$confirm("您确定要发送信息吗?", "提示", {
confirmButtonText: "确定",
cancelButtonTest: "取消",
type: "warning"
})
if (confirm === "confirm") {
const loading = this.$loading({
lock: true,
text: "加载中,请稍后...",
spinner: "el-icon-loading",
background: "rgba(0, 0, 0, 0.7)"
})
const resp = await $.post("/platform/proposal/transact/branchLeaderSuffixAudit/sendNotify", {
sessionId: this.pageForm.meetingId,
proposalId: this.sendFormData.proposalId,
title: this.sendFormData.title,
content: this.sendFormData.content
})
loading.close()
if (resp.code === 0) {
this.sendMsgDialogVisible = false
this.$message.success(resp.msg)
} else {
this.$message.warning(resp.msg)
}
}
},
async rollback(row) {
const confirm = await this.$confirm('您确定要撤回吗?', '提示', {
confirmButtonText: '确定',
@@ -11,11 +11,15 @@ layout("/layouts/platform.html"){
<div id="app" v-cloak>
<guava ref="guava">
<template>
<proposal-search :page="pageForm" @search="doSearch" title="反馈"></proposal-search>
<proposal-search :page="pageForm" @search="doSearch" title="反馈" ref="searchRef"></proposal-search>
<el-card shadow="never" class="mt10">
<table-tool label="反馈评价" :app="this">
<template #func>
<el-button v-if="$auth.hasRole('sysadmin')" type="primary"
@click="openSendMsg" size="small">
一键提醒
</el-button>
<!-- <el-button @click="oneKeyRemind" size="small" type="primary"-->
<!-- v-if="(${@shiro.hasRole('T01') || @shiro.hasRole('sysadmin')} && pageForm.isAudit==false)"-->
<!-- >一键提醒-->
@@ -58,6 +62,9 @@ layout("/layouts/platform.html"){
<el-button v-if="[proposal.FEEDBACKSCORE].includes(row.stateCode)"
@click="openFeedback(row)" size="mini" type="primary">反馈
</el-button>
<el-button v-if="[proposal.FEEDBACKSCORE].includes(row.stateCode) && $auth.hasRoleOr('sysadmin, A06, tamange, jdh10')"
type="warning" @click="openSendMsg(row)" size="mini">催办
</el-button>
<!-- <el-button v-if="row.canRollBack" @click="doWithdraw(row)" size="mini"-->
<!-- type="danger">撤回-->
<!-- </el-button>-->
@@ -147,6 +154,45 @@ layout("/layouts/platform.html"){
<el-button @click="confirmOneKeyRemind" type="primary">确定</el-button>
</el-row>
</el-dialog>
<el-dialog
:close-on-click-modal="false"
:visible.sync="sendMsgDialogVisible"
title="请在下方填写需要发送的内容"
width="50%"
>
<el-form :model="sendFormData" label-width="80px" ref="sendForm">
<el-form-item label="提案名称" prop="userInfo" v-if="sendFormData.proposalName">
<el-input placeholder="请选择提案名称" readonly v-model="sendFormData.proposalName"></el-input>
</el-form-item>
<el-form-item
:rules="[{required: true, message: '请输入发送标题', trigger: ['blur', 'change']}]"
label="发送标题"
prop="title">
<el-input
placeholder="请输入发送标题"
v-model="sendFormData.title">
</el-input>
</el-form-item>
<el-form-item
:rules="[{required: true, message: '请选择发送内容', trigger: ['blur', 'change']}]"
label="发送内容"
prop="content">
<el-input
:rows="6"
placeholder="请输入内容"
type="textarea"
v-model="sendFormData.content">
</el-input>
</el-form-item>
</el-form>
<span class="dialog-footer" slot="footer">
<el-button @click="sendMsgDialogVisible = false">取 消</el-button>
<el-button @click="sendMsg" type="primary">确 定</el-button>
</span>
</el-dialog>
</div>
<script>
@@ -214,10 +260,69 @@ layout("/layouts/platform.html"){
sign: [{required: true, message: '请使用【手机钉钉】扫描二维码进行签字', trigger: ['blur', 'change']}]
},
oneKeyRemindDialogVisible: false,
oneKeyTableData: []
oneKeyTableData: [],
/**
* 发送通知相关
*/
sendMsgDialogVisible: false,
sendFormData: {
sessionId: "",
proposalId: "",
proposalName: "",
title: "提案反馈通知",
content: "尊敬的教代会代表,您在第jdhjs届教代会第jdhcs次会议上提交的提案,相关部门已作出办理回复,请点击评价反馈。"
},
}
},
methods: {
async openSendMsg(row) {
if(!this.$refs.searchRef.allJdhOptions) {
this.$message.warning('教代会信息为空')
return
}
const jdh = this.$refs.searchRef.allJdhOptions.find(o => o.id === this.pageForm.meetingId)
if(!jdh) {
this.$message.warning('教代会信息为空')
return
}
this.sendFormData.content = this.sendFormData.content.replace('jdhjs', jdh.jdhjs).replace('jdhcs', jdh.jdhcs)
this.sendFormData.proposalId = row ? row.id : null
this.sendFormData.proposalName = row ? row.proposalName : null
this.sendMsgDialogVisible = true
},
async sendMsg() {
const valid = await this.$refs["sendForm"].validate()
if (!valid) return
const confirm = await this.$confirm("您确定要发送信息吗?", "提示", {
confirmButtonText: "确定",
cancelButtonTest: "取消",
type: "warning"
})
if (confirm === "confirm") {
const loading = this.$loading({
lock: true,
text: "加载中,请稍后...",
spinner: "el-icon-loading",
background: "rgba(0, 0, 0, 0.7)"
})
const resp = await $.post("/platform/proposal/transact/feedback/sendNotify", {
sessionId: this.pageForm.meetingId,
proposalId: this.sendFormData.proposalId,
title: this.sendFormData.title,
content: this.sendFormData.content
})
loading.close()
if (resp.code === 0) {
this.sendMsgDialogVisible = false
this.$message.success(resp.msg)
} else {
this.$message.warning(resp.msg)
}
}
},
async oneKeyRemind() {
const {meetingId} = this.pageForm
if (!meetingId) {
@@ -414,7 +414,7 @@ layout("/layouts/platform.html"){
async sendMsg() {
const valid = await this.$refs["sendForm"].validate()
if (!valid) return
const confirm = await this.$confirm("您确定要发送信息吗?", "提示", {
const confirm = await this.$confirm("您确定要发送信息吗?", "提示", {
confirmButtonText: "确定",
cancelButtonTest: "取消",
type: "warning"