This commit is contained in:
@jyuhsin
2026-03-26 14:03:21 +08:00
parent c5fbf8576c
commit dc71dc22d8
21 changed files with 585 additions and 509 deletions
@@ -4,6 +4,8 @@ import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Dict; import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.budwk.app.base.result.Result; import com.budwk.app.base.result.Result;
import com.budwk.app.base.vo.LabelValueVO; import com.budwk.app.base.vo.LabelValueVO;
import com.budwk.app.flow.constant.FlowConst; import com.budwk.app.flow.constant.FlowConst;
@@ -12,14 +14,8 @@ import com.budwk.app.flow.engine.event.ProcessEvent;
import com.budwk.app.flow.engine.event.ProcessPublisher; import com.budwk.app.flow.engine.event.ProcessPublisher;
import com.budwk.app.flow.engine.model.ProcessModel; import com.budwk.app.flow.engine.model.ProcessModel;
import com.budwk.app.flow.engine.model.TaskModel; import com.budwk.app.flow.engine.model.TaskModel;
import com.budwk.app.flow.entity.Candidate; import com.budwk.app.flow.entity.*;
import com.budwk.app.flow.entity.ProcessDefine; import com.budwk.app.flow.enums.*;
import com.budwk.app.flow.entity.ProcessInstance;
import com.budwk.app.flow.entity.ProcessTask;
import com.budwk.app.flow.enums.ProcessEventTypeEnum;
import com.budwk.app.flow.enums.ProcessInstanceStateEnum;
import com.budwk.app.flow.enums.ProcessTaskPerformTypeEnum;
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
import com.budwk.app.flow.service.FlowCommonService; import com.budwk.app.flow.service.FlowCommonService;
import com.budwk.app.flow.vo.HighLightVO; import com.budwk.app.flow.vo.HighLightVO;
import com.budwk.app.flow.vo.ProcessInstanceVO; import com.budwk.app.flow.vo.ProcessInstanceVO;
@@ -146,20 +142,25 @@ public class FlowCommonController {
@SaCheckLogin @SaCheckLogin
@ApiOperation("获取流程定义的审批记录") @ApiOperation("获取流程定义的审批记录")
public Result approvalRecord(Long instanceId) { public Result approvalRecord(Long instanceId) {
List<ProcessTask> processTaskList = dao.query(ProcessTask.class, Cnd.where(ProcessTask::getProcessInstanceId, "=", instanceId) List<ProcessTask> processTaskList = dao.query(ProcessTask.class, Cnd.where(ProcessTask::getProcessInstanceId, "=", instanceId)
.and(ProcessTask::getTaskState, "not in", List.of(ProcessTaskStateEnum.DOING, ProcessTaskStateEnum.WITHDRAW, ProcessTaskStateEnum.ABANDON)) .and(ProcessTask::getTaskState, "not in", List.of(ProcessTaskStateEnum.WITHDRAW, ProcessTaskStateEnum.ABANDON))
.asc(ProcessTask::getUpdatedAt)); .asc(ProcessTask::getUpdatedAt));
List<ProcessTaskVO> res = new ArrayList<>(); List<ProcessTaskVO> res = new ArrayList<>();
processTaskList.forEach(processTask -> { processTaskList.forEach(processTask -> {
ProcessTaskVO vo = BeanUtil.toBean(processTask, ProcessTaskVO.class); ProcessTaskVO vo = BeanUtil.toBean(processTask, ProcessTaskVO.class);
if (vo.getTaskState().equals(ProcessTaskStateEnum.FINISHED.getCode()) && StrUtil.isNotBlank(vo.getOperator())) { if (vo.getTaskState().equals(ProcessTaskStateEnum.FINISHED.getCode()) && StrUtil.isNotBlank(vo.getOperator())) {
} }
if(vo.getTaskState().equals(ProcessTaskStateEnum.DOING.getCode())) {
List<ProcessTaskActor> taskActorList = dao.query(ProcessTaskActor.class, Cnd.where(ProcessTaskActor::getProcessTaskId, "=", processTask.getId()));
List<JSONObject> list = JSONUtil.toList(JSONUtil.toJsonStr(taskActorList), JSONObject.class);
vo.setTaskActorList(list);
}
res.add(vo); res.add(vo);
}); });
return Result.success(res); return Result.success(res);
} }
@At @At
@SaCheckLogin @SaCheckLogin
@@ -239,7 +240,7 @@ public class FlowCommonController {
@Aop(TransAop.READ_COMMITTED) @Aop(TransAop.READ_COMMITTED)
public Result executeTask(@Param("data") String param) { public Result executeTask(@Param("data") String param) {
Dict args = Json.fromJson(Dict.class, param); Dict args = Json.fromJson(Dict.class, param);
flowCommonService.executeTask(args); flowCommonService.executeTask(args);
return Result.success(); return Result.success();
} }
@@ -19,6 +19,7 @@ import org.nutz.dao.Dao;
import org.nutz.ioc.aop.Aop; import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import java.util.List; import java.util.List;
@@ -37,7 +38,8 @@ public class FlowCommonService {
*/ */
public void executeTask(Dict args){ public void executeTask(Dict args){
Long processTaskId = args.getLong(FlowConst.PROCESS_TASK_ID_KEY); Long processTaskId = args.getLong(FlowConst.PROCESS_TASK_ID_KEY);
String operator = SecurityUtil.getUserId();
String operator = SecurityUtil.getUserId();
if (args.containsKey(FlowConst.EXT_ENABLE_OPERATOR)&&args.getBool(FlowConst.EXT_ENABLE_OPERATOR)){ if (args.containsKey(FlowConst.EXT_ENABLE_OPERATOR)&&args.getBool(FlowConst.EXT_ENABLE_OPERATOR)){
operator = FlowConst.ADMIN_ID; operator = FlowConst.ADMIN_ID;
} }
@@ -46,6 +48,15 @@ public class FlowCommonService {
if (submitType == null) { if (submitType == null) {
submitType = ProcessSubmitTypeEnum.AGREE.getCode(); submitType = ProcessSubmitTypeEnum.AGREE.getCode();
} }
ProcessTask processTask = flowEngine.processTaskService().getById(processTaskId);
ProcessTask parentTask = flowEngine.processTaskService().getById(processTask.getTaskParentId());
Dict taskArgs = Json.fromJson(Dict.class, parentTask.getVariable());
if(taskArgs.containsKey("tf_sourceTaskKey") && !taskArgs.getBool("tf_audit")) {
submitType = ProcessSubmitTypeEnum.JUMP.getCode();
args.put(FlowConst.TASK_NAME, taskArgs.getStr("tf_sourceTaskKey"));
}
args.put(FlowConst.SUBMIT_TYPE, submitType); args.put(FlowConst.SUBMIT_TYPE, submitType);
// 设置办理人信息到表单参数 // 设置办理人信息到表单参数
@@ -270,43 +270,43 @@ public class ProcessInstanceServiceImpl extends BaseServiceImpl<ProcessInstance>
@Override @Override
public HighLightVO highLight(Long processInstanceId) { public HighLightVO highLight(Long processInstanceId) {
HighLightVO vo = new HighLightVO(); HighLightVO vo = new HighLightVO();
ProcessInstanceVO processInstance = findById(processInstanceId); ProcessInstanceVO processInstance = findById(processInstanceId);
FlowEngine flowEngine = ServiceContext.find(FlowEngine.class); FlowEngine flowEngine = ServiceContext.find(FlowEngine.class);
if (processInstance != null) { if (processInstance != null) {
ProcessModel processModel = flowEngine.processDefineService().getProcessModel(processInstance.getProcessDefineId()); ProcessModel processModel = flowEngine.processDefineService().getProcessModel(processInstance.getProcessDefineId());
// 拿到正在进行中的任务==>活跃节点 // 拿到正在进行中的任务==>活跃节点
List<ProcessTask> processTaskList = flowEngine.processTaskService().getDoingTaskList(processInstanceId, new String[]{}); List<ProcessTask> processTaskList = flowEngine.processTaskService().getDoingTaskList(processInstanceId, new String[]{});
// 拿到历史任务-按更新时间倒序 // 拿到历史任务-按更新时间倒序
List<ProcessTask> hisProcessTaskList = flowEngine.processTaskService().query(Cnd.where(ProcessTask::getProcessInstanceId, "=", processInstanceId).desc(ProcessTask::getUpdatedAt)); List<ProcessTask> hisProcessTaskList = flowEngine.processTaskService().query(Cnd.where(ProcessTask::getProcessInstanceId, "=", processInstanceId).desc(ProcessTask::getUpdatedAt));
processTaskList.forEach(task -> { processTaskList.forEach(task -> {
if (!vo.getActiveNodeNames().contains(task.getTaskName())) { if (!vo.getActiveNodeNames().contains(task.getTaskName())) {
vo.getActiveNodeNames().add(task.getTaskName()); vo.getActiveNodeNames().add(task.getTaskName());
recursionModel(processModel.getStart(), processInstance, processTaskList, hisProcessTaskList, task.getTaskName(), vo); recursionModel(processModel.getStart(), processInstance, processTaskList, hisProcessTaskList, task.getTaskName(), vo);
} }
}); });
// 拿到非正常结束的流程实例状态值 // 拿到非正常结束的流程实例状态值
List<Integer> orderStatusList = Arrays.stream(ProcessInstanceStateEnum.values()).filter(item -> !item.equals(ProcessInstanceStateEnum.DOING) && !item.equals(ProcessInstanceStateEnum.FINISHED)).map(ProcessInstanceStateEnum::getCode).toList(); List<Integer> orderStatusList = Arrays.stream(ProcessInstanceStateEnum.values()).filter(item -> !item.equals(ProcessInstanceStateEnum.DOING) && !item.equals(ProcessInstanceStateEnum.FINISHED)).map(ProcessInstanceStateEnum::getCode).toList();
// 非正常结束,需要进行特殊处理 // 非正常结束,需要进行特殊处理
if (orderStatusList.contains(processInstance.getState())) { if (orderStatusList.contains(processInstance.getState())) {
if (CollectionUtil.isNotEmpty(hisProcessTaskList)) { if (CollectionUtil.isNotEmpty(hisProcessTaskList)) {
ProcessTask lastProcessTask = hisProcessTaskList.get(hisProcessTaskList.size() - 1); ProcessTask lastProcessTask = hisProcessTaskList.get(hisProcessTaskList.size() - 1);
NodeModel nodeModel = processModel.getNode(lastProcessTask.getTaskName()); NodeModel nodeModel = processModel.getNode(lastProcessTask.getTaskName());
recursionModel(processModel.getStart(), processInstance, processTaskList, hisProcessTaskList, nodeModel.getOutputs().get(0).getTo(), vo); recursionModel(processModel.getStart(), processInstance, processTaskList, hisProcessTaskList, nodeModel.getOutputs().get(0).getTo(), vo);
} }
} else { } else {
List<EndModel> endModels = processModel.getModels(EndModel.class); List<EndModel> endModels = processModel.getModels(EndModel.class);
if (endModels != null) { if (endModels != null) {
endModels.forEach(endModel -> { endModels.forEach(endModel -> {
recursionModel(processModel.getStart(), processInstance, processTaskList, hisProcessTaskList, endModel.getName(), vo); recursionModel(processModel.getStart(), processInstance, processTaskList, hisProcessTaskList, endModel.getName(), vo);
}); });
} }
} }
} }
return vo; return vo;
} }
@Override @Override
public List<ProcessTaskVO> approvalRecord(Long processInstanceId) { public List<ProcessTaskVO> approvalRecord(Long processInstanceId) {
@@ -195,6 +195,11 @@ public class ProcessTaskServiceImpl extends BaseServiceImpl<ProcessTask> impleme
// execution.getArgs().remove(key); // execution.getArgs().remove(key);
// } // }
// 删一下吧,只保证退回的那个任务节点有这两个字段,不然要出问题喔
if(execution.getArgs().containsKey("tf_sourceTaskKey")) {
execution.getArgs().remove("tf_sourceTaskKey");
execution.getArgs().remove("tf_audit");
}
processTask.setVariable(JSONUtil.toJsonStr(execution.getArgs())); processTask.setVariable(JSONUtil.toJsonStr(execution.getArgs()));
processTask.setCreatedAt(now); processTask.setCreatedAt(now);
processTask.setUpdatedAt(now); processTask.setUpdatedAt(now);
@@ -15,7 +15,7 @@ import java.util.Base64;
public class CspProcessor extends AbstractProcessor { public class CspProcessor extends AbstractProcessor {
public void process(ActionContext ac) throws Throwable { public void process(ActionContext ac) throws Throwable {
// 1. 生成 nonce /*// 1. 生成 nonce
String nonce = Base64.getEncoder().encodeToString( String nonce = Base64.getEncoder().encodeToString(
java.security.SecureRandom.getInstanceStrong().generateSeed(16) java.security.SecureRandom.getInstanceStrong().generateSeed(16)
); );
@@ -34,7 +34,7 @@ public class CspProcessor extends AbstractProcessor {
"frame-ancestors 'self'; " + "frame-ancestors 'self'; " +
"object-src 'self';"; "object-src 'self';";
ac.getResponse().setHeader("Content-Security-Policy", csp); ac.getResponse().setHeader("Content-Security-Policy", csp);*/
doNext(ac); doNext(ac);
} }
@@ -3,12 +3,15 @@ package com.budwk.app.zhgh.democratic.proposal.controller.transact;
import cn.dev33.satoken.annotation.SaCheckPermission; import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.lang.Dict; import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.budwk.app.base.constant.RoleConstant; import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.page.Pagination; import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.result.Result; import com.budwk.app.base.result.Result;
import com.budwk.app.base.vo.LabelValueVO; import com.budwk.app.base.vo.LabelValueVO;
import com.budwk.app.flow.constant.FlowConst; import com.budwk.app.flow.constant.FlowConst;
import com.budwk.app.flow.entity.ProcessInstance;
import com.budwk.app.flow.entity.ProcessTask; import com.budwk.app.flow.entity.ProcessTask;
import com.budwk.app.flow.enums.ProcessSubmitTypeEnum;
import com.budwk.app.flow.enums.ProcessTaskStateEnum; import com.budwk.app.flow.enums.ProcessTaskStateEnum;
import com.budwk.app.flow.service.FlowCommonService; import com.budwk.app.flow.service.FlowCommonService;
import com.budwk.app.flow.service.ProcessTaskService; import com.budwk.app.flow.service.ProcessTaskService;
@@ -136,13 +139,19 @@ public class ProposalSchoolLeaderApprovalController {
return Result.success(); return Result.success();
} }
@At @At
@SaCheckPermission("proposal.schoolLeaderApproval") @SaCheckPermission("proposal.schoolLeaderApproval")
@ApiOperation("执行任务") @ApiOperation("执行任务")
public Result executeTask(@Param("data") String data) { public Result executeTask(@Param("data") String data) {
Dict args = Json.fromJson(Dict.class, data); Dict args = Json.fromJson(Dict.class, data);
if("back".equals(args.getStr("tf_approval"))) {
args.put("submitType", ProcessSubmitTypeEnum.JUMP.getCode());
args.put("taskName", "committee");
flowCommonService.executeTask(args);
return Result.success();
}
String proposalId = args.getStr("proposalId"); String proposalId = args.getStr("proposalId");
ProcessTask thisTask = dao.fetch(ProcessTask.class, args.getLong(FlowConst.PROCESS_TASK_ID_KEY)); ProcessTask thisTask = dao.fetch(ProcessTask.class, args.getLong(FlowConst.PROCESS_TASK_ID_KEY));
@@ -150,8 +159,20 @@ public class ProposalSchoolLeaderApprovalController {
Dict dict = Json.fromJson(Dict.class, parentTask.getVariable()); Dict dict = Json.fromJson(Dict.class, parentTask.getVariable());
args.put("tf_caseFilingResult", dict.getStr("tf_caseFilingResult")); args.put("tf_caseFilingResult", dict.getStr("tf_caseFilingResult"));
args.put("tf_helpunitreply", dict.getStr("tf_helpunitreply"));
args.put("tf_masterUnitId", dict.getStr("tf_masterUnitId"));
args.put("tf_slaveUnitIds", dict.getObj("tf_slaveUnitIds"));
// 方案流程实例 ProcessInstance instance = dao.fetch(ProcessInstance.class, Cnd.where(ProcessInstance::getId, "=", thisTask.getProcessInstanceId()));
Dict instanceDict = Json.fromJson(Dict.class, instance.getVariable());
instanceDict.put("tf_helpunitreply", dict.getStr("tf_helpunitreply"));
instanceDict.put("tf_masterUnitId", dict.getStr("tf_masterUnitId"));
instanceDict.put("tf_slaveUnitIds", dict.getObj("tf_slaveUnitIds"));
instance.setVariable(JSONUtil.toJsonStr(instanceDict));
dao.update(instance);
// 方案流程实例
// 单条审核 // 单条审核
List<String> mergeProposalIds = proposalCommonService.mergeProposal(proposalId); List<String> mergeProposalIds = proposalCommonService.mergeProposal(proposalId);
@@ -161,7 +182,6 @@ public class ProposalSchoolLeaderApprovalController {
} }
// 并案审核 // 并案审核
List<ProcessTask> mergeTasks = processTaskService.getDoingTaskByBizIdTaskName(mergeProposalIds, thisTask.getTaskName()); List<ProcessTask> mergeTasks = processTaskService.getDoingTaskByBizIdTaskName(mergeProposalIds, thisTask.getTaskName());
for (ProcessTask mergeTask : mergeTasks) { for (ProcessTask mergeTask : mergeTasks) {
Dict cloneArgs = args.clone(); Dict cloneArgs = args.clone();
@@ -170,7 +190,4 @@ public class ProposalSchoolLeaderApprovalController {
} }
return Result.success(); return Result.success();
} }
} }
@@ -114,10 +114,11 @@ public class ProposalSecondedController {
LEFT JOIN teacher_congress_delegation tcd on tcd.id = info.delegationId LEFT JOIN teacher_congress_delegation tcd on tcd.id = info.delegationId
$condition $condition
"""); """);
sql.setParam("seconderId", SecurityUtil.getUserId());
Cnd cnd = Cnd.NEW(); Cnd cnd = Cnd.NEW();
cnd.and("t.taskName", "in", List.of("invite", "second", "delegation", "committee")); cnd.and("t.taskName", "in", List.of("invite", "second", "delegation", "committee"));
cnd.and(new Static("ps.isAgree is null")); cnd.and("ps.isAgree", "is", null);
sql.setParam("seconderId", SecurityUtil.getUserId());
if (!AuthUtil.hasRole(RoleConstant.SYSADMIN.name())) { if (!AuthUtil.hasRole(RoleConstant.SYSADMIN.name())) {
cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId())); cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId()));
@@ -53,8 +53,8 @@ public class ProposalUnSubmitQueryController {
tcd.name as delegationName, tcd.name as delegationName,
pt.name as typeName, pt.name as typeName,
manner.name as mannerName, manner.name as mannerName,
(select count(DISTINCT(seconderId))from proposal_seconded where proposalId = info.id) AS secondedNum, (select count(DISTINCT(seconderId))from proposal_second where proposalId = info.id) AS secondedNum,
(select count(DISTINCT(seconderId))from proposal_seconded where proposalId = info.id and isAgree = 1) AS secondedAgreeNum, (select count(DISTINCT(seconderId))from proposal_second where proposalId = info.id and isAgree = 1) AS secondedAgreeNum,
IF(info.stateCode <= 200 ,'未审核','已审核') AS delegationAudit IF(info.stateCode <= 200 ,'未审核','已审核') AS delegationAudit
FROM FROM
proposal_info info proposal_info info
@@ -1,16 +1,24 @@
package com.budwk.app.zhgh.democratic.proposal.handler; package com.budwk.app.zhgh.democratic.proposal.handler;
import cn.hutool.core.lang.Dict; import cn.hutool.core.lang.Dict;
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.AssignmentHandler;
import com.budwk.app.flow.engine.core.Execution; import com.budwk.app.flow.engine.core.Execution;
import com.budwk.app.flow.engine.core.ServiceContext; import com.budwk.app.flow.engine.core.ServiceContext;
import com.budwk.app.flow.engine.model.TaskModel; import com.budwk.app.flow.engine.model.TaskModel;
import com.budwk.app.flow.entity.Candidate; import com.budwk.app.flow.entity.Candidate;
import com.budwk.app.sys.models.Sys_role;
import com.budwk.app.sys.models.Sys_user;
import com.budwk.app.sys.models.Sys_user_role;
import com.budwk.app.sys.services.SysRoleService;
import com.budwk.app.web.controllers.open.commons.service.CommonService;
import com.budwk.app.zhgh.democratic.proposal.models.ProposalConfig; import com.budwk.app.zhgh.democratic.proposal.models.ProposalConfig;
import org.nutz.dao.Cnd; import org.nutz.dao.Cnd;
import org.nutz.dao.Dao; import org.nutz.dao.Dao;
import org.nutz.dao.Sqls; import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql; import org.nutz.dao.sql.Sql;
import org.nutz.lang.Lang;
import org.nutz.lang.util.NutMap; import org.nutz.lang.util.NutMap;
import java.util.List; import java.util.List;
@@ -22,30 +30,19 @@ public class ProposalSchoolLeaderAssignmentHandler implements AssignmentHandler
@Override @Override
public List<String> assign(TaskModel model, Execution execution) { public List<String> assign(TaskModel model, Execution execution) {
Dao dao = ServiceContext.find(Dao.class); CommonService commonService = ServiceContext.find(CommonService.class);
ProposalConfig proposalConfig = dao.fetch(ProposalConfig.class, Cnd.NEW()); List<Sys_user> users = commonService.findUserInfoByRoleCode(RoleConstant.PROPOSAL_BRANCH_SCHOOL_LEADER.name());
List<String> unitIds = proposalConfig.getSchoolLeaderUnitIds();
Sql sql = Sqls.create("select id,username,loginname from vw_user where unitId in (@unitIds)");
sql.setParam("unitIds", unitIds);
sql.setCallback(Sqls.callback.maps());
dao.execute(sql);
List<NutMap> list = sql.getList(NutMap.class);
List<Candidate> candidates = list.stream().map(item -> Candidate.builder() if(Lang.isEmpty(users)) {
.userId(item.getString("id")) throw new BaseException("未查询到相关审批人");
.userName(item.getString("username")) }
.ext(Dict.of("loginName", item.getString("loginname")))
.build() return users.stream().map(Sys_user::getId).toList();
).toList();
if(candidates.size() > 0) {
return candidates.stream().map(Candidate::getUserId).toList();
}
return List.of();
} }
@Override @Override
public String getMessage() { public String getMessage() {
return "指定主管校领导"; return "获取提案主管校领导";
} }
@Override @Override
@@ -3,6 +3,7 @@ package com.budwk.app.zhgh.democratic.proposal.interceptor;
import cn.hutool.core.lang.Dict; import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.budwk.app.base.constant.RoleConstant; import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.flow.constant.FlowConst; import com.budwk.app.flow.constant.FlowConst;
import com.budwk.app.flow.engine.FlowInterceptor; import com.budwk.app.flow.engine.FlowInterceptor;
@@ -100,5 +101,11 @@ public class ProposalCaseFilingInterceptor implements FlowInterceptor {
} }
dao.update(processTaskList,"variable"); dao.update(processTaskList,"variable");
String helpUnitReply = execution.getArgs().getStr(FlowConst.TASK_FORM_DATA_PREFIX + "helpunitreply");
ProcessTask processTask = execution.getProcessTask();
Dict dict = JSONUtil.toBean(processTask.getVariable(), Dict.class);
dict.set(FlowConst.TASK_FORM_DATA_PREFIX + "helpunitreply", helpUnitReply);
processTask.setVariable(JSONUtil.toJsonStr(dict));
dao.update(processTask);
} }
} }
@@ -25,31 +25,31 @@
<div class="column-setting-container"> <div class="column-setting-container">
<div class="column-setting-header"> <div class="column-setting-header">
<el-checkbox <el-checkbox
:indeterminate="isIndeterminate" :indeterminate="isIndeterminate"
v-model="checkAll" v-model="checkAll"
@change="handleCheckAllChange"> @change="handleCheckAllChange">
全选 全选
</el-checkbox> </el-checkbox>
<span class="column-count">已选择 {{ checkedColumns.length }} / {{ tempColumns.length }} </span> <span class="column-count">已选择 {{ checkedColumns.length }} / {{ tempColumns.length }} </span>
</div> </div>
<el-table <el-table
:data="tempColumns" :data="tempColumns"
ref="columnTableRef" ref="columnTableRef"
@selection-change="handleSelectionChange" @selection-change="handleSelectionChange"
row-key="prop" row-key="prop"
class="column-setting-table" class="column-setting-table"
max-height="500px"> max-height="500px">
<el-table-column type="selection" width="55" :selectable="isColumnSelectable"></el-table-column> <el-table-column type="selection" width="55" :selectable="isColumnSelectable"></el-table-column>
<el-table-column label="标题" prop="label" min-width="120"></el-table-column> <el-table-column label="标题" prop="label" min-width="120"></el-table-column>
<!-- <el-table-column label="字段" prop="prop" min-width="100"></el-table-column>--> <!-- <el-table-column label="字段" prop="prop" min-width="100"></el-table-column>-->
<el-table-column label="宽度PX" prop="width" min-width="120"> <el-table-column label="宽度PX" prop="width" min-width="120">
<template slot-scope="{row}"> <template slot-scope="{row}">
<el-input <el-input
v-model="row.width" v-model="row.width"
type="number" type="number"
size="mini" size="mini"
placeholder="自动"> placeholder="自动">
</el-input> </el-input>
</template> </template>
</el-table-column> </el-table-column>
@@ -1,350 +1,360 @@
<!doctype html> <!doctype html>
<html> <html>
<head> <head>
<meta charset="utf-8"/> <meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/> <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width,initial-scale=1.0"/> <meta name="viewport" content="width=device-width,initial-scale=1.0"/>
<title>流程设计器</title> <title>流程设计器</title>
<script src="/assets/platform/plugins/vue/vue.js"></script> <script src="/assets/platform/plugins/vue/vue.js"></script>
<script src="/assets/platform/plugins/jquery/jquery.js"></script> <script src="/assets/platform/plugins/jquery/jquery.js"></script>
<script src="/assets/platform/plugins/element-ui/lib/index.js"></script> <script src="/assets/platform/plugins/element-ui/lib/index.js"></script>
<link rel="stylesheet" href="${base!}/assets/platform/plugins/element-ui/lib/theme-chalk/index.css"/> <link rel="stylesheet" href="${base!}/assets/platform/plugins/element-ui/lib/theme-chalk/index.css"/>
<link rel="stylesheet" href="${base!}/assets/platform/plugins/element-ui/lib/theme-chalk/index.css"/> <link rel="stylesheet" href="${base!}/assets/platform/plugins/element-ui/lib/theme-chalk/index.css"/>
<link rel="stylesheet" href="${base!}/assets/platform/plugins/element-ui/lib/theme-chalk/override.css"/> <link rel="stylesheet" href="${base!}/assets/platform/plugins/element-ui/lib/theme-chalk/override.css"/>
<!-- 引入 core 包和对应 css--> <!-- 引入 core 包和对应 css-->
<script src="/assets/platform/plugins/logicflow/logic-flow.js"></script> <script src="/assets/platform/plugins/logicflow/logic-flow.js"></script>
<link rel="stylesheet" href="/assets/platform/plugins/logicflow/index.css"/> <link rel="stylesheet" href="/assets/platform/plugins/logicflow/index.css"/>
<script src="https://cdn.jsdelivr.net/npm/@logicflow/extension@2.1.4/dist/index.min.js"></script> <script src="/assets/platform/plugins/logicflow/index.min.js"></script>
<script src="/assets/platform/plugins/snaker/SnakerflowDesigner.umd.js"></script> <!-- <script src="https://cdn.jsdelivr.net/npm/@logicflow/extension@2.1.4/dist/index.min.js"></script>-->
<style> <script src="/assets/platform/plugins/snaker/SnakerflowDesigner.umd.js"></script>
#snaker-flow-preview { <style>
height: 100vh; #snaker-flow-preview {
} height: 100vh;
}
.approval-card { .approval-card {
position: absolute; position: absolute;
width: 320px; width: 320px;
background: #ffffff; background: #ffffff;
border-radius: 8px; border-radius: 8px;
border: 1px solid #d9e3f0; border: 1px solid #d9e3f0;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
z-index: 1000; z-index: 1000;
font-family: "Microsoft YaHei", "PingFang SC", sans-serif; font-family: "Microsoft YaHei", "PingFang SC", sans-serif;
transform: translate(10px, 10px); transform: translate(10px, 10px);
overflow: hidden; overflow: hidden;
} }
.tab-container { .tab-container {
border-bottom: 1px solid #e8e8e8; border-bottom: 1px solid #e8e8e8;
} }
.tab-header { .tab-header {
display: flex; display: flex;
background: #fafafa; background: #fafafa;
} }
.tab-item { .tab-item {
padding: 8px 16px; padding: 8px 16px;
cursor: pointer; cursor: pointer;
border-right: 1px solid #e8e8e8; border-right: 1px solid #e8e8e8;
font-size: 12px; font-size: 12px;
color: #666; color: #666;
background: #fafafa; background: #fafafa;
transition: all 0.2s; transition: all 0.2s;
} }
.tab-item:last-child { .tab-item:last-child {
border-right: none; border-right: none;
} }
.tab-item.active { .tab-item.active {
background: #fff; background: #fff;
color: #333; color: #333;
border-bottom: 2px solid #1890ff; border-bottom: 2px solid #1890ff;
margin-bottom: -1px; margin-bottom: -1px;
} }
.tab-item:hover { .tab-item:hover {
background: #f0f0f0; background: #f0f0f0;
color: #333; color: #333;
} }
/* 卡片标题栏(OA风格顶部色条) */ /* 卡片标题栏(OA风格顶部色条) */
.approval-card .card-header { .approval-card .card-header {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
padding: 12px 16px; padding: 12px 16px;
background: #1a73e8; background: #1a73e8;
color: white; color: white;
} }
.approval-card .card-header h3 { .approval-card .card-header h3 {
margin: 0; margin: 0;
font-size: 15px; font-size: 15px;
font-weight: 500; font-weight: 500;
letter-spacing: 0.5px; letter-spacing: 0.5px;
} }
.approval-card .card-header button { .approval-card .card-header button {
background: rgba(255, 255, 255, 0.2); background: rgba(255, 255, 255, 0.2);
border: none; border: none;
width: 24px; width: 24px;
height: 24px; height: 24px;
border-radius: 50%; border-radius: 50%;
color: white; color: white;
font-size: 16px; font-size: 16px;
line-height: 1; line-height: 1;
cursor: pointer; cursor: pointer;
transition: all 0.2s; transition: all 0.2s;
} }
.approval-card .card-header button:hover { .approval-card .card-header button:hover {
background: rgba(255, 255, 255, 0.3); background: rgba(255, 255, 255, 0.3);
} }
/* 卡片内容区域 */ /* 卡片内容区域 */
.approval-card .card-body { .approval-card .card-body {
padding: 16px; padding: 16px;
} }
/* 信息行样式 */ /* 信息行样式 */
.approval-card .info-row { .approval-card .info-row {
display: flex; display: flex;
margin-bottom: 12px; margin-bottom: 12px;
align-items: flex-start; align-items: flex-start;
} }
.approval-card .info-label { .approval-card .info-label {
width: 80px; width: 80px;
color: #666; color: #666;
font-size: 13px; font-size: 13px;
line-height: 1.5; line-height: 1.5;
} }
.approval-card .info-value { .approval-card .info-value {
flex: 1; flex: 1;
color: #333; color: #333;
font-size: 13px; font-size: 13px;
line-height: 1.5; line-height: 1.5;
word-break: break-all; word-break: break-all;
} }
/*!* 分隔线 *!*/ /*!* 分隔线 *!*/
/*.approval-card .divider {*/ /*.approval-card .divider {*/
/* height: 1px;*/ /* height: 1px;*/
/* background: #f0f0f0;*/ /* background: #f0f0f0;*/
/* margin: 12px 0;*/ /* margin: 12px 0;*/
/*}*/ /*}*/
</style> </style>
</head> </head>
<body> <body>
<div id="snaker-flow-preview"> <div id="snaker-flow-preview">
<snaker-flow-designer <snaker-flow-designer
ref="designer" ref="designer"
v-model="flowData" v-model="flowData"
:show-doc="false" :show-doc="false"
:viewer="true" :viewer="true"
node-render-type="html" node-render-type="html"
:high-light="highLight" :high-light="highLight"
></snaker-flow-designer> ></snaker-flow-designer>
<div <div
v-if="showApprovalCard" v-if="showApprovalCard"
class="approval-card" class="approval-card"
:style="{ :style="{
left: cardPosition.x+'px', left: cardPosition.x+'px',
top: cardPosition.y+'px' top: cardPosition.y+'px'
}" }"
> >
<div class="card-header"> <div class="card-header">
<h3>详情</h3> <h3>详情</h3>
<button @click="closeCard">×</button> <button @click="closeCard">×</button>
</div> </div>
<!-- Tab切换 --> <!-- Tab切换 -->
<div class="tab-container" v-if="approvalInfos.length > 1"> <div class="tab-container" v-if="approvalInfos.length > 1">
<div class="tab-header"> <div class="tab-header">
<div <div
v-for="(item, index) in approvalInfos" v-for="(item, index) in approvalInfos"
:key="index" :key="index"
class="tab-item" class="tab-item"
:class="{active: activeTabIndex === index}" :class="{active: activeTabIndex === index}"
@click="activeTabIndex = index" @click="activeTabIndex = index"
> >
记录{{index + 1}} 记录{{index + 1}}
</div>
</div>
</div> </div>
</div>
</div>
<div class="card-body"> <div class="card-body">
<div v-for="(approvalInfo, index) in approvalInfos" :key="index" v-show="activeTabIndex === index"> <div v-for="(approvalInfo, index) in approvalInfos" :key="index" v-show="activeTabIndex === index">
<div class="info-row"> <div class="info-row">
<span class="info-label">节点类型:</span> <span class="info-label">节点类型:</span>
<span class="info-value">{{approvalInfo.displayName}}</span> <span class="info-value">{{approvalInfo.displayName}}</span>
</div> </div>
<div class="info-row"> <div class="info-row">
<span class="info-label">审批人:</span> <span class="info-label">审批人:</span>
<span class="info-value" v-if="currentNode.id === 'startTask'"> <span class="info-value" v-if="currentNode.id === 'startTask'">
{{approvalInfo.ext?.initiatorName}}({{approvalInfo.ext?.initiatorAccount}}) {{approvalInfo.ext?.initiatorName}}({{approvalInfo.ext?.initiatorAccount}})
</span> </span>
<span class="info-value" <span class="info-value" v-else-if="approvalInfo.taskState === 10">
v-else>{{approvalInfo.taskFormData.userName}}({{approvalInfo.taskFormData?.loginName}})</span> {{ approvalInfo.taskActorList.map(u => u.actorName + '(' + u.actorAccount + ')').join('、') }}
</div> </span>
<div class="info-row"> <span class="info-value"
<span class="info-label">审核状态:</span> v-else>{{approvalInfo.taskFormData.userName}}({{approvalInfo.taskFormData?.loginName}})</span>
<span class="info-value">{{getTaskStateText(approvalInfo.taskState)}}</span> </div>
</div> <div class="info-row">
<div class="info-row"> <span class="info-label">审核状态:</span>
<span class="info-label">提交结果:</span> <span class="info-value">{{getTaskStateText(approvalInfo.taskState)}}</span>
<span class="info-value">{{getSubmitTypeText(approvalInfo.ext.submitType)}}</span> </div>
</div> <div class="info-row">
<div class="info-row"> <span class="info-label">提交结果:</span>
<span class="info-label">提交意见:</span> <span class="info-value" v-if="approvalInfo.taskState !== 10">
<span class="info-value">{{approvalInfo.taskFormData.opinion}}</span> {{getSubmitTypeText(approvalInfo.ext.submitType)}}
</div> </span>
<!-- <div class="divider"></div>--> <span class="info-value" v-else>
<div class="info-row"> 暂未处理
<span class="info-label">提交时间:</span> </span>
<span class="info-value">{{approvalInfo.finishTime}}</span> </div>
<div class="info-row">
<span class="info-label">提交意见:</span>
<span class="info-value" v-if="approvalInfo.taskState !== 10">{{approvalInfo.taskFormData.opinion}}</span>
<span class="info-value" v-else>暂未处理</span>
</div>
<!-- <div class="divider"></div>-->
<div class="info-row">
<span class="info-label">提交时间:</span>
<span class="info-value">{{approvalInfo.finishTime || '暂未处理'}}</span>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </body>
</div> <script>
</body> Vue.use(SnakerflowDesigner.default)
<script nonce="${cspNonce!}"> const vue = new Vue({
Vue.use(SnakerflowDesigner.default) el: "#snaker-flow-preview",
const vue = new Vue({ data() {
el: "#snaker-flow-preview", return {
data() { // 流程定义ID
return { defineId: "${defineId!}",
// 流程定义ID // 流程实例ID
defineId: "${defineId!}", instanceId: "${instanceId!}",
// 流程实例ID // 流程定义数据
instanceId: "${instanceId!}", flowData: {},
// 流程定义数据 // 高亮数据
flowData: {}, highLight: {},
// 高亮数据 // 历史审批记录
highLight: {}, hisApproval: [],
// 历史审批记录 // 展示已审核信息
hisApproval: [], showApprovalCard: false,
// 展示已审核信息 // 审批信息卡片位置
showApprovalCard: false, cardPosition: {x: 0, y: 0},
// 审批信息卡片位置 // 当前节点
cardPosition: {x: 0, y: 0}, currentNode: [],
// 当前节点 // 审批信息数组
currentNode: [], approvalInfos: [],
// 审批信息数组 // 当前选中的tab索引
approvalInfos: [], activeTabIndex: 0
// 当前选中的tab索引 }
activeTabIndex: 0
}
},
computed: {
// approvalInfo() {
// if (this.currentNode) {
// return this.hisApproval.find((item) => item.taskName === this.currentNode.id)
// }
// }
},
methods: {
getDetail() {
$.get("/flow/define/detail", {id: this.defineId}).then((res) => {
if (res.code === 0) {
this.flowData = res.data.content
this.initNodeEvent()
}
})
}, },
getHighLight() { computed: {
$.get("/flow/common/instanceHighLight", {instanceId: this.instanceId}).then((res) => { // approvalInfo() {
if (res.code === 0) { // if (this.currentNode) {
this.highLight = res.data // return this.hisApproval.find((item) => item.taskName === this.currentNode.id)
} // }
}) // }
}, },
methods: {
getHisApproval() { getDetail() {
$.get("/flow/common/approvalRecord", {instanceId: this.instanceId}).then((res) => { $.get("/flow/define/detail", {id: this.defineId}).then((res) => {
if (res.code === 0) { if (res.code === 0) {
this.hisApproval = res.data this.flowData = res.data.content
} this.initNodeEvent()
})
},
initNodeEvent() {
this.$nextTick(() => {
console.log(this.$refs.designer.lf.graphModel.eventCenter)
this.$refs.designer.lf.graphModel.eventCenter.on("node:click", ({e, data}) => {
console.log(data)
console.log(e)
// 获取点击位置(考虑页面滚动情况)
const scrollX = window.scrollX || window.pageXOffset
const scrollY = window.scrollY || window.pageYOffset
this.cardPosition = {
x: e.clientX + scrollX,
y: e.clientY + scrollY
}
if (data.type !== "snaker:task") return
const approvalInfos = this.hisApproval.filter((item) => item.taskName === data.id && item.taskState === 20)
if (approvalInfos && approvalInfos.length > 0) {
this.approvalInfos = approvalInfos
this.currentNode = data
this.activeTabIndex = 0
this.showApprovalCard = true
} }
}) })
},
this.$refs.designer.lf.graphModel.eventCenter.on("blank:click", (args) => { getHighLight() {
this.closeCard() $.get("/flow/common/instanceHighLight", {instanceId: this.instanceId}).then((res) => {
if (res.code === 0) {
this.highLight = res.data
}
}) })
}) },
},
closeCard() { getHisApproval() {
this.showApprovalCard = false $.get("/flow/common/approvalRecord", {instanceId: this.instanceId}).then((res) => {
this.activeTabIndex = 0 if (res.code === 0) {
}, this.hisApproval = res.data
}
})
},
// 获取任务状态文本 initNodeEvent() {
getTaskStateText(taskState) { this.$nextTick(() => {
const stateMap = { console.log(this.$refs.designer.lf.graphModel.eventCenter)
10: "进行中", this.$refs.designer.lf.graphModel.eventCenter.on("node:click", ({e, data}) => {
20: "已完成", console.log(data)
30: "已撤回" console.log(e)
// 获取点击位置(考虑页面滚动情况)
const scrollX = window.scrollX || window.pageXOffset
const scrollY = window.scrollY || window.pageYOffset
this.cardPosition = {
x: e.clientX + scrollX,
y: e.clientY + scrollY
}
if (data.type !== "snaker:task") return
const approvalInfos = this.hisApproval.filter((item) => item.taskName === data.id && [10, 20].includes(item.taskState))
if (approvalInfos && approvalInfos.length > 0) {
this.approvalInfos = approvalInfos
this.currentNode = data
this.activeTabIndex = 0
this.showApprovalCard = true
}
})
this.$refs.designer.lf.graphModel.eventCenter.on("blank:click", (args) => {
this.closeCard()
})
})
},
closeCard() {
this.showApprovalCard = false
this.activeTabIndex = 0
},
// 获取任务状态文本
getTaskStateText(taskState) {
const stateMap = {
10: "进行中",
20: "已完成",
30: "已撤回"
}
return stateMap[taskState] || taskState
},
// 获取提交结果文本
getSubmitTypeText(submitType) {
const typeMap = {
0: "发起申请",
1: "同意申请",
2: "拒绝申请",
3: "退回上一步",
4: "跳转",
5: "重新提交",
6: "退回发起人",
20: "拒绝申请"
}
return typeMap[submitType] || submitType
} }
return stateMap[taskState] || taskState
}, },
mounted() {
// 获取提交结果文本 if (this.defineId) {
getSubmitTypeText(submitType) { this.getDetail()
const typeMap = { }
0: "发起申请", if (this.instanceId) {
1: "同意申请", this.getHighLight()
2: "拒绝申请", this.getHisApproval()
3: "退回上一步",
4: "跳转",
5: "重新提交",
6: "退回发起人",
20: "拒绝申请"
} }
return typeMap[submitType] || submitType
} }
}, })
mounted() { </script>
if (this.defineId) {
this.getDetail()
}
if (this.instanceId) {
this.getHighLight()
this.getHisApproval()
}
}
})
</script>
</html> </html>
@@ -5,6 +5,7 @@ const PROPOSAL_INFO = {
<div class="proposal-info"> <div class="proposal-info">
<div class="process-title"> <div class="process-title">
提案基础信息 提案基础信息
<el-link type="primary" @click="openChart">点击查看流程图</el-link>
</div> </div>
<h3 style="text-align: center;font-weight: 600" class="pt10 pb10"> <h3 style="text-align: center;font-weight: 600" class="pt10 pb10">
{{ viewData.name }} {{ viewData.name }}
@@ -197,6 +198,7 @@ const PROPOSAL_INFO = {
</template> </template>
<slot></slot> <slot></slot>
<snaker-chart ref="snakerChartRef"></snaker-chart>
</div> </div>
`, `,
dicts: ["PROPOSAL_TYPE", "PROPOSAL_CASE_FILING_RESULT", "PROPOSAL_CASE_FILING_TYPE", "PROCESS_TASK_SUBMIT_TYPE", "PROPOSAL_FEEDBACK"], dicts: ["PROPOSAL_TYPE", "PROPOSAL_CASE_FILING_RESULT", "PROPOSAL_CASE_FILING_TYPE", "PROCESS_TASK_SUBMIT_TYPE", "PROPOSAL_FEEDBACK"],
@@ -246,6 +248,9 @@ const PROPOSAL_INFO = {
}) })
}, },
openChart(){
this.$refs.snakerChartRef.onOpenFull(this.row.instanceProcessDefineId, this.row.instanceId)
}
}, },
style: style:
/*language=CSS*/ /*language=CSS*/
@@ -68,9 +68,9 @@ layout("/layouts/platform.html"){
v-if="column.visible !== false" v-if="column.visible !== false"
> >
<template v-if="column.prop === 'caseFilingResult'" scope="{row}"> <template v-if="column.prop === 'caseFilingResult'" scope="{row}">
<dict-tag v-if="row.taskState!==10" <dict-tag
:options="dict.type.PROPOSAL_CASE_FILING_RESULT" :options="dict.type.PROPOSAL_CASE_FILING_RESULT"
:value="row.caseFilingResult"></dict-tag> :value="JSON.parse(row.taskVariable)?.tf_caseFilingResult"></dict-tag>
</template> </template>
<template v-else-if="column.prop === 'merge'" scope="{row}"> <template v-else-if="column.prop === 'merge'" scope="{row}">
<el-tag v-if="row.merge" size="small"></el-tag> <el-tag v-if="row.merge" size="small"></el-tag>
@@ -148,9 +148,9 @@ layout("/layouts/platform.html"){
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="审核意见" prop="approvalOpinion" <el-form-item label="审核意见" prop="tf_opinion"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]"> :rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<user-opinion-textarea v-model="formData.approvalOpinion"></user-opinion-textarea> <user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
</el-form-item> </el-form-item>
</el-form> </el-form>
<el-row type="flex" justify="end"> <el-row type="flex" justify="end">
@@ -44,7 +44,7 @@ layout("/layouts/platform.html"){
<!-- </search-item>--> <!-- </search-item>-->
</search> </search>
</el-card> </el-card>
<el-card shadow="never"> <el-card shadow="never">
<table-tool :columns.sync="tableColumns"> <table-tool :columns.sync="tableColumns">
<!-- <el-button type="primary" icon="el-icon-plus" size="small" @click="openMerge">并案审核</el-button>--> <!-- <el-button type="primary" icon="el-icon-plus" size="small" @click="openMerge">并案审核</el-button>-->
@@ -69,9 +69,9 @@ layout("/layouts/platform.html"){
v-if="column.visible !== false" v-if="column.visible !== false"
> >
<template v-if="column.prop === 'caseFilingResult'" scope="{row}"> <template v-if="column.prop === 'caseFilingResult'" scope="{row}">
<dict-tag v-if="row.taskState!==10" <dict-tag
:options="dict.type.PROPOSAL_CASE_FILING_RESULT" :options="dict.type.PROPOSAL_CASE_FILING_RESULT"
:value="row.caseFilingResult"></dict-tag> :value="JSON.parse(row.taskVariable)?.tf_caseFilingResult"></dict-tag>
</template> </template>
<template v-else-if="column.prop === 'merge'" scope="{row}"> <template v-else-if="column.prop === 'merge'" scope="{row}">
<el-tag v-if="row.merge" size="small"></el-tag> <el-tag v-if="row.merge" size="small"></el-tag>
@@ -93,7 +93,7 @@ layout("/layouts/platform.html"){
</el-table> </el-table>
<!--#include("/layouts/pagination.html"){}#--> <!--#include("/layouts/pagination.html"){}#-->
</el-card> </el-card>
<template #edit> <template #edit>
<proposal-info ref="proposalInfoRef" @done-tasks="doneTasks"> <proposal-info ref="proposalInfoRef" @done-tasks="doneTasks">
<div v-if="showApprovalForm"> <div v-if="showApprovalForm">
@@ -162,7 +162,7 @@ layout("/layouts/platform.html"){
</div> </div>
</proposal-info> </proposal-info>
</template> </template>
<template #public> <template #public>
<merge ref="mergeRef" @close="$refs.guava.index()"></merge> <merge ref="mergeRef" @close="$refs.guava.index()"></merge>
</template> </template>
@@ -172,7 +172,7 @@ layout("/layouts/platform.html"){
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
<!--#include('../../common/info.js'){}#--> <!--#include('../../common/info.js'){}#-->
<!--#include('../committeeFiling/merge.js'){}#--> <!--#include('../committeeFiling/merge.js'){}#-->
new Vue({ new Vue({
el: "#app", el: "#app",
store, store,
@@ -237,7 +237,7 @@ layout("/layouts/platform.html"){
this.$refs.proposalInfoRef.onOpen(row) this.$refs.proposalInfoRef.onOpen(row)
}) })
}, },
handleTaskAction(val) { handleTaskAction(val) {
this.$refs.formRef.validate(valid => { this.$refs.formRef.validate(valid => {
if (!valid) return if (!valid) return
@@ -253,7 +253,7 @@ layout("/layouts/platform.html"){
} else { } else {
tf_helpunitreply = 'NO_HELP_UNIT' tf_helpunitreply = 'NO_HELP_UNIT'
} }
const loading = createLoading('提交中') const loading = createLoading('提交中')
this.$axios.post("/platform/proposal/committeeFilingUnit/executeTask", { this.$axios.post("/platform/proposal/committeeFilingUnit/executeTask", {
data: JSON.stringify({ data: JSON.stringify({
@@ -276,7 +276,7 @@ layout("/layouts/platform.html"){
}) })
}) })
}, },
// 打开并案审核 // 打开并案审核
openMerge() { openMerge() {
const selection = this.$refs.tableRef.selection const selection = this.$refs.tableRef.selection
@@ -293,7 +293,7 @@ layout("/layouts/platform.html"){
}) })
}) })
}, },
onRevoke(row) { onRevoke(row) {
this.$confirm("您确定要撤回吗?", "提示", { this.$confirm("您确定要撤回吗?", "提示", {
confirmButtonText: "确定", confirmButtonText: "确定",
@@ -311,12 +311,12 @@ layout("/layouts/platform.html"){
}) })
}) })
}, },
// 教代会 // 教代会
async meetingChange(val) { async meetingChange(val) {
this.doSearch() this.doSearch()
}, },
// 查询开启的教代会 // 查询开启的教代会
listOpenSession() { listOpenSession() {
this.$axios.post("/platform/proposal/common/listOpenSession").then((res) => { this.$axios.post("/platform/proposal/common/listOpenSession").then((res) => {
@@ -329,7 +329,7 @@ layout("/layouts/platform.html"){
} }
}) })
}, },
// 查询承办单位 // 查询承办单位
listUnderTake() { listUnderTake() {
this.$axios.post("/platform/proposal/common/listUnderTake").then((res) => { this.$axios.post("/platform/proposal/common/listUnderTake").then((res) => {
@@ -23,7 +23,7 @@ layout("/layouts/platform.html"){
</el-card> </el-card>
<el-card shadow="never"> <el-card shadow="never">
<table-tool :columns.sync="tableColumns"> <table-tool :columns.sync="tableColumns">
<el-button class="ml5" icon="el-icon-upload2" plain type="primary" <el-button class="ml5" icon="el-icon-upload2" type="primary" size="small"
@click="openImport">导入提案 @click="openImport">导入提案
</el-button> </el-button>
</table-tool> </table-tool>
@@ -21,7 +21,7 @@ layout("/layouts/platform.html"){
</search-item> </search-item>
</search> </search>
</el-card> </el-card>
<el-card shadow="never"> <el-card shadow="never">
<table-tool :columns.sync="tableColumns"> <table-tool :columns.sync="tableColumns">
<el-radio-group v-model="pageForm.approval" size="small" @change="doSearch"> <el-radio-group v-model="pageForm.approval" size="small" @change="doSearch">
@@ -58,7 +58,7 @@ layout("/layouts/platform.html"){
</el-table> </el-table>
<!--#include("/layouts/pagination.html"){}#--> <!--#include("/layouts/pagination.html"){}#-->
</el-card> </el-card>
<template #edit> <template #edit>
<proposal-info ref="proposalInfoRef"> <proposal-info ref="proposalInfoRef">
<div v-if="showApprovalForm"> <div v-if="showApprovalForm">
@@ -74,7 +74,8 @@ layout("/layouts/platform.html"){
</el-form> </el-form>
<el-row type="flex" justify="end"> <el-row type="flex" justify="end">
<el-button @click="$refs.guava.index()" size="small">取消</el-button> <el-button @click="$refs.guava.index()" size="small">取消</el-button>
<el-button @click="handleTaskAction(6)" size="small" type="info">退回到提案人</el-button> <el-button @click="handleTaskAction(4)" size="small" type="info">退回到提案人(不审核)</el-button>
<el-button @click="handleTaskAction(6)" size="small" type="info">退回到提案人(审核)</el-button>
<el-button @click="handleTaskAction(2)" size="small" type="danger">不同意</el-button> <el-button @click="handleTaskAction(2)" size="small" type="danger">不同意</el-button>
<el-button @click="handleTaskAction(1)" size="small" type="primary">同意</el-button> <el-button @click="handleTaskAction(1)" size="small" type="primary">同意</el-button>
</el-row> </el-row>
@@ -85,7 +86,7 @@ layout("/layouts/platform.html"){
</div> </div>
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
<!--#include('../../common/info.js'){}#--> <!--#include('../../common/info.js'){}#-->
new Vue({ new Vue({
el: "#app", el: "#app",
store, store,
@@ -122,18 +123,19 @@ layout("/layouts/platform.html"){
this.$refs.proposalInfoRef.onOpen(row) this.$refs.proposalInfoRef.onOpen(row)
}) })
}, },
openAudit(row) { openAudit(row) {
this.$refs.guava.edit(() => { this.$refs.guava.edit(() => {
this.showApprovalForm = true this.showApprovalForm = true
this.formData = { this.formData = {
processTaskId: row.taskId, processTaskId: row.taskId,
taskName: row.curTaskName taskName: row.curTaskName,
taskKey: row.taskKey
} }
this.$refs.proposalInfoRef.onOpen(row) this.$refs.proposalInfoRef.onOpen(row)
}) })
}, },
// 查询开启的教代会 // 查询开启的教代会
listOpenSession() { listOpenSession() {
this.$axios.post("/platform/proposal/common/listOpenSession").then((res) => { this.$axios.post("/platform/proposal/common/listOpenSession").then((res) => {
@@ -142,12 +144,11 @@ layout("/layouts/platform.html"){
if (this.sessionOptions) { if (this.sessionOptions) {
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id) this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
this.pageData() this.pageData()
this.listDelegation()
} }
} }
}) })
}, },
handleTaskAction(val) { handleTaskAction(val) {
this.$refs.formRef.validate(valid => { this.$refs.formRef.validate(valid => {
if (!valid) return if (!valid) return
@@ -156,11 +157,17 @@ layout("/layouts/platform.html"){
cancelButtonText: "取消", cancelButtonText: "取消",
type: "warning" type: "warning"
}).then(() => { }).then(() => {
const params = {
...this.formData,
submitType: val,
taskName: 'startTask'
}
if(val === 4) {
params.tf_sourceTaskKey = this.formData.taskKey
params.tf_audit = false
}
this.$axios.post("/flow/common/executeTask", { this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({ data: JSON.stringify(params)
...this.formData,
submitType: val
})
}).then((res) => { }).then((res) => {
if (res.code === 0) { if (res.code === 0) {
this.$refs.guava.index() this.$refs.guava.index()
@@ -170,7 +177,22 @@ layout("/layouts/platform.html"){
}) })
}) })
}) })
} },
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()
}
})
})
},
} }
}) })
</script> </script>
@@ -108,9 +108,8 @@ layout("/layouts/platform.html"){
</el-form> </el-form>
<el-row type="flex" justify="end"> <el-row type="flex" justify="end">
<el-button @click="$refs.guava.index()" size="small">取消</el-button> <el-button @click="$refs.guava.index()" size="small">取消</el-button>
<el-button @click="handleTaskAction('back')" size="small" type="danger">退回重新答复 <el-button @click="handleTaskAction('back')" size="small" type="danger">退回提委会立案</el-button>
</el-button> <el-button @click="handleTaskAction('agree')" size="small" type="primary">同意</el-button>
<el-button @click="handleTaskAction('agree')" size="small" type="primary">同意答复</el-button>
</el-row> </el-row>
</div> </div>
</proposal-info> </proposal-info>
@@ -161,14 +161,14 @@ layout("/layouts/platform.html"){
this.$refs.guava.index() this.$refs.guava.index()
this.$message.success(res.msg) this.$message.success(res.msg)
this.doSearch() this.doSearch()
this.updateSecond(val) this.updateSecond(val, false)
} }
}) })
}) })
}) })
}, },
updateSecond(submitType) { updateSecond(submitType, flag = true) {
this.$axios.post("/platform/proposal/seconded/updateInfo", { this.$axios.post("/platform/proposal/seconded/updateInfo", {
proposalId: this.row.id, proposalId: this.row.id,
taskActorUserId: this.row.taskActorUserId, taskActorUserId: this.row.taskActorUserId,
@@ -177,8 +177,8 @@ layout("/layouts/platform.html"){
}).then((res) => { }).then((res) => {
if (res.code === 0) { if (res.code === 0) {
this.$refs.guava.index() this.$refs.guava.index()
this.$message.success(res.msg) if(flag) this.$message.success(res.msg)
this.doSearch() this.doSearch()
} }
}) })
}, },
@@ -13,9 +13,9 @@ layout("/layouts/platform.html"){
v-for="item in sessionOptions"></el-option> v-for="item in sessionOptions"></el-option>
</el-select> </el-select>
</search-item> </search-item>
<search-item> <search-item label="名称/编号">
<el-input @keyup.enter.native="doSearch" clearable placeholder="请输入内容" <el-input @keyup.enter.native="doSearch" clearable placeholder="请输入内容"
style="width: 90%" v-model="pageForm.searchKeyword"> v-model="pageForm.searchKeyword">
<el-select placeholder="查询类型" slot="prepend" style="width: 110px;" <el-select placeholder="查询类型" slot="prepend" style="width: 110px;"
v-model="pageForm.searchName"> v-model="pageForm.searchName">
<el-option label="提案名称" value="proposalName"></el-option> <el-option label="提案名称" value="proposalName"></el-option>
@@ -23,10 +23,10 @@ layout("/layouts/platform.html"){
</el-select> </el-select>
</el-input> </el-input>
</search-item> </search-item>
<search-item> <search-item label="提案人">
<el-input @keyup.enter.native="doSearch" clearable placeholder="请输入内容" <el-input @keyup.enter.native="doSearch" clearable placeholder="请输入内容"
style="width: 90%" v-model="pageForm.searchKeyword2"> v-model="pageForm.searchKeyword2">
<el-select placeholder="查询类型" slot="prepend" style="width: 100px;" <el-select placeholder="查询类型" slot="prepend" style="width: 110px;"
v-model="pageForm.searchName2"> v-model="pageForm.searchName2">
<el-option label="提案人" value="su.username"></el-option> <el-option label="提案人" value="su.username"></el-option>
<!-- <el-option label="附议人" value="seconded.username"></el-option>--> <!-- <el-option label="附议人" value="seconded.username"></el-option>-->
@@ -36,6 +36,7 @@ layout("/layouts/platform.html"){
</search> </search>
</el-card> </el-card>
<el-card shadow="never"> <el-card shadow="never">
<table-tool label="提案列表" :columns.sync="tableColumns"></table-tool>
<el-table :data="tableData" @sort-change="pageOrder" style="width: 100%"> <el-table :data="tableData" @sort-change="pageOrder" style="width: 100%">
<el-table-column label="序号" width="50" type="index" :index="indexMethod" fixed="left"></el-table-column> <el-table-column label="序号" width="50" type="index" :index="indexMethod" fixed="left"></el-table-column>
<el-table-column <el-table-column
@@ -60,7 +61,7 @@ layout("/layouts/platform.html"){
size="small"></enum-tag> size="small"></enum-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" fixed="right" width="300px"> <el-table-column label="操作" fixed="right" width="120px">
<template slot-scope="{row}"> <template slot-scope="{row}">
<el-button @click="openView(row)" size="mini" type="primary">查看</el-button> <el-button @click="openView(row)" size="mini" type="primary">查看</el-button>
</template> </template>
@@ -95,7 +96,7 @@ layout("/layouts/platform.html"){
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
<!--#include('../../common/info.js'){}#--> <!--#include('../../common/info.js'){}#-->
new Vue({ new Vue({
el: "#app", el: "#app",
store, store,
@@ -119,8 +120,10 @@ layout("/layouts/platform.html"){
{label: "团长审核", prop: "delegationAudit"}, {label: "团长审核", prop: "delegationAudit"},
], ],
pageForm: { pageForm: {
approval: false approval: false,
}, searchName: "proposalName",
searchName2: "su.username",
},
showApprovalForm: false, showApprovalForm: false,
sessionOptions: [] sessionOptions: []
} }
@@ -149,9 +152,6 @@ layout("/layouts/platform.html"){
}, },
created() { created() {
this.pageData() this.pageData()
// 加载教代会信息
this.listOpenSession()
} }
}) })
</script> </script>
@@ -9,9 +9,7 @@ layout("/layouts/platform.html"){
<el-card shadow="never"> <el-card shadow="never">
<snaker-start slot="header" label="撰写提案" define_key="JDHTA"> <snaker-start slot="header" label="撰写提案" define_key="JDHTA">
<template slot="header-right-label"> <template slot="header-right-label">
<span style="margin-right: 15px" v-if="!formData.id"> <el-link type="primary" @click="openImport" v-if="!formData.id" style="margin-right: 15px">导入提案</el-link>
<el-link type="success" @click="openImport">导入</el-link>
</span>
</template> </template>
</snaker-start> </snaker-start>
<template> <template>
@@ -186,49 +184,52 @@ layout("/layouts/platform.html"){
:close-on-click-modal="false" :close-on-click-modal="false"
width="50%" width="50%"
> >
<el-timeline-item timestamp="下载模板" placement="top"> <el-timeline>
<el-card> <el-timeline-item timestamp="下载模板" placement="top">
<el-row :gutter="24"> <el-card>
<el-col :span="24"> <el-row :gutter="24">
<el-radio-group v-model="importTemplateType"> <el-col :span="24">
<el-radio :label="1">excel</el-radio> <el-radio-group v-model="importTemplateType">
<el-radio :label="2">word</el-radio> <el-radio :label="1">excel</el-radio>
</el-radio-group> <el-radio :label="2">word</el-radio>
</el-col> </el-radio-group>
</el-row> </el-col>
<el-row :gutter="24" style="margin-top: 20px;"> </el-row>
<el-col :span="24"> <el-row :gutter="24" style="margin-top: 20px;">
<el-button size="medium" type="" style="width: 200px" <el-col :span="24">
@click="downloadTemplate" <el-button size="medium" type="" style="width: 200px"
icon="el-icon-download">下载模板 @click="downloadTemplate"
</el-button> icon="el-icon-download">下载模板
</el-col> </el-button>
</el-row> </el-col>
</el-card> </el-row>
</el-timeline-item> </el-card>
<el-timeline-item timestamp="上传文件" placement="top"> </el-timeline-item>
<el-card> <el-timeline-item timestamp="上传文件" placement="top">
<el-upload <el-card>
name="file" <el-upload
ref="upload" name="file"
:on-remove="(file, fileList) => { ref="upload"
:on-remove="(file, fileList) => {
importData.fileList = fileHandleRemove(file, fileList) importData.fileList = fileHandleRemove(file, fileList)
}" }"
:on-change="(file, fileList) => { :on-change="(file, fileList) => {
if(this.importTemplateType === 2) { if(this.importTemplateType === 2) {
importData.fileList = fileHandleChange(file, fileList,{type:['docx']}) importData.fileList = fileHandleChange(file, fileList,{type:['docx']})
} else { } else {
importData.fileList = fileHandleChange(file, fileList,{type:['xlsx']}) importData.fileList = fileHandleChange(file, fileList,{type:['xlsx']})
} }
}" }"
:auto-upload="false" :auto-upload="false"
:limit="1" :limit="1"
:file-list="importData.fileList"> :file-list="importData.fileList">
<el-button size="medium" type="" icon="el-icon-upload" style="width: 200px">选择文件 <el-button size="medium" type="" icon="el-icon-upload" style="width: 200px">选择文件
</el-button> </el-button>
</el-upload> </el-upload>
</el-card> </el-card>
</el-timeline-item> </el-timeline-item>
</el-timeline>
<span slot="footer" class="dialog-footer"> <span slot="footer" class="dialog-footer">
<el-button @click="importVisible = false" :disabled="importLoading">取 消</el-button> <el-button @click="importVisible = false" :disabled="importLoading">取 消</el-button>
<el-button type="primary" @click="doImport" :loading="importLoading">确定</el-button> <el-button type="primary" @click="doImport" :loading="importLoading">确定</el-button>
@@ -245,14 +246,14 @@ layout("/layouts/platform.html"){
return { return {
bizId: GetQueryString("bizId"), bizId: GetQueryString("bizId"),
taskId: GetQueryString("taskId"), taskId: GetQueryString("taskId"),
// 将 window.location 的引用存储在响应式数据中 // 将 window.location 的引用存储在响应式数据中
location: window.location, location: window.location,
importTemplateType: 1, importTemplateType: 1,
importData: {}, importData: {},
importVisible: false, importVisible: false,
importLoading: false, importLoading: false,
formData: {}, formData: {},
sessionOptions: [], sessionOptions: [],
sourceOptions: [], sourceOptions: [],
@@ -356,7 +357,7 @@ layout("/layouts/platform.html"){
}) })
} }
}, },
// 打开导入窗口 // 打开导入窗口
async openImport() { async openImport() {
this.importData = { this.importData = {
@@ -364,7 +365,7 @@ layout("/layouts/platform.html"){
} }
this.importVisible = true; this.importVisible = true;
}, },
// 下载导入模板 // 下载导入模板
async downloadTemplate() { async downloadTemplate() {
let templateType = '.xlsx' let templateType = '.xlsx'
@@ -373,7 +374,7 @@ layout("/layouts/platform.html"){
} }
this.location.href='/platform/basics/downloadTemplate?filePath=proposal/proposal' + templateType + '&fileName=教职工代表大会提案表' + templateType this.location.href='/platform/basics/downloadTemplate?filePath=proposal/proposal' + templateType + '&fileName=教职工代表大会提案表' + templateType
}, },
// 开始导入数据 // 开始导入数据
async doImport() { async doImport() {
if (!this.importData.fileList.length) { if (!this.importData.fileList.length) {
@@ -517,7 +518,7 @@ layout("/layouts/platform.html"){
} }
}) })
}, },
// 查询字典 撰写方式 // 查询字典 撰写方式
async getDictByCode(code) { async getDictByCode(code) {
const res = await $.get("/platform/proposal/write/listSourceByCode", {code: code}) const res = await $.get("/platform/proposal/write/listSourceByCode", {code: code})
@@ -567,7 +568,7 @@ layout("/layouts/platform.html"){
this.$set(this.formData, "mobile", this.$store.state.user.mobile) this.$set(this.formData, "mobile", this.$store.state.user.mobile)
this.$set(this.formData, "unitName", this.$store.state.user.unit?.name) this.$set(this.formData, "unitName", this.$store.state.user.unit?.name)
} }
// 撰写方式 // 撰写方式
this.allSourceOptions = await this.getDictByCode("PROPOSAL_SOURCE") this.allSourceOptions = await this.getDictByCode("PROPOSAL_SOURCE")
this.sourceOptions = this.allSourceOptions this.sourceOptions = this.allSourceOptions