This commit is contained in:
@jyuhsin
2025-09-23 10:43:59 +08:00
parent af146d6c9b
commit c3108c879f
2 changed files with 364 additions and 0 deletions
@@ -0,0 +1,138 @@
package com.budwk.app.zhgh.democratic.proposal.controller.senior;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.result.Result;
import com.budwk.app.bpm.models.BpmProcessTask;
import com.budwk.app.flow.entity.ProcessTask;
import com.budwk.app.flow.entity.ProcessTaskActor;
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
import com.budwk.app.web.commons.auth.utils.AuthUtil;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.dayofficework.message.service.GlobalMessageSendService;
import com.budwk.app.zhgh.democratic.proposal.param.ProposalSearchParam;
import com.budwk.app.zhgh.democratic.proposal.service.common.ProposalCommonService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.nutz.aop.interceptor.ioc.TransAop;
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.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import javax.validation.Valid;
import java.util.List;
/**
* @ClassName ProposalExpeditingController
* @Author JyuHsin
* @Date 2025/9/23 9:38
* @Version 1.0
* @Description TODO
*/
@IocBean
@At("/platform/senior/expediting")
@Ok("json:full")
@Api(tags = "提案-高级管理-提案催办")
public class ProposalExpeditingController {
@Inject
private Dao dao;
@Inject
private ProposalCommonService proposalCommonService;
@Inject
private GlobalMessageSendService globalMessageSendService;
@At("")
@Ok("beetl:/platform/zhgh/democratic/proposal/senior/expediting/index.html")
@SaCheckPermission("proposal.senior.expediting")
public void index() {
}
@At
@SaCheckPermission("proposal.senior.expediting")
@ApiOperation("分页列表")
public Result pageData(@Valid ProposalSearchParam pageForm) {
Sql sql = Sqls.create("""
SELECT
info.*,
type.name AS typeName,
tcs.fullName AS sessionName,
tcd.`name` AS delegationName,
ins.id AS instanceId,
ins.businessNo,
ins.state instanceState,
ins.variable instanceVariable,
ins.processDefineId instanceProcessDefineId,
t.id taskId,
t.taskName AS taskKey,
t.displayName taskName,
t.taskType,
t.performType taskPerformType,
t.taskState,
t.finishTime,
t.taskParentId,
t.variable taskVariable,
IFNULL(GROUP_CONCAT(DISTINCT nt.displayName),'结束') curTaskName,
IFNULL(GROUP_CONCAT(DISTINCT nt.taskName),'结束') curTaskKey,
CASE WHEN t.taskState = 20 AND ( rt.id IS NULL OR rt.taskState = 10 ) THEN 1 ELSE 0 END AS canRevoke,
t.variable->>'$.unitName' AS taskUnitName,
IF(JSON_EXTRACT(t.variable, '$.isMaster') = true, 1, 0) AS taskIsMaster
FROM
wf_process_task t
LEFT JOIN wf_process_instance ins ON ins.id = t.processInstanceId
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = t.id
LEFT JOIN wf_process_task nt ON nt.processInstanceId = ins.id AND nt.taskState = 10
LEFT JOIN wf_process_task rt ON rt.processInstanceId = ins.id AND rt.taskParentId = t.id
LEFT JOIN proposal_info info ON info.id = ins.businessNo
LEFT JOIN proposal_type type on type.id = info.typeId
LEFT JOIN teacher_congress_session tcs on tcs.id = info.sessionId
LEFT JOIN teacher_congress_delegation tcd on tcd.id = info.delegationId
$condition
""");
Cnd cnd = Cnd.NEW();
cnd.and("t.taskName", "in", List.of("85cf23da-2dd5-4007-a1e9-bd9bfddc68f0", "c9a1586e-272b-41b8-b438-0be9f9e3781d","5ed5a1be-0cd3-4b47-a0d5-238d53b61f34"));
if (!AuthUtil.hasRole(RoleConstant.SYSADMIN.name())) {
cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId()));
}
cnd.and("t.taskState", "=", ProcessTaskStateEnum.DOING.getCode());
ProposalSearchParam.buildSearch(cnd, pageForm);
cnd.groupBy("t.id");
cnd.desc("t.createdAt");
sql.setCondition(cnd);
Pagination pagination = proposalCommonService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
return Result.success(pagination);
}
@At
@ApiOperation("提案催办")
@Aop(TransAop.READ_COMMITTED)
@SaCheckPermission("proposal.senior.expediting")
@SLog(tag = "提案-高级管理", msg = "提案催办")
public Result submit(@Param(value = "taskIds") String[] taskIds,
@Param(value = "content") String content) {
for (String taskId : taskIds) {
ProcessTask task = dao.fetch(ProcessTask.class, taskId);
List<ProcessTaskActor> taskActors = dao.query(ProcessTaskActor.class, Cnd.where(ProcessTaskActor::getProcessTaskId, "=", task.getId()));
List<String> list = taskActors.stream().map(ProcessTaskActor::getActorId).toList();
String message = "您有一条待办任务," + content;
globalMessageSendService.sendMessage(task.getDisplayName(), message, 2, list, null);
}
return Result.success();
}
}
@@ -0,0 +1,226 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app">
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select @change="meetingChange" clearable filterable placeholder="请选择所属教代会"
v-model="pageForm.sessionId">
<el-option :key="item.id" :label="item.fullName" :value="item.id"
v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案编号">
<el-input v-model="pageForm.code" placeholder="请输入提案编号" @keyup.enter.native="doSearch" clearable
style="width: 100%"></el-input>
</search-item>
<search-item label="提案名称">
<el-input v-model="pageForm.name" placeholder="请输入提案名称" @keyup.enter.native="doSearch" clearable
style="width: 100%"></el-input>
</search-item>
<search-item label="提案人姓名">
<el-input
@keyup.enter.native="doSearch"
clearable
placeholder="请输入提案人姓名"
v-model="pageForm.createUserName"
style="width: 100%"
></el-input>
</search-item>
<search-item label="提案人工号">
<el-input
@keyup.enter.native="doSearch"
clearable
placeholder="请输入提案人工号"
v-model="pageForm.createUserLoginName"
style="width: 100%"
></el-input>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool label="未答复列表">
<el-button type="primary" size="small" @click="onBatchHandle">
<i class="el-icon-s-promotion"></i>
批量催办
</el-button>
</table-tool>
<el-table :data="tableData" @sort-change="pageOrder" style="width: 100%"
@selection-change="handleSelectionChange" row-key="id">
<el-table-column type="selection" reserve-selection width="55"></el-table-column>
<el-table-column label="序号" width="50" type="index" :index="indexMethod"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:key="column.prop"
:width="column.width"
:sortable="column.sortable"
align="center"
header-align="center"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template v-slot="{ row }" v-if="column.prop === 'caseFilingResult'">
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_RESULT" :value="row.caseFilingResult"></dict-tag>
</template>
<template v-slot="{ row }" v-else-if="column.prop === 'instanceState'">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="300px">
<template slot-scope="{row}">
<el-button @click="openView(row)" size="mini" type="primary">查看</el-button>
<el-button @click="onHandle(row)" size="mini" type="primary">催办</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #view>
<proposal-info ref="proposalInfoRef"></proposal-info>
</template>
<template #edit>
<div class="process-title">所选提案列表</div>
<el-table :data="chooseTableData" style="width: 100%" max-height="600">
<el-table-column label="序号" width="50" type="index" :index="indexMethod"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:key="column.prop"
:width="column.width"
:sortable="column.sortable"
align="center"
header-align="center"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template v-slot="{ row }" v-if="column.prop === 'caseFilingResult'">
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_RESULT" :value="row.caseFilingResult"></dict-tag>
</template>
<template v-slot="{ row }" v-else-if="column.prop === 'instanceState'">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
</el-table-column>
</el-table>
<div class="process-title">催办内容</div>
<el-input v-model="content" type="textarea" :rows="4" placeholder="请输入催办内容" max="500"></el-input>
<el-row type="flex" justify="end" class="mt20">
<el-button @click="$refs.guava.index()">取消</el-button>
<el-button @click="onSubmit" type="primary">提交</el-button>
</el-row>
</template>
</guava>
</div>
<script>
<!--#include('../../common/info.js'){}#-->
new Vue({
el: "#app",
store,
dicts: ["PROPOSAL_CASE_FILING_RESULT","PROPOSAL_REPLY_IMPLEMENT"],
mixins: [initTableMixins],
components: {
"proposal-info": PROPOSAL_INFO
},
data() {
return {
pageForm: {},
formData: {},
sessionOptions: [],
delegationOptions: [],
tableColumns: [
{prop: 'code', label: '提案编号'},
{prop: 'name', label: '提案名称'},
{prop: 'typeName', label: '提案类别'},
{prop: 'delegationName', label: '代表团'},
{prop: 'caseFilingResult', label: '立案结果'},
{prop: 'curTaskName', label: '当前节点'},
{prop: 'taskUnitName', label: '承办单位'},
{prop: 'taskName', label: '承办类型'},
{prop: 'instanceState', label: '流程状态'},
],
chooseTableData: [],
content: '',
}
},
methods: {
onSubmit() {
if(!this.content) {
this.$message.warning('请输入催办内容')
return
}
this.$confirm("您选择了" + this.chooseTableData.length + "条提案,确定要催办吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/platform/senior/expediting/submit", {
taskIds: JSON.stringify(this.chooseTableData.map(o => o.taskId)),
content: this.content
}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.pageData()
}
})
})
},
onBatchHandle() {
if(this.chooseTableData.length === 0) {
this.$message.warning('请先选择需要催办的提案')
return
}
this.$refs.guava.edit()
},
onHandle(row) {
this.chooseTableData = []
this.chooseTableData.push(row)
this.$refs.guava.edit()
},
handleSelectionChange(val) {
this.chooseTableData = val
},
openView(row) {
this.$refs.guava.view(() => {
this.$refs.proposalInfoRef.onOpen(row)
})
},
// 教代会
async meetingChange(val) {
this.doSearch()
},
// 查询开启的教代会
listOpenSession() {
this.$axios.post("/platform/proposal/common/listOpenSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions) {
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
this.pageData()
this.listDelegation()
}
}
})
}
},
created() {
this.pageData()
this.listOpenSession()
}
})
</script>
<!--#
}
#-->