新增申诉管理模块: 新增角色(申诉处理委员会成员);

This commit is contained in:
dd3s_206
2026-05-21 16:56:43 +08:00
parent 9bd1e865b9
commit 55433b2a8e
26 changed files with 2393 additions and 3 deletions
@@ -25,6 +25,7 @@ RoleConstant {
SCHOOL_UNION_WC_ADMIN("校工会工代会管理员"), SCHOOL_UNION_WC_ADMIN("校工会工代会管理员"),
SCHOOL_UNION_DC_ADMIN("校工会民主管理员"), SCHOOL_UNION_DC_ADMIN("校工会民主管理员"),
SCHOOL_UNION_PROPOSAL_ADMIN("校工会提案管理员"), SCHOOL_UNION_PROPOSAL_ADMIN("校工会提案管理员"),
APPEAL_COMMITTEE_MEMBER("申诉处理委员会成员"),
SCHOOL_UNION_CLUB_ADMIN("校工会协会管理员"), SCHOOL_UNION_CLUB_ADMIN("校工会协会管理员"),
SCHOOL_UNION_ACTIVITY_ADMIN("校工会活动管理员"), SCHOOL_UNION_ACTIVITY_ADMIN("校工会活动管理员"),
SCHOOL_UNION_ARTICLE_CLUB_ADMIN("校工会协会新闻审批管理员"), SCHOOL_UNION_ARTICLE_CLUB_ADMIN("校工会协会新闻审批管理员"),
@@ -61,6 +61,9 @@ public class FlowEngineImpl implements FlowEngine {
@Override @Override
public ProcessInstance startProcessInstanceByKey(String key, String businessKey, String operator, Dict args) { public ProcessInstance startProcessInstanceByKey(String key, String businessKey, String operator, Dict args) {
ProcessDefine define = processDefineService.getLastByName(key); ProcessDefine define = processDefineService.getLastByName(key);
if (define == null) {
throw new BaseException("流程定义不存在或未启用:" + key);
}
return startProcessInstanceById(define.getId(), businessKey, operator, args); return startProcessInstanceById(define.getId(), businessKey, operator, args);
} }
@@ -0,0 +1,53 @@
package com.budwk.app.flow.handler;
import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.exception.BaseException;
import com.budwk.app.flow.engine.AssignmentHandler;
import com.budwk.app.flow.engine.core.Execution;
import com.budwk.app.flow.engine.core.ServiceContext;
import com.budwk.app.flow.engine.model.TaskModel;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.lang.Lang;
import java.util.List;
/**
* 获取申诉处理委员会成员
*/
public class FlowAppealCommitteeAssignmentHandler implements AssignmentHandler {
@Override
public List<String> assign(TaskModel model, Execution execution) {
Dao dao = ServiceContext.find(Dao.class);
Sql sql = Sqls.create("""
SELECT
userRole.userId
FROM
`sys_user_role` userRole
LEFT JOIN sys_role role ON role.id = userRole.roleId
WHERE
role.`code` = @roleCode
GROUP BY
userRole.userId
""").setParam("roleCode", RoleConstant.APPEAL_COMMITTEE_MEMBER.name());
sql.setCallback(Sqls.callback.strList());
dao.execute(sql);
List<String> userIds = sql.getList(String.class);
if (Lang.isEmpty(userIds)) {
throw new BaseException("申诉处理委员会成员没有设置,请联系管理员!");
}
return userIds;
}
@Override
public String getMessage() {
return "申诉处理委员会成员";
}
@Override
public int getOrder() {
return 10;
}
}
@@ -0,0 +1,54 @@
package com.budwk.app.flow.handler;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.exception.BaseException;
import com.budwk.app.flow.engine.AssignmentHandler;
import com.budwk.app.flow.engine.core.Execution;
import com.budwk.app.flow.engine.core.ServiceContext;
import com.budwk.app.flow.engine.model.TaskModel;
import com.budwk.app.sys.models.Sys_role;
import com.budwk.app.sys.models.Sys_user_role;
import com.budwk.app.sys.services.SysRoleService;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.lang.Lang;
import java.util.List;
/**
* 获取被申诉单位分工会管理员
*/
public class FlowAppealDefendantUnitAssignmentHandler implements AssignmentHandler {
@Override
public List<String> assign(TaskModel model, Execution execution) {
Dao dao = ServiceContext.find(Dao.class);
SysRoleService sysRoleService = ServiceContext.find(SysRoleService.class);
String unitId = StrUtil.blankToDefault(execution.getArgs().getStr("appealDefendantUnitId"), execution.getArgs().getStr("defendantUnitId"));
if (StrUtil.isBlank(unitId)) {
throw new BaseException("被申诉单位不能为空!");
}
Sys_role sysRole = sysRoleService.getByCode(RoleConstant.BRANCH_UNION_ADMIN);
List<Sys_user_role> userRoles = dao.query(Sys_user_role.class, Cnd.where("roleId", "=", sysRole.getId()).and("unitId", "=", unitId));
if (Lang.isEmpty(userRoles)) {
userRoles = dao.query(Sys_user_role.class, Cnd.where("roleId", "=", sysRole.getId()).and("unionId", "=", unitId));
}
if (Lang.isEmpty(userRoles)) {
throw new BaseException("被申诉单位分工会管理员没有设置,请联系管理员!", sysRole.getCode());
}
return userRoles.stream().map(Sys_user_role::getUserId).distinct().toList();
}
@Override
public String getMessage() {
return "被申诉单位分工会管理员";
}
@Override
public int getOrder() {
return 10;
}
}
@@ -114,9 +114,9 @@ public class SysUserServiceImpl extends BaseServiceImpl<Sys_user> implements Sys
user.setMenus(allMenus); user.setMenus(allMenus);
//pc端菜单 //pc端菜单
List<Sys_menu> pcMenus = allMenus.stream().filter(menu -> menu.getPlatform().equals("PC")).toList(); List<Sys_menu> pcMenus = allMenus.stream().filter(menu -> StrUtil.equals(menu.getPlatform(), "PC")).toList();
//h5端菜单 //h5端菜单
List<Sys_menu> h5Menus = allMenus.stream().filter(menu -> menu.getPlatform().equals("H5")).toList(); List<Sys_menu> h5Menus = allMenus.stream().filter(menu -> StrUtil.equals(menu.getPlatform(), "H5")).toList();
//所有的模块 //所有的模块
Set<String> allModuleIds = allMenus.stream().map(Sys_menu::getModuleId).collect(Collectors.toSet()); Set<String> allModuleIds = allMenus.stream().map(Sys_menu::getModuleId).collect(Collectors.toSet());
@@ -0,0 +1,152 @@
package com.budwk.app.zhgh.democratic.appeal.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.result.Result;
import com.budwk.app.flow.constant.FlowConst;
import com.budwk.app.flow.enums.ProcessSubmitTypeEnum;
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
import com.budwk.app.flow.service.FlowCommonService;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.democratic.appeal.models.AppealInfo;
import com.budwk.app.zhgh.democratic.appeal.service.AppealInfoService;
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.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.util.NutMap;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import java.util.Date;
import java.util.List;
@IocBean
@At("/platform/appeal/accept")
@Ok("json:full")
@Api("申诉管理-受理")
public class AppealAcceptController {
@Inject
private AppealInfoService appealInfoService;
@Inject
private FlowCommonService flowCommonService;
@At("")
@Ok("beetl:/platform/zhgh/democratic/appeal/accept/index.html")
@SaCheckPermission("appeal.accept")
public void index() {
}
@At
@SaCheckPermission("appeal.accept")
public Result pageData(Integer pageNumber, Integer pageSize, String searchKeyword, String appealTypeId,
Integer year, boolean approval) {
Sql sql = listSql();
Cnd cnd = taskCondition("appealAccept", "受理", approval);
if (StrUtil.isNotBlank(searchKeyword)) {
cnd.where().andLike("info.title", searchKeyword);
}
cnd.andEX("info.appealTypeId", "=", appealTypeId);
cnd.andEX("YEAR(info.applyDate)", "=", year);
cnd.desc("info.applyDate");
cnd.groupBy("t.id");
sql.setCondition(cnd);
Pagination<NutMap> pagination = appealInfoService.listPageMap(pageNumber, pageSize, sql);
return Result.success(pagination);
}
@At
@SaCheckPermission("appeal.accept")
@ApiOperation("查询受理任务")
public Result queryTask(@Param("taskId") Long taskId) {
Sql sql = listSql();
sql.setCondition(Cnd.where("t.id", "=", taskId));
return Result.success(appealInfoService.fetchMap(sql));
}
@At
@SaCheckPermission("appeal.accept")
@ApiOperation("受理申诉")
@Aop(TransAop.READ_COMMITTED)
@SLog(tag = "申诉管理-受理", msg = "受理申诉")
public Result accept(@Param("data") AppealInfo appealInfo, @Param("taskId") Long taskId,
@Param("submitType") Integer submitType) {
AppealInfo old = appealInfoService.fetch(appealInfo.getId());
BeanUtil.copyProperties(appealInfo, old, CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
old.setAcceptUserId(SecurityUtil.getUserId());
old.setAcceptUserName(SecurityUtil.getUserUsername());
old.setAcceptTime(new Date());
if (ProcessSubmitTypeEnum.AGREE.getCode().equals(submitType)) {
old.setState("待执行");
} else if (ProcessSubmitTypeEnum.ROLLBACK_TO_OPERATOR.getCode().equals(submitType)) {
old.setState("退回修改");
} else if (ProcessSubmitTypeEnum.REJECT.getCode().equals(submitType)) {
old.setState("已办结");
}
appealInfoService.updateIgnoreNull(old);
Dict dict = Dict.create();
dict.set(FlowConst.PROCESS_TASK_ID_KEY, taskId);
dict.set(FlowConst.SUBMIT_TYPE, submitType);
dict.set(FlowConst.FORM_DATA, old);
dict.set("appealDefendantUnitId", old.getDefendantUnitId());
dict.set("defendantUnitId", old.getDefendantUnitId());
flowCommonService.executeTask(dict);
return Result.success();
}
private Sql listSql() {
return Sqls.create("""
SELECT
info.*,
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,
IF(rt.id IS NOT NULL, 1, 0) AS canRevoke
FROM
wf_process_task t
LEFT JOIN wf_process_instance ins ON ins.id = t.processInstanceId
LEFT JOIN appeal_info info ON info.id = ins.businessNo
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 AND rt.taskState = 10
$condition
""");
}
private Cnd taskCondition(String taskName, String displayName, boolean approval) {
Cnd cnd = Cnd.NEW();
cnd.and(Cnd.exps("t.taskName", "=", taskName).or("t.displayName", "=", displayName));
cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId()));
if (approval) {
cnd.and("t.taskState", "in", List.of(ProcessTaskStateEnum.FINISHED.getCode(), ProcessTaskStateEnum.INTERRUPT.getCode()));
} else {
cnd.and("t.taskState", "=", ProcessTaskStateEnum.DOING.getCode());
}
return cnd;
}
}
@@ -0,0 +1,52 @@
package com.budwk.app.zhgh.democratic.appeal.controller;
import cn.dev33.satoken.annotation.SaCheckLogin;
import com.budwk.app.base.result.Result;
import com.budwk.app.zhgh.democratic.appeal.service.AppealTypeService;
import io.swagger.annotations.Api;
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.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
@IocBean
@At("/platform/appeal/common")
@Ok("json:full")
@Api("申诉管理-公共接口")
public class AppealCommonController {
@Inject
private Dao dao;
@Inject
private AppealTypeService appealTypeService;
@At
@SaCheckLogin
public Result typeOptions() {
return Result.success(appealTypeService.query(Cnd.where("enabled", "=", true).asc("sort").desc("createdAt")));
}
@At
@SaCheckLogin
public Result unitOptions(String unionId) {
Sql sql = Sqls.create("""
SELECT
unit.*,
su.`name` AS unionName
FROM
`sys_unit` unit
LEFT JOIN sys_union su ON su.id = unit.unionId
$condition
""");
Cnd cnd = Cnd.NEW();
cnd.andEX("unit.unionId", "=", unionId);
cnd.and("unit.unitLevel", "=", "2");
cnd.asc("unit.unitcode");
sql.setCondition(cnd);
return Result.success(appealTypeService.listMap(sql));
}
}
@@ -0,0 +1,143 @@
package com.budwk.app.zhgh.democratic.appeal.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.result.Result;
import com.budwk.app.flow.constant.FlowConst;
import com.budwk.app.flow.enums.ProcessSubmitTypeEnum;
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
import com.budwk.app.flow.service.FlowCommonService;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.democratic.appeal.models.AppealInfo;
import com.budwk.app.zhgh.democratic.appeal.service.AppealInfoService;
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.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.util.NutMap;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import java.util.Date;
import java.util.List;
@IocBean
@At("/platform/appeal/execute")
@Ok("json:full")
@Api("申诉管理-执行")
public class AppealExecuteController {
@Inject
private AppealInfoService appealInfoService;
@Inject
private FlowCommonService flowCommonService;
@At("")
@Ok("beetl:/platform/zhgh/democratic/appeal/execute/index.html")
@SaCheckPermission("appeal.execute")
public void index() {
}
@At
@SaCheckPermission("appeal.execute")
public Result pageData(Integer pageNumber, Integer pageSize, String searchKeyword, String appealTypeId,
Integer year, boolean approval) {
Sql sql = listSql();
Cnd cnd = taskCondition("appealExecute", "执行", approval);
if (StrUtil.isNotBlank(searchKeyword)) {
cnd.where().andLike("info.title", searchKeyword);
}
cnd.andEX("info.appealTypeId", "=", appealTypeId);
cnd.andEX("YEAR(info.applyDate)", "=", year);
cnd.desc("info.applyDate");
cnd.groupBy("t.id");
sql.setCondition(cnd);
Pagination<NutMap> pagination = appealInfoService.listPageMap(pageNumber, pageSize, sql);
return Result.success(pagination);
}
@At
@SaCheckPermission("appeal.execute")
@ApiOperation("查询执行任务")
public Result queryTask(@Param("taskId") Long taskId) {
Sql sql = listSql();
sql.setCondition(Cnd.where("t.id", "=", taskId));
return Result.success(appealInfoService.fetchMap(sql));
}
@At
@SaCheckPermission("appeal.execute")
@ApiOperation("提交执行情况")
@Aop(TransAop.READ_COMMITTED)
@SLog(tag = "申诉管理-执行", msg = "提交执行情况")
public Result execute(@Param("data") AppealInfo appealInfo, @Param("taskId") Long taskId) {
AppealInfo old = appealInfoService.fetch(appealInfo.getId());
BeanUtil.copyProperties(appealInfo, old, CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
old.setExecuteUserId(SecurityUtil.getUserId());
old.setExecuteUserName(SecurityUtil.getUserUsername());
old.setExecuteTime(new Date());
old.setState("已办结");
appealInfoService.updateIgnoreNull(old);
Dict dict = Dict.create();
dict.set(FlowConst.PROCESS_TASK_ID_KEY, taskId);
dict.set(FlowConst.SUBMIT_TYPE, ProcessSubmitTypeEnum.AGREE.getCode());
dict.set(FlowConst.FORM_DATA, old);
flowCommonService.executeTask(dict);
return Result.success();
}
private Sql listSql() {
return Sqls.create("""
SELECT
info.*,
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,
IF(rt.id IS NOT NULL, 1, 0) AS canRevoke
FROM
wf_process_task t
LEFT JOIN wf_process_instance ins ON ins.id = t.processInstanceId
LEFT JOIN appeal_info info ON info.id = ins.businessNo
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 AND rt.taskState = 10
$condition
""");
}
private Cnd taskCondition(String taskName, String displayName, boolean approval) {
Cnd cnd = Cnd.NEW();
cnd.and(Cnd.exps("t.taskName", "=", taskName).or("t.displayName", "=", displayName));
cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId()));
if (approval) {
cnd.and("t.taskState", "in", List.of(ProcessTaskStateEnum.FINISHED.getCode(), ProcessTaskStateEnum.INTERRUPT.getCode()));
} else {
cnd.and("t.taskState", "=", ProcessTaskStateEnum.DOING.getCode());
}
return cnd;
}
}
@@ -0,0 +1,83 @@
package com.budwk.app.zhgh.democratic.appeal.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.result.Result;
import com.budwk.app.flow.engine.FlowEngine;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.democratic.appeal.service.AppealInfoService;
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.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.util.NutMap;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
@IocBean
@At("/platform/appeal/mine")
@Ok("json:full")
@Api("申诉管理-我的申诉")
public class AppealMineController {
@Inject
private FlowEngine flowEngine;
@Inject
private AppealInfoService appealInfoService;
@At("")
@Ok("beetl:/platform/zhgh/democratic/appeal/mine/index.html")
@SaCheckPermission("appeal.mine")
public void index() {
}
@At
@SaCheckPermission("appeal.mine")
public Result pageData(Integer pageNumber, Integer pageSize, String searchKeyword, String appealTypeId, Integer year) {
Sql sql = Sqls.create("""
SELECT
info.*,
ins.id AS instanceId,
ins.state instanceState,
t.id startTaskId,
t.taskName AS taskKey,
IFNULL(GROUP_CONCAT(DISTINCT nt.displayName),'结束') taskName,
IF(rt.id IS NOT NULL, 1, 0) AS canRevoke
FROM
appeal_info info
LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id
LEFT JOIN wf_process_task t ON t.processInstanceId = ins.id AND t.taskName = 'startTask'
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 AND rt.taskState = 10
$condition
""");
Cnd cnd = Cnd.where("info.userId", "=", SecurityUtil.getUserId());
if (StrUtil.isNotBlank(searchKeyword)) {
cnd.where().andLike("info.title", searchKeyword);
}
cnd.andEX("info.appealTypeId", "=", appealTypeId);
cnd.andEX("YEAR(info.applyDate)", "=", year);
cnd.groupBy("info.id");
cnd.desc("info.applyDate");
sql.setCondition(cnd);
Pagination<NutMap> pagination = appealInfoService.listPageMap(pageNumber, pageSize, sql);
return Result.success(pagination);
}
@At
@SaCheckPermission("appeal.mine")
@Aop(TransAop.READ_COMMITTED)
@ApiOperation("删除申诉")
public Result delete(@Param("id") String id) {
appealInfoService.delete(id);
flowEngine.processInstanceService().deleteProcessInstanceByBusinessKey(id);
return Result.success();
}
}
@@ -0,0 +1,106 @@
package com.budwk.app.zhgh.democratic.appeal.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.result.Result;
import com.budwk.app.flow.engine.FlowEngine;
import com.budwk.app.zhgh.democratic.appeal.service.AppealInfoService;
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.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.util.NutMap;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
@IocBean
@At("/platform/appeal/query")
@Ok("json:full")
@Api("申诉管理-查询统计")
public class AppealQueryController {
@Inject
private FlowEngine flowEngine;
@Inject
private AppealInfoService appealInfoService;
@At("")
@Ok("beetl:/platform/zhgh/democratic/appeal/query/index.html")
@SaCheckPermission("appeal.query")
public void index() {
}
@At
@SaCheckPermission("appeal.query")
public Result pageData(Integer pageNumber, Integer pageSize, String searchKeyword, String appealTypeId, String state,
String unitId, String defendantUnitId, Integer year) {
Sql sql = Sqls.create("""
SELECT
info.*,
ins.id AS instanceId,
ins.state instanceState
FROM
appeal_info info
LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id
$condition
""");
Cnd cnd = buildCondition(searchKeyword, appealTypeId, state, unitId, defendantUnitId, year);
cnd.desc("info.applyDate");
sql.setCondition(cnd);
Pagination<NutMap> pagination = appealInfoService.listPageMap(pageNumber, pageSize, sql);
return Result.success(pagination);
}
@At
@SaCheckPermission("appeal.query")
@ApiOperation("申诉统计")
public Result statistics(String searchKeyword, String appealTypeId, String state, String unitId,
String defendantUnitId, Integer year) {
Sql sql = Sqls.create("""
SELECT
COUNT(1) totalCount,
SUM(CASE WHEN info.state = '待受理' THEN 1 ELSE 0 END) waitAcceptCount,
SUM(CASE WHEN info.state = '待执行' THEN 1 ELSE 0 END) waitExecuteCount,
SUM(CASE WHEN info.state = '已办结' THEN 1 ELSE 0 END) finishCount,
SUM(CASE WHEN info.decisionType = 'MAINTAIN' THEN 1 ELSE 0 END) maintainCount,
SUM(CASE WHEN info.decisionType LIKE 'REPROCESS%' THEN 1 ELSE 0 END) reprocessCount
FROM
appeal_info info
$condition
""");
sql.setCondition(buildCondition(searchKeyword, appealTypeId, state, unitId, defendantUnitId, year));
NutMap data = appealInfoService.fetchMap(sql);
return Result.success(data);
}
@At
@SaCheckPermission("appeal.query")
@Aop(TransAop.READ_COMMITTED)
@ApiOperation("删除申诉")
public Result delete(@Param("id") String id) {
appealInfoService.delete(id);
flowEngine.processInstanceService().deleteProcessInstanceByBusinessKey(id);
return Result.success();
}
private Cnd buildCondition(String searchKeyword, String appealTypeId, String state, String unitId,
String defendantUnitId, Integer year) {
Cnd cnd = Cnd.NEW();
if (StrUtil.isNotBlank(searchKeyword)) {
cnd.where().andLike("info.title", searchKeyword);
}
cnd.andEX("info.appealTypeId", "=", appealTypeId);
cnd.andEX("info.state", "=", state);
cnd.andEX("info.unitId", "=", unitId);
cnd.andEX("info.defendantUnitId", "=", defendantUnitId);
cnd.andEX("YEAR(info.applyDate)", "=", year);
return cnd;
}
}
@@ -0,0 +1,77 @@
package com.budwk.app.zhgh.democratic.appeal.controller;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.result.Result;
import com.budwk.app.zhgh.democratic.appeal.models.AppealType;
import com.budwk.app.zhgh.democratic.appeal.service.AppealTypeService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.nutz.dao.Cnd;
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;
@IocBean
@At("/platform/appeal/type")
@Ok("json:full")
@Api("申诉管理-类型维护")
public class AppealTypeController {
@Inject
private AppealTypeService appealTypeService;
@At("")
@Ok("beetl:/platform/zhgh/democratic/appeal/type/index.html")
@SaCheckPermission("appeal.type")
public void index() {
}
@At
@SaCheckPermission("appeal.type")
public Result pageData(Integer pageNumber, Integer pageSize, String name) {
Cnd cnd = Cnd.NEW();
if (StrUtil.isNotBlank(name)) {
cnd.where().andLike("name", name);
}
cnd.asc("sort").desc("createdAt");
Pagination page = appealTypeService.listPage(pageNumber, pageSize, cnd);
return Result.success(page);
}
@At
@SaCheckPermission("appeal.type")
@ApiOperation("保存申诉类型")
@SLog(tag = "申诉管理-类型维护", msg = "保存申诉类型")
public Result save(@Param("data") AppealType appealType) {
if (appealType.getEnabled() == null) {
appealType.setEnabled(true);
}
if (appealType.getSort() == null) {
appealType.setSort(0);
}
appealTypeService.insertOrUpdate(appealType);
return Result.success();
}
@At
@SaCheckPermission("appeal.type")
@ApiOperation("删除申诉类型")
@SLog(tag = "申诉管理-类型维护", msg = "删除申诉类型")
public Result delete(@Param("id") String id) {
appealTypeService.delete(id);
return Result.success();
}
@At
@SaCheckLogin
@ApiOperation("申诉类型下拉")
public Result options() {
return Result.success(appealTypeService.query(Cnd.where("enabled", "=", true).asc("sort").desc("createdAt")));
}
}
@@ -0,0 +1,161 @@
package com.budwk.app.zhgh.democratic.appeal.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.result.Result;
import com.budwk.app.flow.constant.FlowConst;
import com.budwk.app.flow.engine.FlowEngine;
import com.budwk.app.flow.entity.ProcessInstance;
import com.budwk.app.flow.entity.ProcessTask;
import com.budwk.app.flow.enums.ProcessSubmitTypeEnum;
import com.budwk.app.flow.service.FlowCommonService;
import com.budwk.app.sys.views.View_user;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.democratic.appeal.models.AppealInfo;
import com.budwk.app.zhgh.democratic.appeal.models.AppealType;
import com.budwk.app.zhgh.democratic.appeal.service.AppealInfoService;
import com.budwk.app.zhgh.democratic.appeal.service.AppealTypeService;
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.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 java.util.Date;
import java.util.List;
@IocBean
@At("/platform/appeal/write")
@Ok("json:full")
@Api("申诉管理-提交申诉")
public class AppealWriteController {
private static final String DEFINE_KEY = "SSGL";
@Inject
private Dao dao;
@Inject
private FlowEngine flowEngine;
@Inject
private FlowCommonService flowCommonService;
@Inject
private AppealInfoService appealInfoService;
@Inject
private AppealTypeService appealTypeService;
@At("")
@Ok("beetl:/platform/zhgh/democratic/appeal/write/index.html")
@SaCheckPermission("appeal.write")
public void index() {
}
@At
@SaCheckPermission("appeal.write")
@ApiOperation("当前用户信息")
public Result currentUserInfo() {
View_user user = dao.fetch(View_user.class, Cnd.where("id", "=", SecurityUtil.getUserId()));
AppealInfo info = new AppealInfo();
if (user != null) {
info.setUserId(user.getId());
info.setUserName(user.getUsername());
info.setLoginName(user.getLoginname());
info.setSex(user.getSex());
info.setBirthday(user.getBirthday());
info.setPolitical(user.getPolitical());
info.setUnitId(user.getUnitId());
info.setUnitName(user.getUnitName());
info.setPositionName(user.getPosition());
info.setMobile(user.getMobile());
} else {
info.setUserId(SecurityUtil.getUserId());
info.setUserName(SecurityUtil.getUserUsername());
info.setLoginName(SecurityUtil.getUserLoginname());
info.setUnitId(SecurityUtil.getUnitId());
}
info.setApplyDate(new Date());
return Result.success(info);
}
@At
@SaCheckPermission("appeal.write")
@ApiOperation("获取申诉信息")
public Result info(@Param("id") String id) {
return Result.success(appealInfoService.fetch(id));
}
@At
@SaCheckPermission("appeal.write")
@ApiOperation("保存申诉")
@SLog(tag = "申诉管理-提交申诉", msg = "保存申诉")
public Result save(@Param("data") AppealInfo appealInfo) {
fillTypeName(appealInfo);
appealInfoService.insertOrUpdate(appealInfo);
return Result.success(appealInfo);
}
@At
@SaCheckPermission("appeal.write")
@ApiOperation("提交申诉")
@Aop(TransAop.READ_COMMITTED)
@SLog(tag = "申诉管理-提交申诉", msg = "提交申诉")
public Result submit(@Param("data") AppealInfo appealInfo) {
fillTypeName(appealInfo);
if (appealInfo.getApplyDate() == null) {
appealInfo.setApplyDate(new Date());
}
appealInfo.setState("待受理");
appealInfoService.insertOrUpdate(appealInfo);
Dict args = Dict.create();
args.set(FlowConst.SUBMIT_TYPE, ProcessSubmitTypeEnum.APPLY.getCode());
args.set(FlowConst.FORM_DATA, appealInfo);
args.set("appealDefendantUnitId", appealInfo.getDefendantUnitId());
args.set("defendantUnitId", appealInfo.getDefendantUnitId());
ProcessInstance instance = flowEngine.startProcessInstanceByKey(DEFINE_KEY, appealInfo.getId(), SecurityUtil.getUserId(), args);
// 自动完成开始节点任务,进入受理环节。
List<ProcessTask> doingTaskList = flowEngine.processTaskService().getDoingTaskList(instance.getId(), null);
for (ProcessTask task : doingTaskList) {
flowEngine.executeProcessTask(task.getId(), SecurityUtil.getUserId(), args);
}
return Result.success(appealInfo);
}
@At
@SaCheckPermission("appeal.write")
@ApiOperation("重新提交申诉")
@Aop(TransAop.READ_COMMITTED)
@SLog(tag = "申诉管理-提交申诉", msg = "重新提交申诉")
public Result submitAgain(@Param("data") AppealInfo appealInfo, @Param("taskId") Long taskId) {
fillTypeName(appealInfo);
appealInfo.setState("待受理");
appealInfoService.insertOrUpdate(appealInfo);
Dict dict = Dict.create();
dict.set(FlowConst.PROCESS_TASK_ID_KEY, taskId);
dict.set(FlowConst.SUBMIT_TYPE, ProcessSubmitTypeEnum.RE_APPLY.getCode());
dict.set(FlowConst.FORM_DATA, appealInfo);
dict.set("appealDefendantUnitId", appealInfo.getDefendantUnitId());
dict.set("defendantUnitId", appealInfo.getDefendantUnitId());
flowCommonService.executeTask(dict);
return Result.success(appealInfo);
}
private void fillTypeName(AppealInfo appealInfo) {
if (appealInfo == null || StrUtil.isBlank(appealInfo.getAppealTypeId())) {
return;
}
AppealType type = appealTypeService.fetch(appealInfo.getAppealTypeId());
if (type != null) {
appealInfo.setAppealTypeName(type.getName());
}
}
}
@@ -0,0 +1,215 @@
package com.budwk.app.zhgh.democratic.appeal.models;
import cn.hutool.json.JSONObject;
import com.budwk.app.base.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.nutz.dao.entity.annotation.*;
import org.nutz.dao.interceptor.annotation.PrevInsert;
import java.util.Date;
import java.util.List;
@EqualsAndHashCode(callSuper = true)
@Table("appeal_info")
@TableMeta("{'mysql-charset':'utf8mb4'}")
@Comment("教职工申诉")
@Data
public class AppealInfo extends BaseModel {
@Name
@Comment("ID")
@ColDefine(type = ColType.VARCHAR, width = 32)
@PrevInsert(uu32 = true)
private String id;
@Column
@Comment("申诉人ID")
@ColDefine(type = ColType.VARCHAR, width = 32)
private String userId;
@Column
@Comment("申诉人姓名")
@ColDefine(type = ColType.VARCHAR, width = 50)
private String userName;
@Column
@Comment("申诉人工号")
@ColDefine(type = ColType.VARCHAR, width = 50)
private String loginName;
@Column
@Comment("性别")
@ColDefine(type = ColType.VARCHAR, width = 20)
private String sex;
@Column
@Comment("出生年月")
@ColDefine(type = ColType.DATE)
private Date birthday;
@Column
@Comment("政治面貌")
@ColDefine(type = ColType.VARCHAR, width = 100)
private String political;
@Column
@Comment("所在单位ID")
@ColDefine(type = ColType.VARCHAR, width = 32)
private String unitId;
@Column
@Comment("所在单位")
@ColDefine(type = ColType.VARCHAR, width = 100)
private String unitName;
@Column
@Comment("岗位")
@ColDefine(type = ColType.VARCHAR, width = 100)
private String positionName;
@Column
@Comment("住址")
@ColDefine(type = ColType.VARCHAR, width = 300)
private String address;
@Column
@Comment("联系方式")
@ColDefine(type = ColType.VARCHAR, width = 100)
private String mobile;
@Column
@Comment("申诉类型ID")
@ColDefine(type = ColType.VARCHAR, width = 32)
private String appealTypeId;
@Column
@Comment("申诉类型名称")
@ColDefine(type = ColType.VARCHAR, width = 100)
private String appealTypeName;
@Column
@Comment("被申诉单位ID")
@ColDefine(type = ColType.VARCHAR, width = 32)
private String defendantUnitId;
@Column
@Comment("被申诉单位")
@ColDefine(type = ColType.VARCHAR, width = 100)
private String defendantUnitName;
@Column
@Comment("被申诉单位地址")
@ColDefine(type = ColType.VARCHAR, width = 300)
private String defendantAddress;
@Column
@Comment("被申诉单位联系方式")
@ColDefine(type = ColType.VARCHAR, width = 100)
private String defendantContact;
@Column
@Comment("申诉标题")
@ColDefine(type = ColType.VARCHAR, width = 200)
private String title;
@Column
@Comment("申诉事项")
@ColDefine(type = ColType.TEXT)
private String appealMatter;
@Column
@Comment("申诉理由")
@ColDefine(type = ColType.TEXT)
private String reason;
@Column
@Comment("申诉要求")
@ColDefine(type = ColType.TEXT)
private String request;
@Column
@Comment("申请日期")
@ColDefine(type = ColType.DATE)
private Date applyDate;
@Column
@Comment("申诉人签名")
@ColDefine(type = ColType.VARCHAR, width = 100)
private String signature;
@Column
@Comment("附件")
@ColDefine(type = ColType.MYSQL_JSON)
private List<JSONObject> files;
@Column
@Comment("业务状态")
@ColDefine(type = ColType.VARCHAR, width = 50)
private String state;
@Column
@Comment("受理人ID")
@ColDefine(type = ColType.VARCHAR, width = 32)
private String acceptUserId;
@Column
@Comment("受理人姓名")
@ColDefine(type = ColType.VARCHAR, width = 50)
private String acceptUserName;
@Column
@Comment("受理时间")
@ColDefine(type = ColType.DATETIME)
private Date acceptTime;
@Column
@Comment("处理决定类型")
@ColDefine(type = ColType.VARCHAR, width = 80)
private String decisionType;
@Column
@Comment("处理决定")
@ColDefine(type = ColType.TEXT)
private String decisionContent;
@Column
@Comment("事实理由及适用依据")
@ColDefine(type = ColType.TEXT)
private String legalBasis;
@Column
@Comment("作出决定日期")
@ColDefine(type = ColType.DATE)
private Date decisionDate;
@Column
@Comment("决定书附件")
@ColDefine(type = ColType.MYSQL_JSON)
private List<JSONObject> decisionFiles;
@Column
@Comment("执行人ID")
@ColDefine(type = ColType.VARCHAR, width = 32)
private String executeUserId;
@Column
@Comment("执行人姓名")
@ColDefine(type = ColType.VARCHAR, width = 50)
private String executeUserName;
@Column
@Comment("执行时间")
@ColDefine(type = ColType.DATETIME)
private Date executeTime;
@Column
@Comment("执行情况")
@ColDefine(type = ColType.TEXT)
private String executeContent;
@Column
@Comment("执行附件")
@ColDefine(type = ColType.MYSQL_JSON)
private List<JSONObject> executeFiles;
}
@@ -0,0 +1,43 @@
package com.budwk.app.zhgh.democratic.appeal.models;
import com.budwk.app.base.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.nutz.dao.entity.annotation.*;
import org.nutz.dao.interceptor.annotation.PrevInsert;
@EqualsAndHashCode(callSuper = true)
@Table("appeal_type")
@TableMeta("{'mysql-charset':'utf8mb4'}")
@Comment("申诉类型")
@Data
public class AppealType extends BaseModel {
@Name
@Comment("ID")
@ColDefine(type = ColType.VARCHAR, width = 32)
@PrevInsert(uu32 = true)
private String id;
@Column
@Comment("类型名称")
@ColDefine(type = ColType.VARCHAR, width = 100)
private String name;
@Column
@Comment("排序")
@ColDefine(type = ColType.INT)
@Default("0")
private Integer sort;
@Column
@Comment("是否启用")
@ColDefine(type = ColType.BOOLEAN)
@Default("1")
private Boolean enabled;
@Column
@Comment("备注")
@ColDefine(type = ColType.VARCHAR, width = 500)
private String remark;
}
@@ -0,0 +1,7 @@
package com.budwk.app.zhgh.democratic.appeal.service;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.zhgh.democratic.appeal.models.AppealInfo;
public interface AppealInfoService extends BaseService<AppealInfo> {
}
@@ -0,0 +1,7 @@
package com.budwk.app.zhgh.democratic.appeal.service;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.zhgh.democratic.appeal.models.AppealType;
public interface AppealTypeService extends BaseService<AppealType> {
}
@@ -0,0 +1,14 @@
package com.budwk.app.zhgh.democratic.appeal.service.impl;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.zhgh.democratic.appeal.models.AppealInfo;
import com.budwk.app.zhgh.democratic.appeal.service.AppealInfoService;
import org.nutz.dao.Dao;
import org.nutz.ioc.loader.annotation.IocBean;
@IocBean(args = {"refer:dao"})
public class AppealInfoServiceImpl extends BaseServiceImpl<AppealInfo> implements AppealInfoService {
public AppealInfoServiceImpl(Dao dao) {
super(dao);
}
}
@@ -0,0 +1,14 @@
package com.budwk.app.zhgh.democratic.appeal.service.impl;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.zhgh.democratic.appeal.models.AppealType;
import com.budwk.app.zhgh.democratic.appeal.service.AppealTypeService;
import org.nutz.dao.Dao;
import org.nutz.ioc.loader.annotation.IocBean;
@IocBean(args = {"refer:dao"})
public class AppealTypeServiceImpl extends BaseServiceImpl<AppealType> implements AppealTypeService {
public AppealTypeServiceImpl(Dao dao) {
super(dao);
}
}
@@ -420,7 +420,7 @@ layout("/layouts/v4/baseLayout.html"){
this.$message.warning("当前流程没有配置地址") this.$message.warning("当前流程没有配置地址")
return return
} }
window.open(formKey + "?taskId=" + taskId + "bizId=" + businessNo + "taskKey=" + taskKey) window.open(formKey + "?taskId=" + taskId + "&bizId=" + businessNo + "&taskKey=" + taskKey)
}, },
// 获取空状态文本 // 获取空状态文本
@@ -0,0 +1,186 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker v-model="pageForm.year" type="year" value-format="yyyy" style="width: 100%" placeholder="请选择年度"></el-date-picker>
</search-item>
<search-item label="申诉类型">
<el-select v-model="pageForm.appealTypeId" filterable clearable style="width: 100%" placeholder="请选择申诉类型">
<el-option v-for="item in typeOptions" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</search-item>
<search-item label="申诉标题">
<el-input v-model="pageForm.searchKeyword" clearable placeholder="请输入申诉标题" @keyup.enter.native="doSearch"></el-input>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool :app="this" label="审批列表">
<el-radio-group @change="doSearch" class="mr5" size="small" v-model="pageForm.approval">
<el-radio-button :label="true">已审核</el-radio-button>
<el-radio-button :label="false">未审核</el-radio-button>
</el-radio-group>
</table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder" ref="table" row-key="taskId" style="width: 100%">
<el-table-column type="index" label="序号" width="60" :index="indexMethod"></el-table-column>
<el-table-column prop="title" label="申诉标题" show-overflow-tooltip></el-table-column>
<el-table-column prop="userName" label="申诉人" width="100"></el-table-column>
<el-table-column prop="appealTypeName" label="申诉类型" width="140"></el-table-column>
<el-table-column prop="defendantUnitName" label="被申诉单位" width="180" show-overflow-tooltip></el-table-column>
<el-table-column prop="applyDate" label="申请日期" width="120"></el-table-column>
<el-table-column prop="curTaskName" label="当前节点" width="120"></el-table-column>
<el-table-column prop="instanceState" label="流程状态" width="120">
<template slot-scope="{row}">
<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="200">
<template slot-scope="{row}">
<el-button size="mini" type="primary" @click="onOpen(row)">查看</el-button>
<el-button size="mini" type="primary" v-if="row.taskState === 10" @click="onDeal(row)">审核</el-button>
<el-button size="mini" type="danger" v-if="row.canRevoke" @click="onRevoke(row)">撤回</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #view>
<appeal-info ref="infoRef"></appeal-info>
</template>
</guava>
<el-dialog title="受理申诉" :visible.sync="dialogVisible" width="900px" :close-on-click-modal="false">
<el-form :model="formData" ref="formRef" label-width="130px">
<el-form-item label="申诉标题">
<el-input v-model="formData.title" disabled></el-input>
</el-form-item>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="处理决定" prop="decisionType" :rules="[{required:true,message:'请选择处理决定',trigger:'change'}]">
<el-select v-model="formData.decisionType" style="width: 100%">
<el-option label="维持原处理决定" value="MAINTAIN"></el-option>
<el-option label="责令重新处理" value="REPROCESS"></el-option>
<el-option label="责令部分重新处理" value="REPROCESS_PART"></el-option>
<el-option label="其他" value="OTHER"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="作出决定日期" prop="decisionDate" :rules="[{required:true,message:'请选择决定日期',trigger:'change'}]">
<el-date-picker v-model="formData.decisionDate" value-format="yyyy-MM-dd" type="date" style="width: 100%"></el-date-picker>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="处理决定内容" prop="decisionContent" :rules="[{required:true,message:'请输入处理决定内容',trigger:'blur'}]">
<text-editor v-model="formData.decisionContent"></text-editor>
</el-form-item>
<el-form-item label="事实理由及依据" prop="legalBasis" :rules="[{required:true,message:'请输入事实理由及依据',trigger:'blur'}]">
<text-editor v-model="formData.legalBasis"></text-editor>
</el-form-item>
<el-form-item label="决定书附件" prop="decisionFiles">
<file-upload :value.sync="formData.decisionFiles" :upload_number="5" upload_mode="drag" upload_result_category="array" complete_result></file-upload>
</el-form-item>
</el-form>
<span slot="footer">
<el-button @click="dialogVisible=false">取消</el-button>
<el-button type="warning" @click="doAccept(6)">退回修改</el-button>
<el-button type="danger" @click="doAccept(2)">不予受理</el-button>
<el-button type="primary" @click="doAccept(1)">受理并转执行</el-button>
</span>
</el-dialog>
</div>
<script nonce="${cspNonce!}">
<!--#include("../common/info.js"){}#-->
new Vue({
el: "#app",
store,
mixins: [initTableMixins],
components: {
"appeal-info": APPEAL_INFO
},
data() {
return {
pageForm: {
approval: false
},
typeOptions: [],
dialogVisible: false,
formData: {},
currentTaskId: null
}
},
methods: {
onOpen(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
onDeal(row) {
this.currentTaskId = row.taskId
this.$axios.post("/platform/appeal/accept/queryTask", {taskId: row.taskId}).then((res) => {
if (res.code === 0) {
this.formData = res.data || row
this.dialogVisible = true
}
})
},
doAccept(submitType) {
const submit = () => {
this.$axios.post("/platform/appeal/accept/accept", {
data: JSON.stringify(this.formData),
taskId: this.currentTaskId,
submitType
}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.dialogVisible = false
this.pageData()
}
})
}
if (submitType === 1) {
this.$refs.formRef.validate((valid) => {
if (valid) submit()
})
} else {
submit()
}
},
onRevoke(row) {
this.$confirm("您确定要撤回吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
loadTypeOptions() {
this.$axios.post("/platform/appeal/common/typeOptions").then((res) => {
if (res.code === 0) this.typeOptions = res.data || []
})
}
},
created() {
this.loadTypeOptions()
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,123 @@
const APPEAL_INFO = {
name: "AppealInfo",
/*language=HTML*/
template: `
<div class="appeal-info">
<div class="process-title">申诉基础信息</div>
<h3 style="text-align: center;font-weight: 600" class="pt10 pb10">{{ viewData.title }}</h3>
<el-descriptions :column="3" border>
<el-descriptions-item label="申诉人">{{ viewData.userName }}({{ viewData.loginName }})</el-descriptions-item>
<el-descriptions-item label="所在单位">{{ viewData.unitName }}</el-descriptions-item>
<el-descriptions-item label="联系电话">{{ viewData.mobile }}</el-descriptions-item>
<el-descriptions-item label="性别">{{ viewData.sex }}</el-descriptions-item>
<el-descriptions-item label="出生年月">{{ viewData.birthday }}</el-descriptions-item>
<el-descriptions-item label="政治面貌">{{ viewData.political }}</el-descriptions-item>
<el-descriptions-item label="申诉类型">{{ viewData.appealTypeName }}</el-descriptions-item>
<el-descriptions-item label="被申诉单位">{{ viewData.defendantUnitName }}</el-descriptions-item>
<el-descriptions-item label="申请日期">{{ viewData.applyDate }}</el-descriptions-item>
<el-descriptions-item label="业务状态">
<el-tag size="mini">{{ viewData.state || '草稿' }}</el-tag>
</el-descriptions-item>
<el-descriptions-item label="岗位">{{ viewData.positionName }}</el-descriptions-item>
<el-descriptions-item label="住址">{{ viewData.address }}</el-descriptions-item>
<el-descriptions-item label="申诉事项" :span="3">
<div class="text-left" v-html="viewData.appealMatter"></div>
</el-descriptions-item>
<el-descriptions-item label="申诉理由" :span="3">
<div class="text-left" v-html="viewData.reason"></div>
</el-descriptions-item>
<el-descriptions-item label="申诉要求" :span="3">
<div class="text-left" v-html="viewData.request"></div>
</el-descriptions-item>
<el-descriptions-item label="附件" :span="3">
<file-preview :files="viewData.files" complete_result></file-preview>
</el-descriptions-item>
<el-descriptions-item label="申诉人签名" :span="3">
<el-image v-if="viewData.signature" :src="viewData.signature" class="signature-image"></el-image>
<span v-else>暂无</span>
</el-descriptions-item>
</el-descriptions>
<div class="process-title mt10" v-if="viewData.acceptTime || viewData.decisionContent">受理与处理决定</div>
<el-descriptions :column="3" border v-if="viewData.acceptTime || viewData.decisionContent">
<el-descriptions-item label="受理人">{{ viewData.acceptUserName }}</el-descriptions-item>
<el-descriptions-item label="受理时间">{{ viewData.acceptTime }}</el-descriptions-item>
<el-descriptions-item label="处理决定">{{ decisionTypeText(viewData.decisionType) }}</el-descriptions-item>
<el-descriptions-item label="决定日期">{{ viewData.decisionDate }}</el-descriptions-item>
<el-descriptions-item label="决定内容" :span="3">
<div class="text-left" v-html="viewData.decisionContent"></div>
</el-descriptions-item>
<el-descriptions-item label="事实理由及依据" :span="3">
<div class="text-left" v-html="viewData.legalBasis"></div>
</el-descriptions-item>
<el-descriptions-item label="决定书附件" :span="3">
<file-preview :files="viewData.decisionFiles" complete_result></file-preview>
</el-descriptions-item>
</el-descriptions>
<div class="process-title mt10" v-if="viewData.executeTime || viewData.executeContent">执行情况</div>
<el-descriptions :column="3" border v-if="viewData.executeTime || viewData.executeContent">
<el-descriptions-item label="执行人">{{ viewData.executeUserName }}</el-descriptions-item>
<el-descriptions-item label="执行时间">{{ viewData.executeTime }}</el-descriptions-item>
<el-descriptions-item label="执行状态">{{ viewData.state }}</el-descriptions-item>
<el-descriptions-item label="执行情况" :span="3">
<div class="text-left" v-html="viewData.executeContent"></div>
</el-descriptions-item>
<el-descriptions-item label="执行附件" :span="3">
<file-preview :files="viewData.executeFiles" complete_result></file-preview>
</el-descriptions-item>
</el-descriptions>
<template v-for="task in doneTasks">
<div class="mt10" :key="task.id">
<div class="process-title">{{ task.displayName }}</div>
<el-descriptions border class="flow-task-form" :column="3">
<el-descriptions-item label="办理用户">
{{ task.taskFormData && task.taskFormData.userName ? task.taskFormData.userName : task.ext.initiatorName }}
</el-descriptions-item>
<el-descriptions-item label="办理时间">{{ task.finishTime }}</el-descriptions-item>
<el-descriptions-item label="办理结果">
<dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE" :value="task.ext.submitType"></dict-tag>
</el-descriptions-item>
<el-descriptions-item label="办理意见" :span="3" v-if="task.taskFormData && task.taskFormData.tf_opinion">
<div v-html="task.taskFormData.tf_opinion"></div>
</el-descriptions-item>
</el-descriptions>
</div>
</template>
</div>
`,
dicts: ["PROCESS_TASK_SUBMIT_TYPE"],
data() {
return {
viewData: {},
doneTasks: []
}
},
methods: {
onOpen(row) {
this.viewData = {...row}
this.getDoneTasks()
},
getDoneTasks() {
if (!this.viewData.id) {
this.doneTasks = []
return
}
this.$axios.post("/flow/common/doneTasks", {bizId: this.viewData.id}).then((res) => {
if (res.code === 0) {
this.doneTasks = res.data || []
}
})
},
decisionTypeText(value) {
const map = {
MAINTAIN: "维持原处理决定",
REPROCESS: "责令重新处理",
REPROCESS_PART: "责令部分重新处理",
OTHER: "其他"
}
return map[value] || value || ""
}
}
}
@@ -0,0 +1,157 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker v-model="pageForm.year" type="year" value-format="yyyy" style="width: 100%" placeholder="请选择年度"></el-date-picker>
</search-item>
<search-item label="申诉类型">
<el-select v-model="pageForm.appealTypeId" filterable clearable style="width: 100%" placeholder="请选择申诉类型">
<el-option v-for="item in typeOptions" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</search-item>
<search-item label="申诉标题">
<el-input v-model="pageForm.searchKeyword" clearable placeholder="请输入申诉标题" @keyup.enter.native="doSearch"></el-input>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool :app="this" label="审批列表">
<el-radio-group @change="doSearch" class="mr5" size="small" v-model="pageForm.approval">
<el-radio-button :label="true">已审核</el-radio-button>
<el-radio-button :label="false">未审核</el-radio-button>
</el-radio-group>
</table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder" ref="table" row-key="taskId" style="width: 100%">
<el-table-column type="index" label="序号" width="60" :index="indexMethod"></el-table-column>
<el-table-column prop="title" label="申诉标题" show-overflow-tooltip></el-table-column>
<el-table-column prop="userName" label="申诉人" width="100"></el-table-column>
<el-table-column prop="appealTypeName" label="申诉类型" width="140"></el-table-column>
<el-table-column prop="defendantUnitName" label="被申诉单位" width="180" show-overflow-tooltip></el-table-column>
<el-table-column prop="applyDate" label="申请日期" width="120"></el-table-column>
<el-table-column prop="curTaskName" label="当前节点" width="120"></el-table-column>
<el-table-column prop="instanceState" label="流程状态" width="120">
<template slot-scope="{row}">
<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="200">
<template slot-scope="{row}">
<el-button size="mini" type="primary" @click="onOpen(row)">查看</el-button>
<el-button size="mini" type="primary" v-if="row.taskState === 10" @click="onDeal(row)">审核</el-button>
<el-button size="mini" type="danger" v-if="row.canRevoke" @click="onRevoke(row)">撤回</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #view>
<appeal-info ref="infoRef"></appeal-info>
</template>
</guava>
<el-dialog title="执行反馈" :visible.sync="dialogVisible" width="900px" :close-on-click-modal="false">
<el-form :model="formData" ref="formRef" label-width="120px">
<el-form-item label="申诉标题">
<el-input v-model="formData.title" disabled></el-input>
</el-form-item>
<el-form-item label="执行情况" prop="executeContent" :rules="[{required:true,message:'请输入执行情况',trigger:'blur'}]">
<text-editor v-model="formData.executeContent"></text-editor>
</el-form-item>
<el-form-item label="执行附件" prop="executeFiles">
<file-upload :value.sync="formData.executeFiles" :upload_number="5" upload_mode="drag" upload_result_category="array" complete_result></file-upload>
</el-form-item>
</el-form>
<span slot="footer">
<el-button @click="dialogVisible=false">取消</el-button>
<el-button type="primary" @click="doExecute">提交</el-button>
</span>
</el-dialog>
</div>
<script nonce="${cspNonce!}">
<!--#include("../common/info.js"){}#-->
new Vue({
el: "#app",
store,
mixins: [initTableMixins],
components: {
"appeal-info": APPEAL_INFO
},
data() {
return {
pageForm: {
approval: false
},
typeOptions: [],
dialogVisible: false,
formData: {},
currentTaskId: null
}
},
methods: {
onOpen(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
onDeal(row) {
this.currentTaskId = row.taskId
this.$axios.post("/platform/appeal/execute/queryTask", {taskId: row.taskId}).then((res) => {
if (res.code === 0) {
this.formData = res.data || row
this.dialogVisible = true
}
})
},
doExecute() {
this.$refs.formRef.validate((valid) => {
if (!valid) return
this.$axios.post("/platform/appeal/execute/execute", {
data: JSON.stringify(this.formData),
taskId: this.currentTaskId
}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.dialogVisible = false
this.pageData()
}
})
})
},
onRevoke(row) {
this.$confirm("您确定要撤回吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
loadTypeOptions() {
this.$axios.post("/platform/appeal/common/typeOptions").then((res) => {
if (res.code === 0) this.typeOptions = res.data || []
})
}
},
created() {
this.loadTypeOptions()
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,128 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker v-model="pageForm.year" type="year" value-format="yyyy" style="width: 100%" placeholder="请选择年度"></el-date-picker>
</search-item>
<search-item label="申诉类型">
<el-select v-model="pageForm.appealTypeId" filterable clearable style="width: 100%" placeholder="请选择申诉类型">
<el-option v-for="item in typeOptions" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</search-item>
<search-item label="申诉标题">
<el-input v-model="pageForm.searchKeyword" clearable placeholder="请输入申诉标题" @keyup.enter.native="doSearch"></el-input>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool>
<el-button type="primary" size="small" icon="el-icon-plus" @click="onWrite">提交申诉</el-button>
</table-tool>
<el-table :data="tableData" @sort-change="pageOrder" style="width: 100%">
<el-table-column type="index" label="序号" width="60" :index="indexMethod"></el-table-column>
<el-table-column prop="title" label="申诉标题" show-overflow-tooltip></el-table-column>
<el-table-column prop="appealTypeName" label="申诉类型" width="140"></el-table-column>
<el-table-column prop="defendantUnitName" label="被申诉单位" width="180" show-overflow-tooltip></el-table-column>
<el-table-column prop="applyDate" label="申请日期" width="120"></el-table-column>
<el-table-column prop="state" label="业务状态" width="110">
<template slot-scope="{row}">
<el-tag size="mini">{{ row.state || '草稿' }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="taskName" label="当前节点" width="120"></el-table-column>
<el-table-column label="操作" fixed="right" width="260">
<template slot-scope="{row}">
<el-button size="mini" type="primary" @click="onOpen(row)">查看</el-button>
<el-button size="mini" type="primary" v-if="canEdit(row)" @click="onEdit(row)">修改</el-button>
<el-button size="mini" type="warning" v-if="row.canRevoke" @click="onRevoke(row)">撤回</el-button>
<el-button size="mini" type="danger" v-if="!row.instanceId || row.state === '草稿'" @click="onDelete(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #view>
<appeal-info ref="infoRef"></appeal-info>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include("../common/info.js"){}#-->
new Vue({
el: "#app",
store,
mixins: [initTableMixins],
components: {
"appeal-info": APPEAL_INFO
},
data() {
return {
pageForm: {
year: new Date().getFullYear().toString()
},
typeOptions: []
}
},
methods: {
onWrite() {
window.location.href = "/platform/appeal/write"
},
onOpen(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
canEdit(row) {
return !row.instanceId || row.state === '草稿' || row.state === '退回修改'
},
onEdit(row) {
let url = "/platform/appeal/write?id=" + row.id
if (row.startTaskId) {
url += "&taskId=" + row.startTaskId
}
window.location.href = url
},
onDelete(row) {
this.$confirm("您确定删除该申诉吗?", "提示", {type: "warning"}).then(() => {
this.$axios.post("/platform/appeal/mine/delete", {id: row.id}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.pageData()
}
})
})
},
onRevoke(row) {
this.$confirm("您确定撤回当前申诉吗?", "提示", {type: "warning"}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.startTaskId}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.pageData()
}
})
})
},
loadTypeOptions() {
this.$axios.post("/platform/appeal/common/typeOptions").then((res) => {
if (res.code === 0) this.typeOptions = res.data || []
})
}
},
created() {
this.loadTypeOptions()
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,285 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.appeal-query-page .stat-row {
margin: 10px 0;
}
.appeal-query-page .stat-row .el-col {
margin-bottom: 10px;
}
.appeal-query-page .stat-card {
border: 1px solid #ebeef5;
border-radius: 6px;
}
.appeal-query-page .stat-card .el-card__body {
padding: 14px 16px;
}
.appeal-query-page .stat-card-content {
display: flex;
align-items: center;
justify-content: space-between;
min-height: 72px;
}
.appeal-query-page .stat-title {
color: #606266;
font-size: 13px;
line-height: 20px;
}
.appeal-query-page .stat-value {
margin-top: 8px;
color: #303133;
font-size: 28px;
font-weight: 600;
line-height: 32px;
}
.appeal-query-page .stat-tip {
margin-top: 4px;
color: #909399;
font-size: 12px;
line-height: 18px;
}
.appeal-query-page .stat-icon {
width: 42px;
height: 42px;
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
font-size: 22px;
}
.appeal-query-page .stat-total .stat-icon {
color: #409eff;
background: #ecf5ff;
}
.appeal-query-page .stat-wait .stat-icon {
color: #e6a23c;
background: #fdf6ec;
}
.appeal-query-page .stat-execute .stat-icon {
color: #13c2c2;
background: #e6fffb;
}
.appeal-query-page .stat-finish .stat-icon {
color: #67c23a;
background: #f0f9eb;
}
.appeal-query-page .stat-maintain .stat-icon {
color: #3a8ee6;
background: #edf6ff;
}
.appeal-query-page .stat-reprocess .stat-icon {
color: #f56c6c;
background: #fef0f0;
}
.appeal-query-page .table-card {
border-radius: 6px;
}
</style>
<div id="app" v-cloak>
<guava ref="guava" class="appeal-query-page">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker v-model="pageForm.year" type="year" value-format="yyyy" style="width: 100%" placeholder="请选择年度"></el-date-picker>
</search-item>
<search-item label="申诉类型">
<el-select v-model="pageForm.appealTypeId" filterable clearable style="width: 100%" placeholder="请选择申诉类型">
<el-option v-for="item in typeOptions" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</search-item>
<search-item label="申诉标题">
<el-input v-model="pageForm.searchKeyword" clearable placeholder="请输入申诉标题" @keyup.enter.native="doSearch"></el-input>
</search-item>
<search-item label="业务状态">
<el-select v-model="pageForm.state" clearable style="width: 100%" placeholder="请选择业务状态">
<el-option label="待受理" value="待受理"></el-option>
<el-option label="退回修改" value="退回修改"></el-option>
<el-option label="待执行" value="待执行"></el-option>
<el-option label="已办结" value="已办结"></el-option>
</el-select>
</search-item>
<search-item label="申诉单位">
<el-select v-model="pageForm.unitId" filterable clearable style="width: 100%" placeholder="请选择申诉单位">
<el-option v-for="item in unitOptions" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</search-item>
<search-item label="被申诉单位">
<el-select v-model="pageForm.defendantUnitId" filterable clearable style="width: 100%" placeholder="请选择被申诉单位">
<el-option v-for="item in unitOptions" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-row :gutter="12" class="stat-row">
<el-col v-for="item in statCards" :key="item.prop" :xs="24" :sm="12" :md="8" :lg="4">
<el-card shadow="never" class="stat-card" :class="item.className">
<div class="stat-card-content">
<div>
<div class="stat-title">{{ item.title }}</div>
<div class="stat-value">{{ statisticValue(item.prop) }}</div>
<div class="stat-tip">{{ item.tip }}</div>
</div>
<div class="stat-icon">
<i :class="item.icon"></i>
</div>
</div>
</el-card>
</el-col>
</el-row>
<el-card shadow="never" class="table-card">
<table-tool label="申诉列表"></table-tool>
<el-table :data="tableData" @sort-change="pageOrder" style="width: 100%">
<el-table-column type="index" label="序号" width="60" :index="indexMethod"></el-table-column>
<el-table-column prop="title" label="申诉标题" show-overflow-tooltip></el-table-column>
<el-table-column prop="userName" label="申诉人" width="100"></el-table-column>
<el-table-column prop="unitName" label="申诉单位" width="170" show-overflow-tooltip></el-table-column>
<el-table-column prop="appealTypeName" label="申诉类型" width="140"></el-table-column>
<el-table-column prop="defendantUnitName" label="被申诉单位" width="180" show-overflow-tooltip></el-table-column>
<el-table-column prop="applyDate" label="申请日期" width="120"></el-table-column>
<el-table-column prop="decisionType" label="处理决定" width="130">
<template slot-scope="{row}">
<span>{{ decisionTypeText(row.decisionType) || '-' }}</span>
</template>
</el-table-column>
<el-table-column prop="state" label="业务状态" width="100">
<template slot-scope="{row}">
<el-tag :type="stateTagType(row.state)" size="mini">{{ row.state || '草稿' }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="instanceState" label="流程状态" width="110">
<template slot-scope="{row}">
<enum-tag v-if="row.instanceState" :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message" size="small"></enum-tag>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="150">
<template slot-scope="{row}">
<el-button size="mini" type="primary" @click="onOpen(row)">查看</el-button>
<el-button size="mini" type="danger" @click="onDelete(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #view>
<appeal-info ref="infoRef"></appeal-info>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include("../common/info.js"){}#-->
new Vue({
el: "#app",
store,
mixins: [initTableMixins],
components: {
"appeal-info": APPEAL_INFO
},
data() {
return {
pageForm: {
year: new Date().getFullYear().toString()
},
typeOptions: [],
unitOptions: [],
statCards: [
{title: "申诉总数", prop: "totalCount", tip: "当前筛选范围", icon: "el-icon-document", className: "stat-total"},
{title: "待受理", prop: "waitAcceptCount", tip: "委员会待审核", icon: "el-icon-time", className: "stat-wait"},
{title: "待执行", prop: "waitExecuteCount", tip: "单位待反馈", icon: "el-icon-s-operation", className: "stat-execute"},
{title: "已办结", prop: "finishCount", tip: "流程已结束", icon: "el-icon-finished", className: "stat-finish"},
{title: "维持决定", prop: "maintainCount", tip: "维持原处理", icon: "el-icon-circle-check", className: "stat-maintain"},
{title: "重新处理", prop: "reprocessCount", tip: "需重新处理", icon: "el-icon-refresh", className: "stat-reprocess"}
],
statistics: {}
}
},
methods: {
statisticValue(prop) {
return (this.statistics && this.statistics[prop]) || 0
},
stateTagType(state) {
const map = {
"待受理": "warning",
"退回修改": "danger",
"待执行": "",
"已办结": "success"
}
return map[state] || "info"
},
decisionTypeText(value) {
const map = {
"MAINTAIN": "维持原处理",
"REPROCESS": "重新处理",
"REPROCESS_PART": "部分重新处理",
"OTHER": "其他决定"
}
return map[value] || ""
},
onOpen(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
doSearch() {
this.pageNumber = 1
this.pageData()
this.loadStatistics()
},
onDelete(row) {
this.$confirm("您确定删除该申诉吗?", "提示", {type: "warning"}).then(() => {
this.$axios.post("/platform/appeal/query/delete", {id: row.id}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.pageData()
this.loadStatistics()
}
})
})
},
loadOptions() {
this.$axios.post("/platform/appeal/common/typeOptions").then((res) => {
if (res.code === 0) this.typeOptions = res.data || []
})
this.$businessTool.listUnit().then((res) => {
this.unitOptions = res || []
})
},
loadStatistics() {
this.$axios.post("/platform/appeal/query/statistics", this.pageForm).then((res) => {
if (res.code === 0) this.statistics = res.data || {}
})
}
},
created() {
this.loadOptions()
this.pageData()
this.loadStatistics()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,111 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<guava>
<el-card shadow="never">
<search @search="doSearch">
<search-item label="类型名称">
<el-input v-model="pageForm.name" clearable placeholder="请输入类型名称" @keyup.enter.native="doSearch"></el-input>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool>
<el-button type="primary" size="small" icon="el-icon-plus" @click="onAdd">新增</el-button>
</table-tool>
<el-table :data="tableData" @sort-change="pageOrder" style="width: 100%">
<el-table-column type="index" label="序号" width="60" :index="indexMethod"></el-table-column>
<el-table-column prop="name" label="类型名称" show-overflow-tooltip></el-table-column>
<el-table-column prop="sort" label="排序" width="100"></el-table-column>
<el-table-column prop="enabled" label="是否启用" width="120">
<template slot-scope="{row}">
<el-tag size="mini" v-if="row.enabled" type="success">是</el-tag>
<el-tag size="mini" v-else type="info">否</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="160">
<template slot-scope="{row}">
<el-button size="mini" type="primary" @click="onEdit(row)">编辑</el-button>
<el-button size="mini" type="danger" @click="onDelete(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</guava>
<el-dialog :title="formData.id ? '编辑申诉类型' : '新增申诉类型'" :visible.sync="dialogVisible" width="500px" :close-on-click-modal="false">
<el-form :model="formData" ref="formRef" label-width="100px">
<el-form-item label="类型名称" prop="name" :rules="[{required:true,message:'请输入类型名称',trigger:'blur'}]">
<el-input v-model="formData.name" maxlength="100" clearable placeholder="请输入类型名称"></el-input>
</el-form-item>
<el-form-item label="排序" prop="sort">
<el-input-number v-model="formData.sort" :min="0" controls-position="right" style="width: 100%"></el-input-number>
</el-form-item>
<el-form-item label="是否启用" prop="enabled">
<el-switch v-model="formData.enabled"></el-switch>
</el-form-item>
</el-form>
<span slot="footer">
<el-button @click="dialogVisible=false">取消</el-button>
<el-button type="primary" @click="onSubmit">确定</el-button>
</span>
</el-dialog>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
store,
mixins: [initTableMixins],
data() {
return {
dialogVisible: false,
pageForm: {},
formData: {}
}
},
methods: {
onAdd() {
this.formData = {enabled: true, sort: 0}
this.dialogVisible = true
},
onEdit(row) {
this.formData = {...row}
this.dialogVisible = true
},
onSubmit() {
this.$refs.formRef.validate((valid) => {
if (!valid) return
this.$axios.post("/platform/appeal/type/save", {data: JSON.stringify(this.formData)}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.dialogVisible = false
this.pageData()
}
})
})
},
onDelete(row) {
this.$confirm("您确定删除该申诉类型吗?", "提示", {type: "warning"}).then(() => {
this.$axios.post("/platform/appeal/type/delete", {id: row.id}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.pageData()
}
})
})
}
},
created() {
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,215 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<custom-card>
<snaker-start slot="header" label="提交申诉" define_key="SSGL"></snaker-start>
<el-form :model="formData" :rules="formRules" ref="formRef" label-width="130px">
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="申诉人" prop="userName">
<el-input v-model="formData.userName" disabled></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="工号" prop="loginName">
<el-input v-model="formData.loginName" disabled></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="申请日期" prop="applyDate">
<el-date-picker v-model="formData.applyDate" value-format="yyyy-MM-dd" type="date" style="width: 100%" placeholder="请选择申请日期"></el-date-picker>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="所在单位" prop="unitName">
<el-input v-model="formData.unitName" disabled></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="岗位" prop="positionName">
<el-input v-model="formData.positionName" clearable></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="联系电话" prop="mobile">
<el-input v-model="formData.mobile" clearable></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="性别" prop="sex">
<el-input v-model="formData.sex" clearable></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="出生年月" prop="birthday">
<el-date-picker v-model="formData.birthday" value-format="yyyy-MM-dd" type="date" style="width: 100%" placeholder="请选择出生年月"></el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="政治面貌" prop="political">
<el-input v-model="formData.political" clearable maxlength="100"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="住址" prop="address">
<el-input v-model="formData.address" clearable maxlength="300"></el-input>
</el-form-item>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="申诉类型" prop="appealTypeId">
<el-select v-model="formData.appealTypeId" filterable clearable style="width: 100%" @change="onTypeChange">
<el-option v-for="item in typeOptions" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="被申诉单位" prop="defendantUnitId">
<el-select v-model="formData.defendantUnitId" filterable clearable style="width: 100%" @change="onUnitChange">
<el-option v-for="item in unitOptions" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="被申诉单位地址" prop="defendantAddress">
<el-input v-model="formData.defendantAddress" clearable maxlength="300"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="被申诉单位电话" prop="defendantContact">
<el-input v-model="formData.defendantContact" clearable maxlength="100"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="申诉标题" prop="title">
<el-input v-model="formData.title" clearable maxlength="200" placeholder="请输入申诉标题"></el-input>
</el-form-item>
<el-form-item label="申诉事项" prop="appealMatter">
<text-editor v-model="formData.appealMatter"></text-editor>
</el-form-item>
<el-form-item label="申诉理由" prop="reason">
<text-editor v-model="formData.reason"></text-editor>
</el-form-item>
<el-form-item label="申诉要求" prop="request">
<text-editor v-model="formData.request"></text-editor>
</el-form-item>
<el-form-item label="申诉人签名" prop="signature">
<pc-signature v-model="formData.signature"></pc-signature>
</el-form-item>
<el-form-item label="附件" prop="files">
<file-upload :value.sync="formData.files" :upload_number="5" upload_mode="drag" upload_result_category="array" complete_result></file-upload>
</el-form-item>
</el-form>
<template slot="footer">
<el-button type="primary" @click="onSave">保存</el-button>
<el-button type="primary" @click="onSubmit">{{ hasTaskId() ? '提交' : '提交申诉' }}</el-button>
</template>
</custom-card>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
store,
data() {
return {
typeOptions: [],
unitOptions: [],
taskId: null,
formData: {},
formRules: {
appealTypeId: [{required: true, message: "请选择申诉类型", trigger: "change"}],
defendantUnitId: [{required: true, message: "请选择被申诉单位", trigger: "change"}],
title: [{required: true, message: "请输入申诉标题", trigger: "blur"}],
appealMatter: [{required: true, message: "请输入申诉事项", trigger: "blur"}],
reason: [{required: true, message: "请输入申诉理由", trigger: "blur"}],
request: [{required: true, message: "请输入申诉要求", trigger: "blur"}],
signature: [{required: true, message: "请完成申诉人签名", trigger: ["blur", "change"]}]
}
}
},
methods: {
queryParam(name) {
return new URLSearchParams(window.location.search).get(name)
},
loadOptions() {
this.$axios.post("/platform/appeal/common/typeOptions").then((res) => {
if (res.code === 0) this.typeOptions = res.data || []
})
this.$businessTool.listUnit().then((res) => {
this.unitOptions = res || []
})
},
loadCurrentUser() {
this.$axios.post("/platform/appeal/write/currentUserInfo").then((res) => {
if (res.code === 0) {
this.formData = Object.assign({}, res.data, this.formData)
}
})
},
loadInfo(id) {
this.$axios.post("/platform/appeal/write/info", {id}).then((res) => {
if (res.code === 0 && res.data) {
this.formData = res.data
}
})
},
onTypeChange(val) {
const item = this.typeOptions.find((type) => type.id === val)
this.$set(this.formData, "appealTypeName", item ? item.name : "")
},
onUnitChange(val) {
const item = this.unitOptions.find((unit) => unit.id === val)
this.$set(this.formData, "defendantUnitName", item ? item.name : "")
this.$set(this.formData, "defendantAddress", item ? item.address : this.formData.defendantAddress)
this.$set(this.formData, "defendantContact", item ? item.telephone : this.formData.defendantContact)
},
onSave() {
this.$axios.post("/platform/appeal/write/save", {data: JSON.stringify(this.formData)}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.formData = res.data
}
})
},
onSubmit() {
this.$refs.formRef.validate((valid) => {
if (!valid) return
const url = this.hasTaskId() ? "/platform/appeal/write/submitAgain" : "/platform/appeal/write/submit"
this.$confirm("您确定提交该申诉吗?", "提示", {type: "warning"}).then(() => {
this.$axios.post(url, {data: JSON.stringify(this.formData), taskId: this.taskId}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
window.location.href = "/platform/appeal/mine"
}
})
})
})
},
hasTaskId() {
return !!this.taskId && this.taskId !== "undefined" && this.taskId !== "null"
}
},
created() {
this.taskId = this.queryParam("taskId")
const id = this.queryParam("id")
this.loadOptions()
if (id) {
this.loadInfo(id)
} else {
this.loadCurrentUser()
}
}
})
</script>
<!--#
}
#-->