bug优化、提案催办

This commit is contained in:
Paidax
2025-09-09 14:39:09 +08:00
parent b2ee7f9008
commit 99a2748330
9 changed files with 193 additions and 37 deletions
@@ -1,16 +1,10 @@
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 com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.policy.HackLoopTableRenderPolicy;
import io.v.nutz.base.annontation.ViReturn;
import io.v.nutz.base.utils.DateUtil;
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.base.utils.*;
import io.v.nutz.base.query.PageForm;
import io.v.nutz.web.commons.slog.annotation.SLog;
import io.v.nutz.zhgh.proposal.constants.ProposalState;
@@ -36,12 +30,7 @@ import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import org.nutz.trans.Trans;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;
/**
@@ -73,6 +62,9 @@ public class ProposalReplyController {
@Inject
private ProposalReplyService replyService;
@Inject
private MsgApi msgApi;
@At("")
@Ok("beetl:/platform/proposal/transact/reply.html")
@RequiresPermissions("proposal.transact.reply")
@@ -82,10 +74,10 @@ public class ProposalReplyController {
@At
@ViReturn
@RequiresPermissions("proposal.transact.reply")
public Object pageData(PageForm page, ProposalSearch search) {
public Object pageData(PageForm page, ProposalSearch search, Boolean listButtonTypeAdmin) {
Cnd cnd = Cnd.NEW();
proposalInfoService.sortAndSearch(cnd, page, search);
if (ShiroUtil.hasAnyRoles("sysadmin, tamange,A06")) {
if (ShiroUtil.hasAnyRoles("sysadmin, tamange, jdh10, A06") && listButtonTypeAdmin) {
return proposalReplyService.pageDataBySuperAdmin(page, cnd, search);
} else {
return proposalReplyService.pageDataByUnitAdmin(page, cnd, search);
@@ -194,4 +186,57 @@ public class ProposalReplyController {
proposalReplyService.forwardReply(replyForwardList);
return null;
}
@At
@ViReturn
@RequiresPermissions("proposal.transact.reply")
public Result sendNotify(@Param("sessionId") String sessionId, @Param("proposalId") String proposalId,
@Param("title") String title, @Param("content") String content) {
try {
Sql sql = Sqls.create("""
SELECT
info.proposalName,
pu.unitName,
r.replyUnitId,
r.proposalId,
u.username,
u.loginname
FROM
proposal_reply r
LEFT JOIN sys_user_role sur ON sur.cbdwid = r.replyUnitId
AND sur.roleId = @roleId
LEFT JOIN sys_user u ON u.id = sur.userId
LEFT JOIN proposal_undertake pu ON pu.id = r.replyUnitId
LEFT JOIN proposal_info info ON info.id = r.proposalId
WHERE
r.proposalId IN (SELECT id FROM proposal_info WHERE teacherMeetingId = @sessionId)
AND r.isReply = 0
and r.undertakeType = 1
and info.resultCode in ('determine','opinion')
$sql
GROUP BY
r.replyUnitId
""").setParam("roleId", Roles.CONTRACTOR_PERSON).setParam("sessionId", sessionId);
if (StrUtil.isNotBlank(proposalId)) {
sql.setVar("sql", " AND info.id = '%s'".formatted(proposalId));
}
sql.setCallback(Sqls.callback.maps());
dao.execute(sql);
List<NutMap> replyList = (List<NutMap>) sql.getResult();
String linkUrl = Globals.AppDomain + "/platform/proposal/transact/reply";
for (NutMap reply : replyList) {
String loginname = reply.getString("loginname");
System.out.println(JSONUtil.toJsonStr(reply));
msgApi.sendMsg(List.of("DingTalk"), loginname, 2, title, content, "", linkUrl);
}
return Result.success();
} catch (Exception e) {
e.printStackTrace();
return Result.error();
}
}
}
@@ -95,7 +95,7 @@
<dict-select v-model="pageForm.personType" style="width: 100%" clearable
placeholder="人员类型"
@change="doSearch"
code="UserType"></dict-select>
code="PERSON_TYPE"></dict-select>
</div>
</div>
@@ -105,7 +105,7 @@
<dict-select v-model="pageForm.userState" style="width: 100%" clearable
placeholder="在职状态"
@change="doSearch"
code="UserState"></dict-select>
code="USER_STATE"></dict-select>
</div>
</div>
@@ -835,8 +835,8 @@ module.exports = {
}
await this.flushUnits()
await this.getActivityGroup()
this.personTypeOptions = await getDictOptions("UserType")
this.userStateOptions = await getDictOptions("UserState")
this.personTypeOptions = await getDictOptions("PERSON_TYPE")
this.userStateOptions = await getDictOptions("USER_STATE")
await this.getMenuOptions()
await this.pageData()
},
@@ -192,7 +192,7 @@
v-for="item in activityGroupList"></el-option>
</el-select>
</div>
<div v-if="type !== 40003">
<div v-if="$auth.hasRoleOr('sysadmin, A06')">
<el-button
@click="$refs.drawerUserScope.userScopeDialog = true"
type="primary">设置
@@ -657,7 +657,10 @@
></drawer-user-scope>
</div>
<script src="${base!}/assets/platform/js/util/commonUtil.js"></script>
<script type="text/javascript">
Vue.prototype.$auth = commonUtil.authService()
</script>
<script>
let marker = null
let map = null
@@ -1138,7 +1141,7 @@
},
async getActivityGroup() {
const resp = await $.get('/platform/activity/basic/scope/getActivityUserScopeGroup')
if (type === 40003) {
if (type === 40003 && !this.$auth.hasRoleOr('sysadmin, A06')) {
this.activityGroupList = resp.data.filter(v => v.groupId === 6)
} else {
this.activityGroupList = resp.data
@@ -15,9 +15,9 @@ layout("/layouts/platform.html"){
<el-card shadow="never" class="mt10">
<table-tool label="提案列表" :app="this">
<template #tips>
</template>
<template #func>
<el-button v-if="pageForm.listButtonTypeAdmin" type="primary" @click="openSendMsg" size="small">一键提醒</el-button>
<el-button type="warning" @click="changeListType" size="small">切换成“{{pageForm.listButtonTypeAdmin ? '承办单位' : '管理员'}}”列表</el-button>
</template>
</table-tool>
<el-table ref="proTable"
@@ -73,11 +73,13 @@ layout("/layouts/platform.html"){
<!-- </template>-->
</el-table-column>
<el-table-column :width="200" align="center" fixed="right"
<el-table-column :width="250" align="center" fixed="right"
header-align="center"
label="操作">
<template scope="{row}">
<el-button @click="openView(row)" size="mini" type="primary">查看</el-button>
<el-button v-if="!row.isReply && $auth.hasRoleOr('sysadmin, A06, tamange, jdh10')"
type="warning" @click="openSendMsg(row)" size="mini">催办</el-button>
<el-button v-if="!row.isReply" type="primary" @click="openAudit(row)" size="mini">办理
</el-button>
</template>
@@ -205,6 +207,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>
@@ -260,7 +301,11 @@ layout("/layouts/platform.html"){
{prop: 'isReply', label: '办理状态', sortable: false},
],
submitDisabled: false,
pageForm: {searchName: 'proposalName', isAudit: false},
pageForm: {
searchName: 'proposalName',
isAudit: false,
listButtonTypeAdmin: true
},
formData: {
username: "${@shiro.getPrincipalProperty('username')}",
replyTime: moment().format('YYYY-MM-DD'),
@@ -281,10 +326,65 @@ layout("/layouts/platform.html"){
forwardUserSelection: null,
implementStateOptions: [],
oneKeyRemindDialogVisible: false,
oneKeyTableData: []
oneKeyTableData: [],
/**
* 发送通知相关
*/
sendMsgDialogVisible: false,
sendFormData: {
sessionId: '',
proposalId: '',
proposalName: '',
title: '提案承办通知',
content: '您部门有新交办的提案,请及时查收处理,并按规定于收到此信息之日起2个月内办结。'
},
}
},
methods: {
async openSendMsg(row) {
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/reply/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)
}
}
},
// 列表类型切换
changeListType(){
this.pageForm.listButtonTypeAdmin = !this.pageForm.listButtonTypeAdmin
this.pageData()
},
async oneKeyRemind() {
const {meetingId} = this.pageForm
if (!meetingId) {
@@ -499,8 +599,16 @@ layout("/layouts/platform.html"){
}
},
async created() {
await proposal.initData(this)
this.implementStateOptions = await getDictByCode('proposal_reply_result')
if (window.innerWidth < 768 && location.pathname === '/platform/proposal/transact/reply') {
this.$confirm('请您使用电脑端访问此界面,以获取更好的体验!', '提示', {
confirmButtonText: '确定',
cancelButtonTest: '取消',
type: 'warning'
})
} else {
await proposal.initData(this)
this.implementStateOptions = await getDictByCode('proposal_reply_result')
}
}
})
</script>
@@ -140,7 +140,7 @@ layout("/layouts/platform.html"){
<!-- <div class="search-item-option">-->
<!-- <dict-select v-model="pageForm.personType" style="width: 100%" clearable-->
<!-- placeholder="人员类型"-->
<!-- code="UserType"></dict-select>-->
<!-- code="PERSON_TYPE"></dict-select>-->
<!-- </div>-->
<!-- </div>-->
@@ -149,7 +149,7 @@ layout("/layouts/platform.html"){
<!-- <div class="search-item-option">-->
<!-- <dict-select v-model="pageForm.userState" style="width: 100%" clearable-->
<!-- placeholder="在职状态"-->
<!-- code="UserState"></dict-select>-->
<!-- code="USER_STATE"></dict-select>-->
<!-- </div>-->
<!-- </div>&ndash;&gt;-->
@@ -89,7 +89,7 @@ layout("/layouts/platform.html"){
<dict-select v-model="pageForm.personType" style="width: 100%"
clearable
placeholder="人员类型"
code="UserType"></dict-select>
code="PERSON_TYPE"></dict-select>
</div>
</div>
@@ -99,7 +99,7 @@ layout("/layouts/platform.html"){
<dict-select v-model="pageForm.userState" style="width: 100%"
clearable
placeholder="在职状态"
code="UserState"></dict-select>
code="USER_STATE"></dict-select>
</div>
</div>
</template>
@@ -85,7 +85,7 @@ layout("/layouts/platform.html"){
<div class="search-item">
<div class="search-item-label">人员类型:</div>
<div class="search-item-option">
<dict-select clearable code="UserType"
<dict-select clearable code="PERSON_TYPE"
placeholder="人员类型"
style="width: 100%"
v-model="pageForm.personType"></dict-select>
@@ -95,7 +95,7 @@ layout("/layouts/platform.html"){
<div class="search-item">
<div class="search-item-label">在职状态:</div>
<div class="search-item-option">
<dict-select clearable code="UserState"
<dict-select clearable code="USER_STATE"
placeholder="在职状态"
style="width: 100%"
v-model="pageForm.userState"></dict-select>
@@ -85,7 +85,7 @@ layout("/layouts/platform.html"){
<div class="search-item">
<div class="search-item-label">人员类型:</div>
<div class="search-item-option">
<dict-select clearable code="UserType"
<dict-select clearable code="PERSON_TYPE"
placeholder="人员类型"
style="width: 100%"
v-model="pageForm.personType"></dict-select>
@@ -95,7 +95,7 @@ layout("/layouts/platform.html"){
<div class="search-item">
<div class="search-item-label">在职状态:</div>
<div class="search-item-option">
<dict-select clearable code="UserState"
<dict-select clearable code="USER_STATE"
placeholder="在职状态"
style="width: 100%"
v-model="pageForm.userState"></dict-select>