Compare commits

...
14 Commits
Author SHA1 Message Date
c-hongqw1 909aaa291c 提案审核提交增加转圈圈、如果域名解析失败,不缓存,等待两秒重新读取,共三次,域名解析成功缓存一分钟;手机端审核撤回失败,审核下拉选择参数自动弹出审核页等bug 2026-10-29 15:44:01 +08:00
c-hongqw1 986faea6b3 修复:调查问卷查看题目后,新增的题目看不到了 2026-10-27 10:55:28 +08:00
c-hongqw1 f9f112104d 调查问卷题目选项增加必填设置 2026-10-27 10:28:36 +08:00
c-hongqw1 f20bccc1ee 不在组别内的扫描调查问卷二维码优化 2026-10-22 17:05:06 +08:00
c-hongqw1 3f51f5ebc4 调查问卷二维码不跳转,白屏问题;增加题目隐显逻辑 2026-10-22 16:47:23 +08:00
c-hongqw1 c7f0f75680 调查问卷二维码不跳转,白屏问题;增加题目隐显逻辑 2026-10-22 16:24:24 +08:00
c-hongqw1 f2a1825e6a 提案查看综合问题 2026-10-22 14:35:01 +08:00
c-hongqw1 038bd825bd 协办办理意见被覆盖问题 2026-10-22 11:42:50 +08:00
c-hongqw1 187f6a6491 提案委主任的办理意见展示修正 2026-10-16 13:55:59 +08:00
c-hongqw1 6e0ca7190d 提案委主任审核”的办理意见展示已修正 2026-10-16 13:01:06 +08:00
c-hongqw1 fd59d28cbd 提案审核查看,提案主任意见办理意见字段显示bug 2026-10-16 12:52:43 +08:00
c-hongqw1 c350485fbe 文化活动活动时间可以选择时分秒;职工慰问收款人固定为申请人 2026-10-14 18:59:41 +08:00
c-hongqw1 e784b5d4a8 修复个人只能报两项的限制 2026-10-14 16:38:38 +08:00
c-hongqw1 3e152181ea 学校OA待办不存在,跳过改已办并继续流程 2026-10-13 16:50:27 +08:00
59 changed files with 2604 additions and 1408 deletions
@@ -63,17 +63,29 @@ public class MainLauncher {
private Dao dao; private Dao dao;
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
configureDnsCache();
NbApp nb = new NbApp().setArgs(args).setPrintProcDoc(true); NbApp nb = new NbApp().setArgs(args).setPrintProcDoc(true);
nb.getAppContext().setMainPackage("com.budwk"); nb.getAppContext().setMainPackage("com.budwk");
nb.run(); nb.run();
} }
public static NbApp warMain(ServletContext sc) { public static NbApp warMain(ServletContext sc) {
configureDnsCache();
NbApp nb = new NbApp().setPrintProcDoc(true); NbApp nb = new NbApp().setPrintProcDoc(true);
nb.getAppContext().setMainPackage("com.budwk"); nb.getAppContext().setMainPackage("com.budwk");
return nb; return nb;
} }
/**
* 在启动框架及网络依赖之前设置 JVM 域名缓存:成功缓存 60 秒,失败不缓存。
* 此策略作用于整个 JVM;共享 WAR 容器若已初始化解析器,需在容器启动配置中设置。
* 无入参、无返回值;不清理操作系统或 DNS 服务器的缓存。
*/
private static void configureDnsCache() {
java.security.Security.setProperty("networkaddress.cache.ttl", "60");
java.security.Security.setProperty("networkaddress.cache.negative.ttl", "0");
}
public void init() { public void init() {
Mvcs.DISABLE_X_POWERED_BY = true; Mvcs.DISABLE_X_POWERED_BY = true;
Globals.AppBase = Mvcs.getServletContext().getContextPath(); Globals.AppBase = Mvcs.getServletContext().getContextPath();
@@ -7,6 +7,8 @@ import com.budwk.app.flow.constant.FlowConst;
import com.budwk.app.flow.engine.FlowEngine; import com.budwk.app.flow.engine.FlowEngine;
import com.budwk.app.flow.enums.ProcessSubmitTypeEnum; import com.budwk.app.flow.enums.ProcessSubmitTypeEnum;
import com.budwk.app.web.commons.auth.utils.SecurityUtil; import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import org.nutz.aop.interceptor.ioc.TransAop;
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;
@@ -17,9 +19,12 @@ public class FlowCommonService {
private FlowEngine flowEngine; private FlowEngine flowEngine;
/** /**
* 执行任务 * 执行 WF 任务,任务状态、业务监听器和后续任务写入共用本地事务;OA 异常向外抛出触发回滚。
* @param args * @param args 包含 processTaskId、submitType 和 tf_ 前缀表单变量;submitType 缺省为同意。
* 方法会移除任务 ID 并补充办理人信息,批量办理应为每个任务传入独立副本。
* 返回值为 void;失败抛出异常,由调用入口返回失败结果
*/ */
@Aop(TransAop.READ_COMMITTED)
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();
@@ -195,10 +195,12 @@ public interface ProcessTaskService extends BaseService<ProcessTask> {
ProcessTaskVO latest(Long processInstanceId); ProcessTaskVO latest(Long processInstanceId);
/** /**
* 转办任务 * 转办正在办理的 WF 任务:旧 OA 待办转已办,新任务向目标办理人发送 OA 待办。
* 无返回值;任务无效、参与人创建失败或 OA 同步异常时抛出异常,回滚本地事务。
* OA 同步遵循系统开关;本地回滚不能撤销已经成功的远程 OA 操作。
* *
* @param taskId 任务ID * @param taskId 当前仍在办理的 WF 任务 ID,不是流程实例 ID
* @param transferUserId 转办用户ID * @param transferUserId 新办理人的系统用户 ID,不是工号
*/ */
void transfer(Long taskId, String transferUserId); void transfer(Long taskId, String transferUserId);
@@ -463,8 +463,22 @@ public class ProcessTaskServiceImpl extends BaseServiceImpl<ProcessTask> impleme
@Override @Override
@Aop(TransAop.READ_COMMITTED) @Aop(TransAop.READ_COMMITTED)
public void transfer(Long taskId, String transferUserId) { public void transfer(Long taskId, String transferUserId) {
// 设置原任务状态为已转办 // taskId 为正在办理的 WF 任务,transferUserId 为目标用户 ID;无返回值,失败抛异常回滚。
if (taskId == null || StrUtil.isBlank(transferUserId)) {
throw new BaseException("转办失败:任务和新办理人不能为空");
}
ProcessTask task = fetch(taskId); ProcessTask task = fetch(taskId);
if (task == null || Boolean.TRUE.equals(task.getDelFlag())
|| !ProcessTaskStateEnum.DOING.getCode().equals(task.getTaskState())) {
throw new BaseException("当前任务已处理或不存在,请刷新后重试");
}
// 使用与任务参与人创建相同的用户视图,提前拒绝无法创建参与人的目标用户。
Sql transferUserSql = Sqls.create("select id from vw_user where id=@userId");
transferUserSql.setParam("userId", transferUserId);
if (listMap(transferUserSql).isEmpty()) {
throw new BaseException("转办失败:新办理人不存在");
}
// 本系统保留已转办状态,OA 中旧办理人的待办在下方同步为已办。
task.setTaskState(ProcessTaskStateEnum.TRANSFER.getCode()); task.setTaskState(ProcessTaskStateEnum.TRANSFER.getCode());
Dict variable = FlowUtil.variableToDict(task.getVariable()); Dict variable = FlowUtil.variableToDict(task.getVariable());
variable.put(FlowConst.TASK_FORM_DATA_PREFIX + "transferUserId", transferUserId); variable.put(FlowConst.TASK_FORM_DATA_PREFIX + "transferUserId", transferUserId);
@@ -487,11 +501,18 @@ public class ProcessTaskServiceImpl extends BaseServiceImpl<ProcessTask> impleme
// 创建转办任务参与者 // 创建转办任务参与者
addTaskActor(newTask.getId(), List.of(transferUserId)); addTaskActor(newTask.getId(), List.of(transferUserId));
// 发布流程任务开始事件 // 参与人创建失败时禁止关闭旧 OA 待办;事务回滚新任务及旧任务状态。
List<ProcessTask> processTaskList = List.of(task); if (!getTaskActors(newTask.getId()).contains(transferUserId)) {
processTaskList.forEach(processTask -> { throw new BaseException("转办失败:未能创建新办理人的任务参与记录");
ProcessPublisher.notify(ProcessEvent.builder().eventType(ProcessEventTypeEnum.PROCESS_TASK_START).sourceId(processTask.getId()).build()); }
}); // 两次 OA 调用均须成功才允许本地事务提交;异常继续向外抛出,不吞掉同步失败。
// 本地事务不能撤销已成功的远程 OA 请求,因此仍需保留异常日志用于对账。
schoolOaTodoService.completeTodo(task);
schoolOaTodoService.createTodo(newTask);
// OA 同步成功后通知新任务的办理人,避免使用旧任务 ID 通知原办理人。
ProcessPublisher.notify(ProcessEvent.builder().eventType(ProcessEventTypeEnum.PROCESS_TASK_START)
.sourceId(newTask.getId()).build());
} }
@@ -3,6 +3,7 @@ package com.budwk.app.flow.service.impl;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest; import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil; import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject; import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
@@ -28,8 +29,9 @@ import org.nutz.ioc.impl.PropertiesProxy;
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 java.util.Date; import java.net.UnknownHostException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.List; import java.util.List;
/** /**
@@ -39,6 +41,12 @@ import java.util.List;
@IocBean @IocBean
public class SchoolOaTodoServiceImpl implements SchoolOaTodoService { public class SchoolOaTodoServiceImpl implements SchoolOaTodoService {
// 总次数包含首次请求;只重试尚未连接到 OA 的域名解析失败。
private static final int MAX_REQUEST_ATTEMPTS = 3;
private static final int CONNECT_TIMEOUT_MS = 2000;
private static final int READ_TIMEOUT_MS = 10000;
private static final long DNS_RETRY_DELAY_MS = 2000L;
private static final String DATE_PATTERN = "yyyy-MM-dd HH:mm:ss"; private static final String DATE_PATTERN = "yyyy-MM-dd HH:mm:ss";
private static final String DEFAULT_APP_TODO_URL = "zhgh.ypi.edu.cn"; private static final String DEFAULT_APP_TODO_URL = "zhgh.ypi.edu.cn";
@@ -271,7 +279,14 @@ public class SchoolOaTodoServiceImpl implements SchoolOaTodoService {
return; return;
} }
String updateUrl = requireConfig("school-oa.todo.update-url").replace("{uniqueId}", uniqueId); String updateUrl = requireConfig("school-oa.todo.update-url").replace("{uniqueId}", uniqueId);
String responseBody = sendTodoRequest(updateUrl, "学校OA待办完成失败", "学校OA待办完成异常"); String responseBody = sendTodoRequest(updateUrl, null, "学校OA待办完成失败", "学校OA待办完成异常", true);
JSONObject response = JSONUtil.parseObj(responseBody);
if (response.getInt("state", 0) == 1131) {
// 历史流程任务没有创建对应的 OA 待办时,允许 WF 继续流转并由原流程逻辑创建下一节点待办。
log.warn("学校OA待办不存在,跳过改已办并继续流程,uniqueId={},state=1131,message={}",
uniqueId, response.getStr("message"));
return;
}
log.info("学校OA待办完成成功,uniqueId={},response={}", uniqueId, responseBody); log.info("学校OA待办完成成功,uniqueId={},response={}", uniqueId, responseBody);
} }
@@ -319,7 +334,7 @@ public class SchoolOaTodoServiceImpl implements SchoolOaTodoService {
String uniqueId = task.getId() + "_" + actor.getActorId(); String uniqueId = task.getId() + "_" + actor.getActorId();
completeTodoByUniqueId(uniqueId); completeTodoByUniqueId(uniqueId);
log.info("学校OA待办完成成功,taskId={},receiveCode={},uniqueId={}", task.getId(), actor.getActorAccount(), uniqueId); log.info("学校OA待办完成处理结束,taskId={},receiveCode={},uniqueId={}", task.getId(), actor.getActorAccount(), uniqueId);
} }
/** /**
@@ -481,28 +496,95 @@ public class SchoolOaTodoServiceImpl implements SchoolOaTodoService {
} }
private String sendTodoRequest(String url, JSONObject body, String failMessage, String errorMessage) { private String sendTodoRequest(String url, JSONObject body, String failMessage, String errorMessage) {
String requestBody = body == null ? "" : JSONUtil.toJsonStr(body); return sendTodoRequest(url, body, failMessage, errorMessage, false);
log.info("学校OA请求开始,url={},body={}", url, requestBody); }
try {
HttpRequest request = HttpUtil.createPost(url);
setTodoRequestHeaders(request);
if (body != null) {
request.body(requestBody);
}
String responseBody = request.execute().body(); /**
log.info("学校OA请求响应,url={},response={}", url, responseBody); * 发送 OA 请求。DNS 失败间隔两秒、最多尝试三次;业务错误和结果不确定的网络异常直接抛出。
JSONObject response = JSONUtil.parseObj(responseBody); * @param url 已替换任务标识的 OA 接口地址
if (response.getInt("state", 0) != 200) { * @param body 请求 JSON,null 表示无请求体
log.warn("学校OA请求失败响应,url={},body={},response={}", url, requestBody, responseBody); * @param failMessage OA 业务失败提示前缀
throw new BaseException("{}:{}", failMessage, response.getStr("message", responseBody)); * @param errorMessage 请求异常提示前缀
* @param skipMissingTodo 仅完成待办接口允许 state=1131(记录不存在)继续办理
* @return OA 原始 JSON 字符串,state=200 为成功,允许缺失时也可能为 1131
*/
private String sendTodoRequest(String url, JSONObject body, String failMessage, String errorMessage, boolean skipMissingTodo) {
String requestBody = body == null ? "" : JSONUtil.toJsonStr(body);
for (int attempt = 1; attempt <= MAX_REQUEST_ATTEMPTS; attempt++) {
long attemptStarted = System.nanoTime();
log.info("学校OA请求开始,url={},attempt={}/{}", url, attempt, MAX_REQUEST_ATTEMPTS);
try {
// 每次重建请求并关闭响应;仅 DNS 失败后等待重试,不引入共享锁。
HttpRequest request = HttpUtil.createPost(url)
.setConnectionTimeout(CONNECT_TIMEOUT_MS)
.setReadTimeout(READ_TIMEOUT_MS);
setTodoRequestHeaders(request);
if (body != null) {
request.body(requestBody);
}
String responseBody;
try (HttpResponse httpResponse = request.execute()) {
responseBody = httpResponse.body();
}
log.info("学校OA请求响应,url={},attempt={},elapsedMs={},response={}", url, attempt,
(System.nanoTime() - attemptStarted) / 1_000_000L, responseBody);
JSONObject response = JSONUtil.parseObj(responseBody);
int state = response.getInt("state", 0);
// 保留历史待办缺失的兼容规则;其他业务失败不重试。
if (state != 200 && !(skipMissingTodo && state == 1131)) {
throw new BaseException("{}:{}", failMessage, response.getStr("message", responseBody));
}
return responseBody;
} catch (BaseException e) {
throw e;
} catch (Exception e) {
if (isUnknownHostFailure(e)) {
log.warn("学校OA域名解析失败,url={},attempt={}/{},elapsedMs={}", url, attempt, MAX_REQUEST_ATTEMPTS,
(System.nanoTime() - attemptStarted) / 1_000_000L, e);
if (attempt < MAX_REQUEST_ATTEMPTS) {
// 只暂停当前请求;中断时终止重试并抛出异常,交由外层事务回滚。
log.info("学校OA等待域名解析重试,url={},nextAttempt={},delayMs={}",
url, attempt + 1, DNS_RETRY_DELAY_MS);
try {
Thread.sleep(DNS_RETRY_DELAY_MS);
} catch (InterruptedException interrupted) {
Thread.currentThread().interrupt();
BaseException failure = new BaseException("学校OA请求已中断,请稍后重试");
failure.initCause(interrupted);
failure.addSuppressed(e);
throw failure;
}
continue;
}
BaseException failure = new BaseException("学校OA暂时无法连接,请稍后重试");
failure.initCause(e);
throw failure;
}
// 读取超时等异常可能发生在 OA 已处理之后,自动重试可能导致重复待办。
log.error("学校OA请求异常,url={},attempt={},elapsedMs={}", url, attempt,
(System.nanoTime() - attemptStarted) / 1_000_000L, e);
BaseException failure = new BaseException("{}:{}", errorMessage, e.getMessage());
failure.initCause(e);
throw failure;
} }
return responseBody;
} catch (BaseException e) {
throw e;
} catch (Exception e) {
log.error("学校OA请求异常,url={},body={}", url, requestBody, e);
throw new BaseException("{}:{}", errorMessage, e.getMessage());
} }
throw new BaseException("学校OA暂时无法连接,请稍后重试");
}
/**
* 检查 HTTP 库包装的底层 DNS 异常;限制遍历深度,避免异常原因链循环导致无限等待。
* @param error 请求抛出的异常
* @return true 表示异常链包含 UnknownHostException,可安全重试域名解析失败的请求
*/
private boolean isUnknownHostFailure(Throwable error) {
Throwable cause = error;
for (int depth = 0; cause != null && depth < 32; depth++) {
if (cause instanceof UnknownHostException) {
return true;
}
cause = cause.getCause();
}
return false;
} }
} }
@@ -1,5 +1,6 @@
package com.budwk.app.zhgh.dayofficework.qsv.h5controller; package com.budwk.app.zhgh.dayofficework.qsv.h5controller;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject; import cn.hutool.json.JSONObject;
import com.budwk.app.base.result.Result; import com.budwk.app.base.result.Result;
@@ -12,6 +13,8 @@ import com.budwk.app.zhgh.dayofficework.qsv.param.QsvAnswerParam;
import com.budwk.app.zhgh.dayofficework.qsv.service.QsvUserAnswerRecordService; import com.budwk.app.zhgh.dayofficework.qsv.service.QsvUserAnswerRecordService;
import org.nutz.dao.Cnd; import org.nutz.dao.Cnd;
import org.nutz.dao.Dao; import org.nutz.dao.Dao;
import org.nutz.aop.interceptor.ioc.TransAop;
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.lang.util.NutMap; import org.nutz.lang.util.NutMap;
@@ -34,12 +37,22 @@ public class H5QsvSurveyController {
@Inject @Inject
private QsvUserAnswerRecordService qsvUserAnswerRecordService; private QsvUserAnswerRecordService qsvUserAnswerRecordService;
/**
* 扫码进入问卷前校验登录状态;未登录时由统一异常处理发起认证,
* 携带原始地址及 id 参数,认证成功后返回当前问卷。
*/
@At("") @At("")
@SaCheckLogin
@Ok("beetl:/platform/zhghh5/dayofficework/qsv/survey/index.html") @Ok("beetl:/platform/zhghh5/dayofficework/qsv/survey/index.html")
public void index() { public void index() {
} }
/**
* activityId 为当前调查活动ID;返回 Result,data 包含 activity、subjects、answerRecordId。
* 未提交答卷由 service 同步当前题目及新增答案结构,再加载题目供手机端显示。
*/
@At @At
@Aop(TransAop.READ_COMMITTED)
public Result subjects(String activityId) { public Result subjects(String activityId) {
QsvActivity activity = dao.fetch(QsvActivity.class, activityId); QsvActivity activity = dao.fetch(QsvActivity.class, activityId);
@@ -62,6 +75,7 @@ public class H5QsvSurveyController {
Cnd.where("activityId", "=", activityId) Cnd.where("activityId", "=", activityId)
.and("userId", "=", SecurityUtil.getUserId())); .and("userId", "=", SecurityUtil.getUserId()));
answerRecord2 = qsvUserAnswerRecordService.syncSurveySubjects(answerRecord2.getId());
answerRecordId = answerRecord2.getId(); answerRecordId = answerRecord2.getId();
List<QsvSubject> subjects = dao.query(QsvSubject.class, Cnd.where("id", "in", answerRecord2.getSubjectIds()).asc("sortNum")); List<QsvSubject> subjects = dao.query(QsvSubject.class, Cnd.where("id", "in", answerRecord2.getSubjectIds()).asc("sortNum"));
@@ -38,6 +38,15 @@ public class QsvSubject extends BaseModel implements Serializable {
@ColDefine(type = ColType.VARCHAR, width = 50) @ColDefine(type = ColType.VARCHAR, width = 50)
private String type; private String type;
/**
* 是否必须作答;新题默认必填,历史空值由答题页面按必填兼容。
*/
@Column
@Comment("是否必填")
@ColDefine(type = ColType.BOOLEAN)
@Default("1")
private Boolean required = true;
@Column @Column
@Comment("正确答案") @Comment("正确答案")
@ColDefine(type = ColType.MYSQL_JSON) @ColDefine(type = ColType.MYSQL_JSON)
@@ -63,6 +72,26 @@ public class QsvSubject extends BaseModel implements Serializable {
@ColDefine(type = ColType.INT, width = 1) @ColDefine(type = ColType.INT, width = 1)
private Integer sortNum; private Integer sortNum;
@Column
@Comment("是否启用题目隐显逻辑")
@ColDefine(type = ColType.BOOLEAN)
private Boolean visibleRuleEnabled;
@Column
@Comment("隐显逻辑处理方式(show显示,hide隐藏)")
@ColDefine(type = ColType.VARCHAR, width = 20)
private String visibleRuleAction;
@Column
@Comment("隐显逻辑条件关系(AND并且,OR或者)")
@ColDefine(type = ColType.VARCHAR, width = 20)
private String visibleRuleLogic;
@Column
@Comment("隐显逻辑条件列表")
@ColDefine(type = ColType.MYSQL_JSON)
private List<VisibleRuleCondition> visibleRuleConditions;
/** /**
* 选项 * 选项
*/ */
@@ -79,4 +108,22 @@ public class QsvSubject extends BaseModel implements Serializable {
*/ */
private String userFillContent; private String userFillContent;
/**
* 题目隐显逻辑条件,一条条件表示选择指定题目的指定选项后参与显示或隐藏判断。
*/
@Data
public static class VisibleRuleCondition implements Serializable {
/**
* 作为触发条件的题目ID。
*/
private String subjectId;
/**
* 作为触发条件的选项ID。
*/
private String optionId;
}
} }
@@ -12,6 +12,13 @@ public interface QsvUserAnswerRecordService extends BaseService<QsvUserAnswerRec
QsvUserAnswerRecord insertRecord(String activityId, List<String> subjectIds); QsvUserAnswerRecord insertRecord(String activityId, List<String> subjectIds);
/**
* 同步未提交调查问卷的当前题目,保留已有答案并补齐新增题目的答案结构。
* @param answerRecordId 已通过参与范围校验的当前用户答题记录ID
* @return 答题记录,subjectIds 为同步后的题目ID列表,extJson 按题目ID保存答案;已提交或非调查记录原样返回
*/
QsvUserAnswerRecord syncSurveySubjects(String answerRecordId);
/** /**
* 计算得分 * 计算得分
*/ */
@@ -170,8 +170,8 @@ public class QsvSurveyServiceImpl extends BaseServiceImpl<QsvUserAnswerRecord> i
// 将答题记录的扩展JSON转换为JSONObject列表 // 将答题记录的扩展JSON转换为JSONObject列表
List<JSONObject> answerExtList = answerRecords.stream().map(QsvUserAnswerRecord::getExtJson).toList(); List<JSONObject> answerExtList = answerRecords.stream().map(QsvUserAnswerRecord::getExtJson).toList();
// 查询活动题目列表 // 按题目设置顺序生成答卷列,保证查看答卷与 Excel 导出的题目顺序一致。
List<QsvSubject> subjects = dao().query(QsvSubject.class, Cnd.where("activityId", "=", activityId)); List<QsvSubject> subjects = dao().query(QsvSubject.class, Cnd.where("activityId", "=", activityId).asc("sortNum"));
// 将题目列表转换为Map // 将题目列表转换为Map
Map<String, QsvSubject> subjectMap = subjects.stream().collect(Collectors.toMap(QsvSubject::getId, v -> v)); Map<String, QsvSubject> subjectMap = subjects.stream().collect(Collectors.toMap(QsvSubject::getId, v -> v));
// 获取题目ID列表 // 获取题目ID列表
@@ -222,8 +222,8 @@ public class QsvSurveyServiceImpl extends BaseServiceImpl<QsvUserAnswerRecord> i
// 将答题记录的扩展JSON转换为JSONObject列表 // 将答题记录的扩展JSON转换为JSONObject列表
// List<JSONObject> answerExtList = answerRecords.stream().map(QsvUserAnswerRecord::getExtJson).toList(); // List<JSONObject> answerExtList = answerRecords.stream().map(QsvUserAnswerRecord::getExtJson).toList();
// 查询活动题目列表 // 按题目设置顺序生成答卷列,保证查看答卷与 Excel 导出的题目顺序一致。
List<QsvSubject> subjects = dao().query(QsvSubject.class, Cnd.where("activityId", "=", activityId)); List<QsvSubject> subjects = dao().query(QsvSubject.class, Cnd.where("activityId", "=", activityId).asc("sortNum"));
// 将题目列表转换为Map // 将题目列表转换为Map
Map<String, QsvSubject> subjectMap = subjects.stream().collect(Collectors.toMap(QsvSubject::getId, v -> v)); Map<String, QsvSubject> subjectMap = subjects.stream().collect(Collectors.toMap(QsvSubject::getId, v -> v));
// 获取题目ID列表 // 获取题目ID列表
@@ -17,6 +17,7 @@ import org.nutz.dao.Cnd;
import org.nutz.dao.Dao; import org.nutz.dao.Dao;
import org.nutz.ioc.aop.Aop; import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import java.util.*; import java.util.*;
@@ -27,6 +28,7 @@ public class QsvUserAnswerRecordServiceImpl extends BaseServiceImpl<QsvUserAnswe
} }
@Override @Override
@Aop(TransAop.READ_COMMITTED)
public QsvUserAnswerRecord insertRecord(String activityId, List<String> subjectIds) { public QsvUserAnswerRecord insertRecord(String activityId, List<String> subjectIds) {
QsvActivity activity = dao().fetch(QsvActivity.class, activityId); QsvActivity activity = dao().fetch(QsvActivity.class, activityId);
String category = activity.getCategory(); String category = activity.getCategory();
@@ -85,6 +87,51 @@ public class QsvUserAnswerRecordServiceImpl extends BaseServiceImpl<QsvUserAnswe
} }
/**
* 按记录ID同步未提交的调查问卷,返回包含当前题目列表及答案结构的记录。
* 仅补齐缺失答案,不清除已有答案;已提交记录及考试抽题记录不参与同步。
*/
@Override
@Aop(TransAop.READ_COMMITTED)
public QsvUserAnswerRecord syncSurveySubjects(String answerRecordId) {
QsvUserAnswerRecord record = dao().fetch(QsvUserAnswerRecord.class, answerRecordId);
if (record == null) {
throw new IllegalArgumentException("答题记录不存在");
}
if (Boolean.TRUE.equals(record.getIsFinish())) {
return record;
}
QsvActivity activity = dao().fetch(QsvActivity.class, record.getActivityId());
if (activity == null || !"SURVEY".equals(activity.getCategory())) {
return record;
}
List<QsvSubject> subjects = dao().query(QsvSubject.class,
Cnd.where("activityId", "=", record.getActivityId()).asc("sortNum"));
List<String> subjectIds = subjects.stream().map(QsvSubject::getId).toList();
JSONObject extJson = record.getExtJson() == null ? new JSONObject() : record.getExtJson();
boolean changed = !Objects.equals(subjectIds, record.getSubjectIds());
for (String subjectId : subjectIds) {
// 提交接口只更新已存在的答案对象,新增题目必须同时补齐结构才能保存答案。
JSONObject answer = extJson.get(subjectId, JSONObject.class);
if (answer == null || answer.isEmpty()) {
extJson.set(subjectId, Dict.create()
.set("optionIds", new ArrayList<>())
.set("text", null)
.set("isCorrect", null));
changed = true;
}
}
if (changed) {
// 只更新题目和答案字段,并再次限制未提交状态,避免并发提交后覆盖已完成的答卷。
dao().update(QsvUserAnswerRecord.class,
Chain.make("subjectIds", Json.toJson(subjectIds)).add("extJson", extJson.toString()),
Cnd.where("id", "=", answerRecordId)
.and(Cnd.exps("isFinish", "=", false).or("isFinish", "is", null)));
return dao().fetch(QsvUserAnswerRecord.class, answerRecordId);
}
return record;
}
@Override @Override
public float calcScore(QsvAnswerParam qsvAnswerParam) { public float calcScore(QsvAnswerParam qsvAnswerParam) {
List<String> subjectIds = qsvAnswerParam.getSubjects().stream().map(QsvAnswerParam.Subject::getId).toList(); List<String> subjectIds = qsvAnswerParam.getSubjects().stream().map(QsvAnswerParam.Subject::getId).toList();
@@ -190,8 +190,22 @@ public class ProposalPositiveSecondedController {
return Result.success(); return Result.success();
} }
/**
* 供附议及七个办理节点的公共详情读取主动附议记录;读取权限不授予实际附议操作权限。
* @param bizId 提案 ID,对应 proposal_second.proposalId
* @return Result,data 为主动附议记录列表,包含附议人、附议意见、结果及时间;无记录时为空列表
*/
@At @At
@SaCheckPermission(value = {"proposal.seconded", "h5.proposal.seconded", "proposal.commissioner", "h5.proposal.commissioner", "proposal.committeeFiling", "h5.proposal.committeeFiling", "proposal.schoolLeaderApproval", "h5.proposal.schoolLeaderApproval"}, mode = SaMode.OR) @SaCheckPermission(value = {
"proposal.seconded", "h5.proposal.seconded",
"proposal.delegation", "h5.proposal.delegation",
"proposal.commissioner", "h5.proposal.commissioner",
"proposal.committeeFiling", "h5.proposal.committeeFiling",
"proposal.unitReply", "h5.proposal.unitReply",
"proposal.suggestion", "h5.proposal.suggestion",
"proposal.schoolLeaderApproval", "h5.proposal.schoolLeaderApproval",
"proposal.feedbackEvaluation", "h5.proposal.feedbackEvaluation"
}, mode = SaMode.OR)
public Result listPositiveSeconded(String bizId) { public Result listPositiveSeconded(String bizId) {
List<ProposalSecond> list = dao.query(ProposalSecond.class, Cnd.where(ProposalSecond::getProposalId, "=", bizId).and(ProposalSecond::getMode, "=", false)); List<ProposalSecond> list = dao.query(ProposalSecond.class, Cnd.where(ProposalSecond::getProposalId, "=", bizId).and(ProposalSecond::getMode, "=", false));
return Result.success(list); return Result.success(list);
@@ -6,10 +6,8 @@ import cn.hutool.core.util.ObjectUtil;
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.flow.constant.FlowConst;
import com.budwk.app.flow.entity.ProcessTask; import com.budwk.app.flow.entity.ProcessTask;
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.ProcessTaskService; import com.budwk.app.flow.service.ProcessTaskService;
import com.budwk.app.sys.models.Sys_role; import com.budwk.app.sys.models.Sys_role;
import com.budwk.app.sys.models.Sys_user_role; import com.budwk.app.sys.models.Sys_user_role;
@@ -18,6 +16,7 @@ import com.budwk.app.sys.services.SysUserService;
import com.budwk.app.web.commons.auth.utils.AuthUtil; import com.budwk.app.web.commons.auth.utils.AuthUtil;
import com.budwk.app.web.commons.auth.utils.SecurityUtil; import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.democratic.proposal.param.ProposalSearchParam; import com.budwk.app.zhgh.democratic.proposal.param.ProposalSearchParam;
import com.budwk.app.zhgh.democratic.proposal.service.ProposalUnderTakeReplyService;
import com.budwk.app.zhgh.democratic.proposal.service.common.ProposalCommonService; import com.budwk.app.zhgh.democratic.proposal.service.common.ProposalCommonService;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
@@ -37,9 +36,9 @@ import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok; import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param; import org.nutz.mvc.annotation.Param;
import javax.validation.Valid;
import java.util.List; import java.util.List;
import java.util.stream.Stream; import java.util.stream.Stream;
import javax.validation.Valid;
@IocBean @IocBean
@At("/platform/proposal/unitReply") @At("/platform/proposal/unitReply")
@@ -53,7 +52,7 @@ public class ProposalUnderTakeReplyController {
@Inject @Inject
private ProposalCommonService proposalCommonService; private ProposalCommonService proposalCommonService;
@Inject @Inject
private FlowCommonService flowCommonService; private ProposalUnderTakeReplyService proposalUnderTakeReplyService;
@Inject @Inject
private ProcessTaskService processTaskService; private ProcessTaskService processTaskService;
@Inject @Inject
@@ -154,30 +153,18 @@ public class ProposalUnderTakeReplyController {
return Result.success(pagination); return Result.success(pagination);
} }
/**
* 接收承办答复参数,委托 Service 完成整批 WF 办理。
* @param data JSON 字符串,包含 proposalId、processTaskId、submitType 及 tf_ 表单变量
* @return Result 成功结果;业务或 OA 异常由统一异常处理返回失败信息
*/
@At @At
@SaCheckPermission("proposal.unitReply") @SaCheckPermission("proposal.unitReply")
@ApiOperation("执行任务") @ApiOperation("执行任务")
@Aop(TransAop.READ_COMMITTED)
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);
String proposalId = args.getStr("proposalId"); proposalUnderTakeReplyService.executeTask(args);
// 查询是否提案
// 单条审核
List<String> mergeProposalIds = proposalCommonService.mergeProposal(proposalId);
if (ObjectUtil.isEmpty(mergeProposalIds)) {
flowCommonService.executeTask(args);
return Result.success();
}
// 并案审核
ProcessTask thisTask = dao.fetch(ProcessTask.class, args.getLong(FlowConst.PROCESS_TASK_ID_KEY));
List<ProcessTask> mergeTasks = processTaskService.getDoingTaskByBizIdTaskName(mergeProposalIds, thisTask.getTaskName());
for (ProcessTask mergeTask : mergeTasks) {
Dict cloneArgs = args.clone();
cloneArgs.put(FlowConst.PROCESS_TASK_ID_KEY, mergeTask.getId());
flowCommonService.executeTask(cloneArgs);
}
return Result.success(); return Result.success();
} }
@@ -9,8 +9,10 @@ import com.budwk.app.flow.engine.util.FlowUtil;
import com.budwk.app.flow.entity.ProcessTask; import com.budwk.app.flow.entity.ProcessTask;
import com.budwk.app.flow.entity.ProcessTaskActor; import com.budwk.app.flow.entity.ProcessTaskActor;
import com.budwk.app.zhgh.democratic.proposal.models.ProposalReplyUnit; import com.budwk.app.zhgh.democratic.proposal.models.ProposalReplyUnit;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd; import org.nutz.dao.Cnd;
import org.nutz.dao.Dao; import org.nutz.dao.Dao;
import org.nutz.ioc.aop.Aop;
import org.nutz.json.Json; import org.nutz.json.Json;
import java.util.ArrayList; import java.util.ArrayList;
@@ -26,7 +28,13 @@ import java.util.Set;
public class ProposalUnderTakeInfoInterceptor implements FlowInterceptor { public class ProposalUnderTakeInfoInterceptor implements FlowInterceptor {
private static final Set<String> REPLY_TASK_NAMES = Set.of("master_reply", "slave_reply", "opinion_master_reply"); private static final Set<String> REPLY_TASK_NAMES = Set.of("master_reply", "slave_reply", "opinion_master_reply");
/**
* 为本次流转涉及的答复任务补充承办单位信息,保留任务已保存的最新表单数据。
*
* @param execution 当前 WF 执行上下文,包含提案业务编号、当前任务和本次新建任务
*/
@Override @Override
@Aop(TransAop.READ_COMMITTED)
public void intercept(Execution execution) { public void intercept(Execution execution) {
Dao dao = ServiceContext.find(Dao.class); Dao dao = ServiceContext.find(Dao.class);
@@ -53,7 +61,13 @@ public class ProposalUnderTakeInfoInterceptor implements FlowInterceptor {
throw new BaseException("Proposal undertaking unit is empty, cannot write proposal undertaking unit info."); throw new BaseException("Proposal undertaking unit is empty, cannot write proposal undertaking unit info.");
} }
Dict variable = FlowUtil.variableToDict(task.getVariable()); // 完成任务后,执行上下文中的任务仍可能保留提交前的变量。
// 必须以数据库中已保存的最新变量补充单位信息,避免覆盖本次办理人和答复内容。
ProcessTask savedTask = dao.fetch(ProcessTask.class, task.getId());
if (savedTask == null) {
throw new BaseException("答复任务不存在,无法补充承办单位信息。");
}
Dict variable = FlowUtil.variableToDict(savedTask.getVariable());
variable.set("underTakeName", replyUnit.getUnitName()); variable.set("underTakeName", replyUnit.getUnitName());
variable.set("underTakeId", replyUnit.getUnitId()); variable.set("underTakeId", replyUnit.getUnitId());
variable.set("underTakeIsMaster", replyUnit.getIsMaster()); variable.set("underTakeIsMaster", replyUnit.getIsMaster());
@@ -1,5 +1,6 @@
package com.budwk.app.zhgh.democratic.proposal.service; package com.budwk.app.zhgh.democratic.proposal.service;
import cn.hutool.core.lang.Dict;
import com.budwk.app.base.page.Pagination; import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.service.BaseService; import com.budwk.app.base.service.BaseService;
import com.budwk.app.zhgh.democratic.proposal.models.ProposalInfo; import com.budwk.app.zhgh.democratic.proposal.models.ProposalInfo;
@@ -8,11 +9,18 @@ import com.budwk.app.zhgh.democratic.proposal.param.ProposalUnderTakeReplyApprov
import com.budwk.app.zhgh.democratic.proposal.param.ProposalUnderTakeReplyTransferParam; import com.budwk.app.zhgh.democratic.proposal.param.ProposalUnderTakeReplyTransferParam;
import org.nutz.lang.util.NutMap; import org.nutz.lang.util.NutMap;
import javax.validation.Valid;
import java.util.List; import java.util.List;
import javax.validation.Valid;
public interface ProposalUnderTakeReplyService extends BaseService<ProposalInfo> { public interface ProposalUnderTakeReplyService extends BaseService<ProposalInfo> {
/**
* 在同一事务中办理单条或并案提案的 WF 承办答复。
* @param args proposalId 为提案 ID,processTaskId 为当前任务 ID,submitType 和 tf_ 变量沿用页面参数
* 返回值为 void;办理失败抛出异常,整批本地修改回滚
*/
void executeTask(Dict args);
Pagination pageData(ProposalSearchParam param); Pagination pageData(ProposalSearchParam param);
void approval(ProposalUnderTakeReplyApprovalParam param); void approval(ProposalUnderTakeReplyApprovalParam param);
@@ -104,7 +104,8 @@ public class ProposalCommonServiceImpl extends BaseServiceImpl<ProposalInfo> imp
""").setParam("id", id); """).setParam("id", id);
NutMap info = (NutMap) dao().execute(sql.setCallback(Sqls.callback.map())).getResult(); NutMap info = (NutMap) dao().execute(sql.setCallback(Sqls.callback.map())).getResult();
if (StrUtil.isNotBlank(info.getString("suggestUnits"))) { if (StrUtil.isNotBlank(info.getString("suggestUnits"))) {
info.put("suggestUnits", String.join(",", Json.fromJson(ArrayList.class, info.getString("suggestUnits")))); // 分号仅分隔不同单位,保留每个单位名称内部的顿号等标点。
info.put("suggestUnits", String.join(";", Json.fromJson(ArrayList.class, info.getString("suggestUnits"))));
} }
// 并案提案 // 并案提案
@@ -26,8 +26,10 @@ import com.budwk.app.zhgh.democratic.proposal.models.ProposalUndertake;
import com.budwk.app.zhgh.democratic.proposal.param.ProposalUnderTakeSchoolLeaderApprovalParam; import com.budwk.app.zhgh.democratic.proposal.param.ProposalUnderTakeSchoolLeaderApprovalParam;
import com.budwk.app.zhgh.democratic.proposal.service.ProposalSchoolLeaderApprovalService; import com.budwk.app.zhgh.democratic.proposal.service.ProposalSchoolLeaderApprovalService;
import com.budwk.app.zhgh.democratic.proposal.service.common.ProposalCommonService; import com.budwk.app.zhgh.democratic.proposal.service.common.ProposalCommonService;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd; import org.nutz.dao.Cnd;
import org.nutz.dao.Dao; import org.nutz.dao.Dao;
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;
@@ -65,7 +67,13 @@ public class ProposalSchoolLeaderApprovalServiceImpl extends BaseServiceImpl<Pro
super(dao); super(dao);
} }
/**
* 办理校领导 WF 审核;并案中任一任务失败时,整批本地修改回滚。
* @param args proposalId 为提案 ID,processTaskId 为当前任务 ID,其余为审核操作和表单变量
* 返回值为 void;失败异常交由接口统一处理
*/
@Override @Override
@Aop(TransAop.READ_COMMITTED)
public void executeTask(Dict args) { public void executeTask(Dict args) {
String proposalId = args.getStr("proposalId"); String proposalId = args.getStr("proposalId");
@@ -1,6 +1,8 @@
package com.budwk.app.zhgh.democratic.proposal.service.impl; package com.budwk.app.zhgh.democratic.proposal.service.impl;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject; import cn.hutool.json.JSONObject;
import com.budwk.app.base.constant.BpmProcessConstant; import com.budwk.app.base.constant.BpmProcessConstant;
@@ -16,6 +18,10 @@ import com.budwk.app.bpm.models.BpmProcessInstance;
import com.budwk.app.bpm.models.BpmProcessNodeDefine; import com.budwk.app.bpm.models.BpmProcessNodeDefine;
import com.budwk.app.bpm.models.BpmProcessTask; import com.budwk.app.bpm.models.BpmProcessTask;
import com.budwk.app.bpm.service.BpmService; import com.budwk.app.bpm.service.BpmService;
import com.budwk.app.flow.constant.FlowConst;
import com.budwk.app.flow.entity.ProcessTask;
import com.budwk.app.flow.service.FlowCommonService;
import com.budwk.app.flow.service.ProcessTaskService;
import com.budwk.app.sys.models.Sys_role; import com.budwk.app.sys.models.Sys_role;
import com.budwk.app.sys.models.Sys_user; import com.budwk.app.sys.models.Sys_user;
import com.budwk.app.sys.models.Sys_user_role; import com.budwk.app.sys.models.Sys_user_role;
@@ -53,6 +59,10 @@ import java.util.stream.Collectors;
@IocBean(args = {"refer:dao"}) @IocBean(args = {"refer:dao"})
public class ProposalUnderTakeReplyServiceImpl extends BaseServiceImpl<ProposalInfo> implements ProposalUnderTakeReplyService { public class ProposalUnderTakeReplyServiceImpl extends BaseServiceImpl<ProposalInfo> implements ProposalUnderTakeReplyService {
@Inject
private FlowCommonService flowCommonService;
@Inject
private ProcessTaskService processTaskService;
@Inject @Inject
private BpmService bpmService; private BpmService bpmService;
@Inject @Inject
@@ -70,6 +80,33 @@ public class ProposalUnderTakeReplyServiceImpl extends BaseServiceImpl<ProposalI
super(dao); super(dao);
} }
/**
* 保留原 PC 答复的并案联动规则,整批 WF 办理共用外层事务。
* @param args proposalId 为提案 ID,processTaskId 为任务 ID,其余操作及表单变量原样交给 WF
* 返回值为 void;任一任务或 OA 请求失败均向外抛出异常
*/
@Override
@Aop(TransAop.READ_COMMITTED)
public void executeTask(Dict args) {
String proposalId = args.getStr("proposalId");
// 未并案时只办理当前任务;并案时统一办理同节点的关联任务。
List<String> mergeProposalIds = proposalCommonService.mergeProposal(proposalId);
if (ObjectUtil.isEmpty(mergeProposalIds)) {
flowCommonService.executeTask(args);
return;
}
// 每个任务使用独立参数副本,避免公共执行方法移除任务 ID 后影响下一条。
ProcessTask thisTask = dao().fetch(ProcessTask.class, args.getLong(FlowConst.PROCESS_TASK_ID_KEY));
List<ProcessTask> mergeTasks = processTaskService.getDoingTaskByBizIdTaskName(mergeProposalIds, thisTask.getTaskName());
for (ProcessTask mergeTask : mergeTasks) {
Dict cloneArgs = args.clone();
cloneArgs.put(FlowConst.PROCESS_TASK_ID_KEY, mergeTask.getId());
flowCommonService.executeTask(cloneArgs);
}
}
@Override @Override
public Pagination pageData(ProposalSearchParam param) { public Pagination pageData(ProposalSearchParam param) {
return null; return null;
@@ -3,7 +3,6 @@ package com.budwk.app.zhgh.staffbenefit.condolence.controller;
import cn.dev33.satoken.annotation.SaCheckLogin; import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckPermission; import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaMode; import cn.dev33.satoken.annotation.SaMode;
import cn.hutool.core.date.DateUtil;
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 com.budwk.app.base.annotation.SLog; import com.budwk.app.base.annotation.SLog;
@@ -26,7 +25,6 @@ import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.nutz.aop.interceptor.ioc.TransAop; import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd; import org.nutz.dao.Cnd;
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.dao.util.cri.SqlExpressionGroup; import org.nutz.dao.util.cri.SqlExpressionGroup;
@@ -52,8 +50,6 @@ import java.util.List;
@Ok("json:full") @Ok("json:full")
public class CondolenceApplyController { public class CondolenceApplyController {
@Inject
private Dao dao;
@Inject @Inject
private FlowEngine flowEngine; private FlowEngine flowEngine;
@Inject @Inject
@@ -75,9 +71,9 @@ public class CondolenceApplyController {
@ApiOperation("保存申请") @ApiOperation("保存申请")
@SaCheckPermission(value = {"condolence.apply", "h5.condolence.apply"}, mode = SaMode.OR) @SaCheckPermission(value = {"condolence.apply", "h5.condolence.apply"}, mode = SaMode.OR)
@SLog(tag = "职工慰问系统-慰问申请", msg = "保存申请") @SLog(tag = "职工慰问系统-慰问申请", msg = "保存申请")
@Aop(TransAop.READ_COMMITTED)
public Result save(@Param("data") Condolence condolence) { public Result save(@Param("data") Condolence condolence) {
if(StrUtil.isBlank(condolence.getId())) condolence.setCreateTime(DateUtil.now()); condolenceService.saveApplication(condolence);
dao.insertOrUpdate(condolence);
return Result.success(); return Result.success();
} }
@@ -87,8 +83,7 @@ public class CondolenceApplyController {
@SLog(tag = "职工慰问系统-慰问申请", msg = "提交申请") @SLog(tag = "职工慰问系统-慰问申请", msg = "提交申请")
@Aop(TransAop.READ_COMMITTED) @Aop(TransAop.READ_COMMITTED)
public Result submit(@Param("data") Condolence condolence) { public Result submit(@Param("data") Condolence condolence) {
if(StrUtil.isBlank(condolence.getId())) condolence.setCreateTime(DateUtil.now()); condolenceService.saveApplication(condolence);
dao.insertOrUpdate(condolence);
// 开启流程实例 // 开启流程实例
Dict args = Dict.create(); Dict args = Dict.create();
args.set(FlowConst.SUBMIT_TYPE, ProcessSubmitTypeEnum.APPLY.getCode()); args.set(FlowConst.SUBMIT_TYPE, ProcessSubmitTypeEnum.APPLY.getCode());
@@ -108,7 +103,7 @@ public class CondolenceApplyController {
@Aop(TransAop.READ_COMMITTED) @Aop(TransAop.READ_COMMITTED)
@SaCheckPermission(value = {"condolence.apply", "h5.condolence.apply"}, mode = SaMode.OR) @SaCheckPermission(value = {"condolence.apply", "h5.condolence.apply"}, mode = SaMode.OR)
public Result submitAgain(@Param("data") Condolence condolence, @Param("taskId") Long taskId) { public Result submitAgain(@Param("data") Condolence condolence, @Param("taskId") Long taskId) {
dao.insertOrUpdate(condolence); condolenceService.saveApplication(condolence);
Dict dict = Dict.create(); Dict dict = Dict.create();
dict.set(FlowConst.PROCESS_TASK_ID_KEY, taskId); dict.set(FlowConst.PROCESS_TASK_ID_KEY, taskId);
@@ -14,6 +14,12 @@ import com.budwk.app.zhgh.staffbenefit.condolence.model.Condolence;
* @Description TODO * @Description TODO
*/ */
public interface CondolenceService extends BaseService<Condolence> { public interface CondolenceService extends BaseService<Condolence> {
/**
* 保存慰问申请,并使收款人始终与申请人一致;返回类型为 void,无返回数据。
* @param condolence 表单中的慰问申请,申请人 ID、姓名和工号用于确定收款人
*/
void saveApplication(Condolence condolence);
/** /**
* 按工会备案节点查询慰问任务,节点尚未配置时返回空分页。 * 按工会备案节点查询慰问任务,节点尚未配置时返回空分页。
* @param pageForm 页码、每页条数、姓名/工号关键字及排序参数 * @param pageForm 页码、每页条数、姓名/工号关键字及排序参数
@@ -20,6 +20,8 @@ import org.nutz.lang.util.NutMap;
import java.util.List; import java.util.List;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.nutz.dao.Dao; import org.nutz.dao.Dao;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
/** /**
@@ -37,6 +39,19 @@ public class CondolenceServiceImpl extends BaseServiceImpl<Condolence> implement
super(dao); super(dao);
} }
@Override
@Aop(TransAop.READ_COMMITTED)
public void saveApplication(Condolence condolence) {
// 收款人以申请表中的申请人为准,覆盖旧草稿及请求中单独提交的收款人信息。
condolence.setPayUserId(condolence.getApplyUserId());
condolence.setPayUserName(condolence.getApplyUserName());
condolence.setPayLoginName(condolence.getApplyLoginName());
if (StrUtil.isBlank(condolence.getId())) {
condolence.setCreateTime(DateUtil.now());
}
dao().insertOrUpdate(condolence);
}
// 工会备案的 wf 节点代码,与流程定义中的 taskName 保持一致。 // 工会备案的 wf 节点代码,与流程定义中的 taskName 保持一致。
private static final String UNION_RECORD_TASK_KEY = "80c3d6f8-978a-4f00-816e-338005240c7e"; private static final String UNION_RECORD_TASK_KEY = "80c3d6f8-978a-4f00-816e-338005240c7e";
@@ -99,6 +99,8 @@
let active = null let active = null
let serial = 0 let serial = 0
let pending = null let pending = null
let registered = null
let releasing = Promise.resolve()
let skippingClosedHistory = false let skippingClosedHistory = false
const sync = (closedKeys) => { const sync = (closedKeys) => {
if (active) active.onChange(active.keys.slice(), closedKeys) if (active) active.onChange(active.keys.slice(), closedKeys)
@@ -146,37 +148,55 @@
return { return {
/** 注册页面同步回调,参数为仍打开的弹框 key 数组;返回页面专用操作句柄。 */ /** 注册页面同步回调,参数为仍打开的弹框 key 数组;返回页面专用操作句柄。 */
register(onChange) { register(onChange) {
if (active) throw new Error("上一个页面的弹框历史尚未注销") if (registered) throw new Error("上一个页面的弹框历史尚未注销")
const owner = { id: Date.now() + "-" + (++serial), keys: [], onChange } const owner = { id: Date.now() + "-" + (++serial), keys: [], onChange, disposed: false }
active = owner registered = owner
// 旧页面注销时先释放注册资格;新页面的弹框操作等待旧历史回退完成,不能接管其 popstate。
const ready = active ? releasing.then(() => {
if (!owner.disposed) active = owner
}) : Promise.resolve()
if (!active) active = owner
const runOwned = (work) => {
const run = () => active === owner && !owner.disposed ? work() : undefined
return active === owner ? run() : ready.then(run)
}
let destroyed = null
return { return {
// key 是页面内唯一弹框名称;相同弹框重复打开不会重复压栈。 // key 是页面内唯一弹框名称;相同弹框重复打开不会重复压栈。
open(key) { open(key) {
const open = () => { const open = () => {
if (active !== owner || owner.keys.includes(key)) return if (active !== owner || owner.disposed || owner.keys.includes(key)) return
owner.keys.push(key) owner.keys.push(key)
window.history.pushState({ h5Popup: { owner: owner.id, depth: owner.keys.length } }, "", window.location.href) window.history.pushState({ h5Popup: { owner: owner.id, depth: owner.keys.length } }, "", window.location.href)
} }
return pending ? pending.promise.then(open) : Promise.resolve(open()) return Promise.resolve(runOwned(() => pending ? pending.promise.then(open) : open()))
}, },
// 关闭指定弹框及其上层弹框,返回 Promise<void>,保持后进先出。 // 关闭指定弹框及其上层弹框,返回 Promise<void>,保持后进先出。
close(key) { close(key) {
if (active !== owner) return Promise.resolve() return Promise.resolve(runOwned(() => {
const index = owner.keys.indexOf(key) const index = owner.keys.indexOf(key)
return index < 0 ? Promise.resolve() : rewind(index) return index < 0 ? undefined : rewind(index)
}))
}, },
clear() { clear() {
return active === owner ? rewind(0) : Promise.resolve() return Promise.resolve(runOwned(() => rewind(0)))
}, },
destroy() { destroy() {
if (destroyed) return destroyed
owner.disposed = true
if (registered === owner) registered = null
// 无弹框时同步注销,保证 PJAX 同次替换中下一个页面可以立即注册。 // 无弹框时同步注销,保证 PJAX 同次替换中下一个页面可以立即注册。
if (active === owner && !owner.keys.length && !pending) { if (active === owner && !owner.keys.length && !pending) {
active = null active = null
return Promise.resolve() destroyed = Promise.resolve()
return destroyed
} }
return this.clear().then(() => { // 新页面可能尚在等待更早页面释放历史;连续切换也必须按顺序完成注销。
destroyed = ready.then(() => active === owner ? rewind(0) : undefined).then(() => {
if (active === owner) active = null if (active === owner) active = null
}) })
releasing = destroyed
return destroyed
} }
} }
}, },
@@ -215,27 +235,17 @@
$(document).on("pjax:complete", function () { $(document).on("pjax:complete", function () {
if (window.customStyleList) { if (window.customStyleList) {
window.customStyleList.forEach((style) => { window.customStyleList.forEach((style) => {
style.parentNode.removeChild(style) // 页面替换或前一次清理可能已移除节点,仅清理仍挂载的旧样式。
if (style.parentNode) style.parentNode.removeChild(style)
}) })
window.customStyleList = null
} }
NProgress.done() NProgress.done()
toggleShowBar() toggleShowBar()
}) })
// 监听浏览器的前进和后退操作 // 普通页面前进/后退交给 PJAX 自带的 popstate.pjax 处理。
$(window).on("popstate", function (event) { // 弹框历史只有 h5Popup 标记,没有页面 url/container,不能再次发起页面请求。
if (event.originalEvent.state) {
// 如果存在历史记录状态,触发 Pjax 加载对应内容
$.pjax({
url: event.originalEvent.state.url,
container: "#container",
fragment: "#container",
timeout: 8000,
push: false,
scrollTo: false
})
}
})
} }
})() })()
@@ -116,14 +116,17 @@ const ACTIVITY_CULTURE_APPLY_ACTIVITY = {
<el-col :span="12"> <el-col :span="12">
<el-form-item label="实际活动时间" prop="time"> <el-form-item label="实际活动时间" prop="time">
<!-- 三类文化活动共用此表单,活动起止时间均保留到秒。 -->
<el-date-picker <el-date-picker
end-placeholder="结束日期" align="right"
end-placeholder="结束时间"
range-separator="-" range-separator="-"
start-placeholder="开始日期" start-placeholder="开始时间"
style="width: 100%" style="width: 100%"
type="daterange" format="yyyy-MM-dd HH:mm:ss"
type="datetimerange"
v-model="formData.time" v-model="formData.time"
value-format="yyyy-MM-dd"> value-format="yyyy-MM-dd HH:mm:ss">
</el-date-picker> </el-date-picker>
</el-form-item> </el-form-item>
</el-col> </el-col>
@@ -635,7 +635,7 @@ var ACTIVITY_SPORTS_APPLY_USER = {
} }
}, },
//点击添加运动员操作 //点击添加运动员操作
async applyUser() { applyUser() {
const {isManGirlNum, restrictGirlNum, restrictBoyNum} = this.eventData const {isManGirlNum, restrictGirlNum, restrictBoyNum} = this.eventData
if (!this.rightApplyUserList.length) { if (!this.rightApplyUserList.length) {
@@ -696,83 +696,85 @@ var ACTIVITY_SPORTS_APPLY_USER = {
} }
} }
const resp = await this.$axios.post(loc() + "/getActivityData", {activityId: this.activityData.id}) this.$axios.post(loc() + "/getActivityData", {activityId: this.activityData.id}).then((resp) => {
const aa = resp.data.filter((v) => { const aa = resp.data.filter((v) => {
return this.rightApplyUserList.includes(v.userId) return this.rightApplyUserList.includes(v.userId)
}) })
const groupData = groupBy(aa, (v) => { const groupData = groupBy(aa, (v) => {
return v.userId return v.userId
}) })
// 未配置限报数时不限制单项报名,避免 null 被 JavaScript 当作 0 比较。 // 每人限报项目数只在综合赛单项中配置;个人赛不能使用隐藏的历史限报值。
const hasSingleEventLimit = this.activityTableData.eveProjectType === '1' && const hasSingleEventLimit = this.activityTableData.applyType === 2 &&
Number.isInteger(this.eventData.restrictRegNumber) && this.eventData.restrictRegNumber >= 0 this.activityTableData.eveProjectType === '1' &&
const cc = hasSingleEventLimit ? groupData.filter((v) => { Number.isInteger(this.eventData.restrictRegNumber) && this.eventData.restrictRegNumber >= 0
return v.length >= this.eventData.restrictRegNumber const cc = hasSingleEventLimit ? groupData.filter((v) => {
}) : [] return v.length >= this.eventData.restrictRegNumber
}) : []
//从全部人员里找出右边框选择的人 //从全部人员里找出右边框选择的人
const arr = this.userList.filter((v) => { const arr = this.userList.filter((v) => {
return this.rightApplyUserList.includes(v.id) return this.rightApplyUserList.includes(v.id)
}) })
//表格的人员 //表格的人员
arr.forEach((v) => { arr.forEach((v) => {
this.applyFromData.teamName=this.teamList.find(t=>t.id===this.applyFromData.teamId)?.name this.applyFromData.teamName=this.teamList.find(t=>t.id===this.applyFromData.teamId)?.name
const data = { const data = {
id: null, id: null,
loginname: v.loginname, loginname: v.loginname,
username: v.username, username: v.username,
age: v.age, age: v.age,
professionalLevel: v.professionalLevel, professionalLevel: v.professionalLevel,
birthday: v.birthday, birthday: v.birthday,
unitId: v.unitId, unitId: v.unitId,
unionId: v.unionId, unionId: v.unionId,
unitname: v.unitname, unitname: v.unitname,
userId: v.id, userId: v.id,
mobile: v.mobile, mobile: v.mobile,
sex: v.sex, sex: v.sex,
awardsMode: this.activityTableData.eveProjectType, awardsMode: this.activityTableData.eveProjectType,
activityId: this.activityData.id, activityId: this.activityData.id,
teamId: this.applyFromData.teamId, teamId: this.applyFromData.teamId,
team: this.applyFromData.teamName, team: this.applyFromData.teamName,
identity: ["1"], identity: ["1"],
eventId: this.eventData.eventId eventId: this.eventData.eventId
} }
//然后把每一个人加到全部报名的字段中 //然后把每一个人加到全部报名的字段中
this.applyUserList.push(data) this.applyUserList.push(data)
//如果是单项判断每个人可以报几项
if (hasSingleEventLimit) {
cc.forEach((z) => {
if (z[0]) {
const index = this.applyUserList.findIndex((x) => x.userId === z[0].userId && x.id === null)
if (index > -1) {
this.applyUserList.splice(index, 1)
}
}
})
}
})
//如果是单项判断每个人可以报几项 //如果是单项判断每个人可以报几项
if (hasSingleEventLimit) { if (hasSingleEventLimit) {
cc.forEach((z) => { const usernames = cc.map((v) => v[0].username).join(",")
if (z[0]) { if (usernames) {
const index = this.applyUserList.findIndex((x) => x.userId === z[0].userId && x.id === null) this.$notify({
if (index > -1) { title: "警告",
this.applyUserList.splice(index, 1) message: usernames + "已报" + this.eventData.restrictRegNumber + "项",
} type: "warning"
} })
}) }
} }
})
//如果是单项判断每个人可以报几项 this.flushApplyUser(this.applyUserList)
if (hasSingleEventLimit) { this.$refs.transfer.clearQuery("right")
const usernames = cc.map((v) => v[0].username).join(",") this.$refs.transfer.clearQuery("left")
if (usernames) { this.leftApplyUserList = this.leftApplyUserList.filter((v) => {
this.$notify({ return !this.applyUserTableData.map((v) => v.userId).includes(v.id)
title: "警告", })
message: usernames + "已报" + this.eventData.restrictRegNumber + "项", this.rightApplyUserList = []
type: "warning" this.sortApplyUserTableData()
})
}
}
this.flushApplyUser(this.applyUserList)
this.$refs.transfer.clearQuery("right")
this.$refs.transfer.clearQuery("left")
this.leftApplyUserList = this.leftApplyUserList.filter((v) => {
return !this.applyUserTableData.map((v) => v.userId).includes(v.id)
}) })
this.rightApplyUserList = []
this.sortApplyUserTableData()
}, },
//勾选左边的框设置角色 //勾选左边的框设置角色
setUserRole(num) { setUserRole(num) {
@@ -20,6 +20,9 @@ const subjectForm = {
placeholder="请输入题目" placeholder="请输入题目"
style="flex: 1"> style="flex: 1">
</el-input> </el-input>
<el-button v-if="activity.category === 'SURVEY'" type="primary"
style="margin-left: 8px" icon="el-icon-setting"
@click="openSubjectVisibleSetting(subjectIndex, subject)">隐显逻辑</el-button>
</div> </div>
<div class="subject-meta"> <div class="subject-meta">
@@ -45,6 +48,17 @@ const subjectForm = {
<!-- </el-option>--> <!-- </el-option>-->
</el-select> </el-select>
</div> </div>
<div>
是否必填:
<el-select
:value="subject.required"
@change="subjectRequiredChange(subject, $event)"
placeholder="请选择是否必填"
style="width: 200px;">
<el-option label="必填" :value="true"></el-option>
<el-option label="非必填" :value="false"></el-option>
</el-select>
</div>
<div v-if="subject.type === 'checkbox'"> <div v-if="subject.type === 'checkbox'">
最大选择数: 最大选择数:
<el-input-number v-model="subject.maxMulti" placeholder="最多可选数量"></el-input-number> <el-input-number v-model="subject.maxMulti" placeholder="最多可选数量"></el-input-number>
@@ -205,7 +219,7 @@ const subjectForm = {
<el-button type="primary" icon="el-icon-plus" @click="addSubject"> <el-button type="primary" icon="el-icon-plus" @click="addSubject">
添加题目 添加题目
</el-button> </el-button>
<el-button type="primary" icon="el-icon-check" @click="saveQuestionnaire"> <el-button type="primary" icon="el-icon-check" :loading="formLoading" @click="saveQuestionnaire">
保存题目 保存题目
</el-button> </el-button>
</div> </div>
@@ -214,6 +228,87 @@ const subjectForm = {
<setting ref="settingRef" @confirm="onSettingConfirm"></setting> <setting ref="settingRef" @confirm="onSettingConfirm"></setting>
<txt-import ref="txtImportRef" @confirm="onTxtImportConfirm"></txt-import> <txt-import ref="txtImportRef" @confirm="onTxtImportConfirm"></txt-import>
<bank ref="bankRef" @confirm="onBankConfirm"></bank> <bank ref="bankRef" @confirm="onBankConfirm"></bank>
<el-dialog
title="设置题目隐显逻辑"
:visible.sync="subjectVisibleSetting.visible"
append-to-body
width="520px">
<el-form :model="subjectVisibleSetting.formData" label-width="110px">
<el-form-item label="启用逻辑">
<el-switch
v-model="subjectVisibleSetting.formData.enabled"
active-text="启用"
inactive-text="关闭">
</el-switch>
</el-form-item>
<template v-if="subjectVisibleSetting.formData.enabled">
<el-form-item label="处理方式">
<el-radio-group v-model="subjectVisibleSetting.formData.action">
<el-radio label="show">选中后显示本题</el-radio>
<el-radio label="hide">选中后隐藏本题</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="条件关系">
<el-radio-group v-model="subjectVisibleSetting.formData.logic">
<el-radio label="AND">并且</el-radio>
<el-radio label="OR">或者</el-radio>
</el-radio-group>
</el-form-item>
<div
v-for="(condition, conditionIndex) in subjectVisibleSetting.formData.conditions"
:key="conditionIndex"
class="subject-visible-condition">
<el-form-item :label="'条件' + (conditionIndex + 1)">
<div style="display: flex; gap: 8px;">
<el-select
v-model="condition.subjectId"
placeholder="请选择触发题目"
style="flex: 1;"
@change="subjectVisibleRuleSubjectChange(condition)">
<el-option
v-for="item in subjectVisibleRuleSubjects"
:key="item.id"
:label="item.title || '未填写题目'"
:value="item.id">
</el-option>
</el-select>
<el-select
v-model="condition.optionId"
placeholder="请选择触发选项"
style="flex: 1;">
<el-option
v-for="item in getSubjectVisibleRuleOptions(condition.subjectId)"
:key="item.id"
:label="item.text || '未填写选项'"
:value="item.id">
</el-option>
</el-select>
<el-button
type="danger"
icon="el-icon-delete"
size="mini"
@click="removeSubjectVisibleRuleCondition(conditionIndex)">
</el-button>
</div>
</el-form-item>
</div>
<el-form-item label="">
<el-button
type="primary"
icon="el-icon-plus"
size="small"
@click="addSubjectVisibleRuleCondition">
添加条件
</el-button>
</el-form-item>
</template>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="closeSubjectVisibleSetting">取 消</el-button>
<el-button type="primary" @click="onSubjectVisibleSettingConfirm">确 定</el-button>
</div>
</el-dialog>
</div> </div>
`, `,
components: { components: {
@@ -230,7 +325,33 @@ const subjectForm = {
subjects: [], subjects: [],
previewDialogVisible: false, previewDialogVisible: false,
activity: {}, activity: {},
formRules: {} formLoading: false,
formRules: {},
subjectVisibleSetting: {
visible: false,
subjectIndex: null,
formData: {
enabled: false,
action: "show",
logic: "AND",
conditions: [
{
subjectId: "",
optionId: ""
}
]
}
}
}
},
computed: {
subjectVisibleRuleSubjects() {
if (this.subjectVisibleSetting.subjectIndex === null) {
return []
}
return this.subjects.filter((item, index) => {
return index < this.subjectVisibleSetting.subjectIndex && ["radio", "checkbox"].includes(item.type)
})
} }
}, },
methods: { methods: {
@@ -245,7 +366,11 @@ const subjectForm = {
}) })
$.post("/platform/qsv/activity/listSubjects", {activityId: id}).then((res) => { $.post("/platform/qsv/activity/listSubjects", {activityId: id}).then((res) => {
if (res.code === 0) { if (res.code === 0) {
this.subjects = res.data // 旧题未设置必填属性时沿用必填规则,已设置的非必填值保持不变。
res.data.forEach((subject) => {
this.$set(subject, "required", subject.required !== false)
})
this.$set(this, "subjects", res.data)
} }
}) })
} }
@@ -263,6 +388,8 @@ const subjectForm = {
title: "", title: "",
hint: "", hint: "",
type: "radio", type: "radio",
// 手工新增题目默认必填,允许在题目类型右侧切换为非必填。
required: true,
score: 0, score: 0,
displayDate: "", displayDate: "",
options: [ options: [
@@ -284,6 +411,11 @@ const subjectForm = {
}) })
}, },
// subject 为当前题目,required 为下拉框返回的布尔值;响应式更新必填设置,不返回结果。
subjectRequiredChange(subject, required) {
this.$set(subject, "required", required)
},
//题目类型切换 //题目类型切换
subjectTypeChange(subject, subjectIndex) { subjectTypeChange(subject, subjectIndex) {
if (subject.type === 'text') { if (subject.type === 'text') {
@@ -358,6 +490,136 @@ const subjectForm = {
// this.$set(this.subjects[ext.subjectIndex].options[ext.optionIndex], "hint", option.hint) // this.$set(this.subjects[ext.subjectIndex].options[ext.optionIndex], "hint", option.hint)
}, },
//打开题目隐显逻辑设置,用于配置当前题目受前置选择题的哪个选项控制显示或隐藏
openSubjectVisibleSetting(subjectIndex, subject) {
const conditions = this.buildSubjectVisibleConditions(subject)
this.$set(this.subjectVisibleSetting, "subjectIndex", subjectIndex)
this.$set(this.subjectVisibleSetting, "formData", {
enabled: !!subject.visibleRuleEnabled,
action: subject.visibleRuleAction || "show",
logic: subject.visibleRuleLogic || "AND",
conditions
})
this.$set(this.subjectVisibleSetting, "visible", true)
},
//构建题目隐显逻辑条件,已有条件按实际数量回显;未配置时默认提供一条空条件
buildSubjectVisibleConditions(subject) {
let visibleRuleConditions = subject.visibleRuleConditions || []
if (typeof visibleRuleConditions === "string") {
try {
visibleRuleConditions = JSON.parse(visibleRuleConditions)
} catch (e) {
visibleRuleConditions = []
}
}
const conditions = Array.isArray(visibleRuleConditions) ? visibleRuleConditions.filter((condition) => condition) : []
const result = conditions.map((condition) => {
return {
subjectId: condition.subjectId || "",
optionId: condition.optionId || ""
}
})
if (result.length === 0) {
result.push({
subjectId: "",
optionId: ""
})
}
return result
},
//根据触发题目获取可选项,用于每条隐显条件选择触发选项
getSubjectVisibleRuleOptions(subjectId) {
const subject = this.subjects.find((item) => {
return item.id === subjectId
})
if (!subject || !subject.options) {
return []
}
return subject.options
},
//切换触发题目后清空当前条件的旧选项,避免保留其他题目的选项导致隐显条件错误
subjectVisibleRuleSubjectChange(condition) {
this.$set(condition, "optionId", "")
},
//添加一条隐显逻辑条件,多个条件通过条件关系字段统一按并且或或者计算
addSubjectVisibleRuleCondition() {
this.subjectVisibleSetting.formData.conditions.push({
subjectId: "",
optionId: ""
})
},
//删除一条隐显逻辑条件,至少保留一条条件用于继续配置
removeSubjectVisibleRuleCondition(conditionIndex) {
if (this.subjectVisibleSetting.formData.conditions.length === 1) {
this.$message.warning("至少保留一条条件")
return
}
this.subjectVisibleSetting.formData.conditions.splice(conditionIndex, 1)
},
//保存题目隐显逻辑到当前题目对象,后续保存题目时随 subjects 一起提交
onSubjectVisibleSettingConfirm() {
const subjectIndex = this.subjectVisibleSetting.subjectIndex
if (subjectIndex === null) {
return
}
const formData = this.subjectVisibleSetting.formData
if (formData.enabled) {
for (let i = 0; i < formData.conditions.length; i++) {
const condition = formData.conditions[i]
if (!condition.subjectId || !condition.optionId) {
this.$message.warning("请选择条件" + (i + 1) + "的触发题目和触发选项")
return
}
}
}
this.$set(this.subjects[subjectIndex], "visibleRuleEnabled", formData.enabled)
this.$set(this.subjects[subjectIndex], "visibleRuleAction", formData.enabled ? formData.action : "show")
this.$set(this.subjects[subjectIndex], "visibleRuleLogic", formData.enabled ? formData.logic : "AND")
this.$set(this.subjects[subjectIndex], "visibleRuleConditions", formData.enabled ? formData.conditions.map((condition) => {
return {
subjectId: condition.subjectId,
optionId: condition.optionId
}
}) : [])
this.closeSubjectVisibleSetting()
},
//关闭配置弹框;取消时不将编辑中的条件写回题目。
closeSubjectVisibleSetting() {
this.$set(this.subjectVisibleSetting, "visible", false)
},
//保存整份问卷前核对前置题和选项,阻止删除、改题型或拖动排序后留下失效依赖。
validateSubjectVisibleRules() {
for (let index = 0; index < this.subjects.length; index++) {
const subject = this.subjects[index]
if (!subject.visibleRuleEnabled) {
continue
}
const conditions = this.buildSubjectVisibleConditions(subject)
const valid = ["show", "hide"].includes(subject.visibleRuleAction)
&& ["AND", "OR"].includes(subject.visibleRuleLogic)
&& conditions.every((condition) => {
return this.subjects.slice(0, index).some((trigger) => {
return trigger.id === condition.subjectId
&& ["radio", "checkbox"].includes(trigger.type)
&& (trigger.options || []).some((option) => option.id === condition.optionId)
})
})
if (!valid) {
this.$message.warning("第" + (index + 1) + "题的隐显条件已失效,请重新选择前置题目和选项或关闭规则")
return false
}
}
return true
},
//从文本导入 //从文本导入
openTxtImport() { openTxtImport() {
this.$refs.txtImportRef.visible = true; this.$refs.txtImportRef.visible = true;
@@ -375,6 +637,8 @@ const subjectForm = {
// 更新导入题目的序号 // 更新导入题目的序号
importedQuestions.forEach((question, index) => { importedQuestions.forEach((question, index) => {
question.sortNum = startSortNum + index; question.sortNum = startSortNum + index;
// 文本导入没有必填配置时默认必填,保留明确的非必填设置。
this.$set(question, "required", question.required !== false);
}); });
// 将导入的题目添加到现有题目列表 // 将导入的题目添加到现有题目列表
@@ -395,6 +659,10 @@ const subjectForm = {
//保存 //保存
saveQuestionnaire() { saveQuestionnaire() {
if (this.activity.category === "SURVEY" && !this.validateSubjectVisibleRules()) {
return
}
this.$set(this, "formLoading", true)
$ $
.post("/platform/qsv/activity/saveSubjects", { .post("/platform/qsv/activity/saveSubjects", {
activityId: this.id, activityId: this.id,
@@ -402,11 +670,14 @@ const subjectForm = {
}) })
.then((res) => { .then((res) => {
if (res.code === 0) { if (res.code === 0) {
this.visible = false this.$set(this, "visible", false)
this.$message.success(res.msg) this.$message.success(res.msg)
this.$emit("refresh", null) this.$emit("refresh", null)
} }
}) })
.always(() => {
this.$set(this, "formLoading", false)
})
} }
}, },
style: /*language=CSS*/ ` style: /*language=CSS*/ `
@@ -189,12 +189,13 @@ const PROPOSAL_INFO = {
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="主办单位" :span="3">{{task.ext.tf_masterUnitName}} <el-descriptions-item label="主办单位" :span="3">{{task.ext.tf_masterUnitName}}
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="协办单位" :span="3">{{task?.ext?.tf_slaveUnitNameStr}} <el-descriptions-item label="协办单位" :span="3">{{getSlaveUnitNames(task)}}
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="指定分管校领导" :span="3" v-if="getBranchSchoolLeaderName(task)"> <el-descriptions-item label="指定分管校领导" :span="3" v-if="getBranchSchoolLeaderName(task)">
{{getBranchSchoolLeaderName(task)}} {{getBranchSchoolLeaderName(task)}}
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="办理意见" :span="3"> <el-descriptions-item label="办理意见" :span="3">
<!-- 主任意见统一读取本节点提交的 tf_opinion;历史意见由专项 SQL 修正。 -->
<div v-html="task.taskFormData.tf_opinion"></div> <div v-html="task.taskFormData.tf_opinion"></div>
</el-descriptions-item> </el-descriptions-item>
</el-descriptions> </el-descriptions>
@@ -214,14 +215,20 @@ const PROPOSAL_INFO = {
{{getBranchSchoolLeaderName(task)}} {{getBranchSchoolLeaderName(task)}}
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="办理意见" :span="3"> <el-descriptions-item label="办理意见" :span="3">
<!-- 主任审核统一读取本节点提交的 tf_opinion,避免展示前序单位的答复。 -->
<div v-html="task.taskFormData.tf_opinion"></div> <div v-html="task.taskFormData.tf_opinion"></div>
</el-descriptions-item> </el-descriptions-item>
</el-descriptions> </el-descriptions>
<el-descriptions border class="flow-task-form" :column="3" :key="task.id" v-else> <el-descriptions border class="flow-task-form" :column="3" :key="task.id" v-else>
<el-descriptions-item label="承办单位" <el-descriptions-item label="承办单位"
v-if="['master_reply','slave_reply'].includes(task.taskName)" :span="3"> v-if="isReplyTask(task)" :span="3">
{{task.ext.underTakeName}} {{getReplyUnitName(task)}}
</el-descriptions-item>
<el-descriptions-item label="落实情况" v-if="isReplyTask(task)" :span="3">
<dict-tag v-if="task.ext.tf_implementState" :options="dict.type.PROPOSAL_REPLY_IMPLEMENT"
:value="task.ext.tf_implementState"></dict-tag>
<span v-else>未记录</span>
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="办理用户">{{ task.taskFormData.userName <el-descriptions-item label="办理用户">{{ task.taskFormData.userName
@@ -233,6 +240,9 @@ const PROPOSAL_INFO = {
<dict-tag :options="dict.type.PROPOSAL_FEEDBACK" <dict-tag :options="dict.type.PROPOSAL_FEEDBACK"
:value="task.ext.tf_feedback"></dict-tag> :value="task.ext.tf_feedback"></dict-tag>
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="办理结果" v-else-if="getSchoolLeaderResult(task)">
{{getSchoolLeaderResult(task)}}
</el-descriptions-item>
<el-descriptions-item label="办理结果" v-else> <el-descriptions-item label="办理结果" v-else>
<dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE" <dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE"
:value="task.ext.submitType"></dict-tag> :value="task.ext.submitType"></dict-tag>
@@ -247,7 +257,7 @@ const PROPOSAL_INFO = {
<slot></slot> <slot></slot>
</div> </div>
`, `,
dicts: ["PROPOSAL_TYPE", "PROPOSAL_CASE_FILING_RESULT", "PROPOSAL_SUGGESTION_CASE_FILING_RESULT", "PROPOSAL_CASE_FILING_TYPE", "PROCESS_TASK_SUBMIT_TYPE", "PROPOSAL_FEEDBACK"], dicts: ["PROPOSAL_TYPE", "PROPOSAL_CASE_FILING_RESULT", "PROPOSAL_SUGGESTION_CASE_FILING_RESULT", "PROPOSAL_CASE_FILING_TYPE", "PROCESS_TASK_SUBMIT_TYPE", "PROPOSAL_FEEDBACK", "PROPOSAL_REPLY_IMPLEMENT"],
props: { props: {
hide_slave: false hide_slave: false
}, },
@@ -259,12 +269,18 @@ const PROPOSAL_INFO = {
viewDialogVisible: false, viewDialogVisible: false,
positiveSecondList: [], positiveSecondList: [],
branchSchoolLeaderOptions: [], branchSchoolLeaderOptions: [],
detailRequestVersion: 0,
} }
}, },
methods: { methods: {
// 打开 // 打开
onOpen(row) { onOpen(row) {
this.row = row // 每次打开递增版本,阻止前一次查看的迟到响应覆盖当前提案(包括 A→B→A)。
this.$set(this, "detailRequestVersion", this.detailRequestVersion + 1)
this.$set(this, "row", row)
this.$set(this, "viewData", {})
this.$set(this, "doneTasks", [])
this.$set(this, "positiveSecondList", [])
this.visible = true this.visible = true
this.getInfo() this.getInfo()
this.getDoneTasks() this.getDoneTasks()
@@ -274,9 +290,10 @@ const PROPOSAL_INFO = {
// 获取申请信息 // 获取申请信息
getInfo() { getInfo() {
const requestVersion = this.detailRequestVersion
this.$axios.post("/platform/proposal/common/proposalInfo", {id: this.row.id}).then((res) => { this.$axios.post("/platform/proposal/common/proposalInfo", {id: this.row.id}).then((res) => {
if (res.code === 0) { if (res.code === 0 && requestVersion === this.detailRequestVersion) {
this.viewData = res.data this.$set(this, "viewData", res.data)
} }
}) })
}, },
@@ -291,22 +308,57 @@ const PROPOSAL_INFO = {
// 获取已办任务审批记录 // 获取已办任务审批记录
getDoneTasks() { getDoneTasks() {
const requestVersion = this.detailRequestVersion
this.$axios.post("/flow/common/doneTasks", {bizId: this.row.id}).then((res) => { this.$axios.post("/flow/common/doneTasks", {bizId: this.row.id}).then((res) => {
if (res.code === 0) { if (res.code === 0 && requestVersion === this.detailRequestVersion) {
this.doneTasks = res.data this.$set(this, "doneTasks", res.data)
} }
}) })
}, },
// 获取主动附议信息 // 获取主动附议信息
listPositiveSeconded() { listPositiveSeconded() {
const requestVersion = this.detailRequestVersion
this.$axios.post("/platform/proposal/positiveSeconded/listPositiveSeconded", {bizId: this.row.id}).then((res) => { this.$axios.post("/platform/proposal/positiveSeconded/listPositiveSeconded", {bizId: this.row.id}).then((res) => {
if (res.code === 0) { if (res.code === 0 && requestVersion === this.detailRequestVersion) {
this.positiveSecondList = res.data this.$set(this, "positiveSecondList", res.data)
} }
}) })
}, },
// task 为主任已办任务;返回分号分隔的单位名称,旧记录仅转换原拼接用的英文逗号,不拆分单位内部顿号。
getSlaveUnitNames(task) {
const ext = task.ext || {}
if (Array.isArray(ext.tf_slaveUnitNames)) {
return ext.tf_slaveUnitNames.join(";")
}
return (ext.tf_slaveUnitNameStr || "").split(",").join(";")
},
// 三类答复节点均展示单位和落实情况,其他节点不能展示继承的答复字段。
isReplyTask(task) {
return ["master_reply", "slave_reply", "opinion_master_reply"].includes(task.taskName)
},
// task 为已办任务;返回单位名称。仅主办允许使用本任务保存的主办名称补齐历史缺失值。
getReplyUnitName(task) {
const ext = task.ext || {}
if (ext.underTakeName) {
return ext.underTakeName
}
return ["master_reply", "opinion_master_reply"].includes(task.taskName)
? (ext.tf_masterUnitName || "未记录") : "未记录"
},
// task 为已办任务;校领导返回实际审批动作文本,其他节点或旧记录缺少动作时返回空串沿用提交结果。
getSchoolLeaderResult(task) {
if (!["school_leader", "school_leader_instruction"].includes(task.taskName)) {
return ""
}
const approval = task.ext?.tf_approval
return approval === "back" ? "退回重新答复" : (approval === "agree" ? "同意" : "")
},
// 查询分管校领导,用于把流程任务中保存的 userId 显示成姓名。 // 查询分管校领导,用于把流程任务中保存的 userId 显示成姓名。
listBranchSchoolLeader() { listBranchSchoolLeader() {
if (this.branchSchoolLeaderOptions.length > 0) { if (this.branchSchoolLeaderOptions.length > 0) {
@@ -0,0 +1,125 @@
// 仅供提案办理页面使用:同一页面的表单、并案和转办共用办理锁,查询与分页仍使用原 mixin。
const PROPOSAL_SUBMIT_MIXIN = {
data() {
return {
formLoading: false,
formAction: '',
proposalSubmitting: false
}
},
created() {
// H5 每个页面只注册一个历史栈所有者,子组件共享它,避免多层弹框重复监听 popstate。
if (this === this.$root && this.$options.proposalH5) {
this.proposalPopupRecords = new Map()
this.proposalPopupSerial = 0
this.proposalPopupHandle = window.h5PopupHistory.register((keys, closedKeys) => {
closedKeys.slice().reverse().forEach((key) => {
const record = this.proposalPopupRecords.get(key)
if (record) {
record.fromHistory = true
record.close()
record.fromHistory = false
}
})
})
// PJAX 只替换 DOM,不会自动销毁 Vue;替换所属容器前释放旧页面的历史栈所有权。
this.proposalBeforeReplace = (event) => {
if (this.$el && (event.target === this.$el || event.target.contains(this.$el))) {
this.$destroy()
}
}
$(document).on('pjax:beforeReplace', this.proposalBeforeReplace)
}
// options 中只列出本页面已有的弹框状态,不创建新弹框或改变业务字段。
;(this.$options.proposalPopupFields || []).forEach((field) => {
this.$root.trackProposalPopup(this, field)
})
},
beforeDestroy() {
this.proposalDisposed = true
// 每个 H5 根实例仅监听自己的页面替换;主动销毁或 PJAX 离开后均移除监听,避免残留实例重复响应。
if (this.proposalBeforeReplace) {
$(document).off('pjax:beforeReplace', this.proposalBeforeReplace)
}
if (this.proposalPopupUnwatch) this.proposalPopupUnwatch.forEach((stop) => stop())
if (this !== this.$root && this.$root.proposalPopupRecords) {
this.$root.proposalPopupRecords.forEach((record, key) => {
if (record.vm === this) {
this.$root.proposalPopupHandle.close(key)
this.$root.proposalPopupRecords.delete(key)
}
})
}
if (this === this.$root && this.proposalPopupHandle) this.proposalPopupHandle.destroy()
},
methods: {
/** action 为按钮标识,work 返回包含校验、确认和所有提交请求的 Promise;结束后统一释放锁。 */
runProposalSubmit(action, work) {
if (this.proposalDisposed || this.$root.proposalDisposed || this.formLoading || this.$root.proposalSubmitting) return Promise.resolve()
this.$set(this, 'formLoading', true)
this.$set(this, 'formAction', action)
this.$set(this.$root, 'proposalSubmitting', true)
return Promise.resolve().then(() => {
if (!this.proposalDisposed && !this.$root.proposalDisposed) return work()
}).catch(() => {
// 表单校验、确认取消以及 axios 拦截器已负责提示;不重复提示或重发流程请求。
}).finally(() => {
if (this.proposalDisposed || this.$root.proposalDisposed) return
this.$set(this, 'formLoading', false)
this.$set(this, 'formAction', '')
this.$set(this.$root, 'proposalSubmitting', false)
})
},
/** 将已有 v-model 与全局历史栈同步;返回键只关闭最上层,程序关闭也同步回退历史。 */
trackProposalPopup(vm, field) {
const root = this.$root
if (!root.proposalPopupHandle) return
const key = 'proposal-popup-' + (++root.proposalPopupSerial)
const record = { vm, field, fromHistory: false, close: () => vm.$set(vm, field, false) }
root.proposalPopupRecords.set(key, record)
const stop = vm.$watch(field, (visible) => {
if (record.fromHistory) return
if (visible) root.proposalPopupHandle.open(key)
else root.proposalPopupHandle.close(key)
}, { sync: true })
if (!vm.proposalPopupUnwatch) vm.proposalPopupUnwatch = []
vm.proposalPopupUnwatch.push(stop)
if (vm[field]) root.proposalPopupHandle.open(key)
},
/** options 沿用 Vant 确认框参数;确认/取消均先回退确认框历史,再向调用方传递结果。 */
proposalConfirm(options) {
const root = this.$root
if (this.proposalDisposed || root.proposalDisposed) return Promise.reject('cancel')
const key = 'proposal-confirm-' + (++root.proposalPopupSerial)
let settled = false
let cancelConfirmation
const cancelled = new Promise((resolve, reject) => { cancelConfirmation = reject })
root.proposalPopupRecords.set(key, { close: () => {
if (!settled) {
// Vant Dialog.close() 只隐藏界面,不会拒绝 confirm Promise,必须同时结束等待。
cancelConfirmation('cancel')
this.$dialog.close()
}
} })
// 等待旧页面历史释放期间也监听取消,避免页面已销毁后才打开确认框。
const confirmation = root.proposalPopupHandle.open(key).then(() => {
if (this.proposalDisposed || root.proposalDisposed) return Promise.reject('cancel')
return this.$dialog.confirm(Object.assign({}, options, { closeOnPopstate: false }))
})
return Promise.race([confirmation, cancelled]).finally(() => {
settled = true
return root.proposalPopupHandle.close(key).then(() => {
root.proposalPopupRecords.delete(key)
})
})
},
/** 关闭本页面所有提案弹框后执行成功回调,防止提交完成后返回到已关闭的审核弹层。 */
finishProposalSubmit(work) {
const root = this.$root
if (this.proposalDisposed || root.proposalDisposed) return Promise.resolve()
return (root.proposalPopupHandle ? root.proposalPopupHandle.clear() : Promise.resolve()).then(() => {
if (!this.proposalDisposed && !root.proposalDisposed) return work()
})
}
}
}
@@ -84,8 +84,8 @@ layout("/layouts/platform.html"){
</el-table-column> </el-table-column>
<el-table-column label="操作" fixed="right" width="200px"> <el-table-column label="操作" fixed="right" width="200px">
<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" :disabled="$root.proposalSubmitting">查看</el-button>
<el-button v-if="row.taskState === 10" @click="openAudit(row)" size="mini" type="primary">审核</el-button> <el-button v-if="row.taskState === 10" @click="openAudit(row)" size="mini" type="primary" :disabled="$root.proposalSubmitting">审核</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@@ -98,7 +98,7 @@ layout("/layouts/platform.html"){
<div class="process-title"> <div class="process-title">
提案委员会成员意见 提案委员会成员意见
</div> </div>
<el-form :model="formData" ref="formRef" label-width="120px" :rules="formRules" label-suffix=""> <el-form :model="formData" ref="formRef" label-width="120px" :rules="formRules" label-suffix="" :disabled="$root.proposalSubmitting">
<el-form-item label="审核意见" prop="opinion" <el-form-item label="审核意见" prop="opinion"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]"> :rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<div class="commissioner-opinion-box"> <div class="commissioner-opinion-box">
@@ -122,8 +122,8 @@ layout("/layouts/platform.html"){
<!-- </el-form-item>--> <!-- </el-form-item>-->
</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" :disabled="$root.proposalSubmitting">取消</el-button>
<el-button @click="doSubmit" size="small" type="primary">提交</el-button> <el-button @click="doSubmit" size="small" type="primary" :loading="formLoading && formAction === ('doSubmit')" :disabled="$root.proposalSubmitting">提交</el-button>
</el-row> </el-row>
</div> </div>
</proposal-info> </proposal-info>
@@ -133,13 +133,15 @@ layout("/layouts/platform.html"){
</div> </div>
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
<!--#include("/platform/zhgh/democratic/proposal/common/submit.js"){}#-->
<!--#include('../../common/info.js'){}#--> <!--#include('../../common/info.js'){}#-->
new Vue({ new Vue({
el: "#app", el: "#app",
store, store,
dicts: ["PROPOSAL_CASE_FILING_RESULT", "PROPOSAL_SUGGESTION_CASE_FILING_RESULT", "PROPOSAL_CASE_FILING_TYPE"], dicts: ["PROPOSAL_CASE_FILING_RESULT", "PROPOSAL_SUGGESTION_CASE_FILING_RESULT", "PROPOSAL_CASE_FILING_TYPE"],
mixins: [initTableMixins], mixins: [initTableMixins, PROPOSAL_SUBMIT_MIXIN],
components: { components: {
"proposal-info": PROPOSAL_INFO "proposal-info": PROPOSAL_INFO
}, },
@@ -173,16 +175,18 @@ layout("/layouts/platform.html"){
}, },
methods: { methods: {
openView(row) { openView(row) {
if (this.$root.proposalSubmitting) return
this.$refs.guava.edit(() => { this.$refs.guava.edit(() => {
this.showApprovalForm = false this.$set(this, "showApprovalForm", false)
this.$refs.proposalInfoRef.onOpen(row) this.$refs.proposalInfoRef.onOpen(row)
}) })
}, },
// 审批 // 审批
openAudit(row) { openAudit(row) {
if (this.$root.proposalSubmitting) return
this.$refs.guava.edit(() => { this.$refs.guava.edit(() => {
this.showApprovalForm = true this.$set(this, "showApprovalForm", true)
this.$set(this, "formData", { this.$set(this, "formData", {
processTaskId: row.taskId, processTaskId: row.taskId,
proposalId: row.id, proposalId: row.id,
@@ -195,23 +199,27 @@ layout("/layouts/platform.html"){
}, },
doSubmit() { doSubmit() {
if (!this.formData.caseFilingResult) { return this.runProposalSubmit("doSubmit", () => {
this.$message.warning("请选择立案结果") if (!this.formData.caseFilingResult) {
return this.$message.warning("请选择立案结果")
} return
this.$refs.formRef.validate((valid) => { }
if (!valid) return return new Promise((resolve) => {
this.$confirm("您确定要提交吗?", "提示", { this.$refs.formRef.validate(resolve)
confirmButtonText: "确定", }).then((valid) => {
cancelButtonText: "取消", if (!valid) return
type: "warning" return this.$confirm("您确定要提交吗?", "提示", {
}).then(() => { confirmButtonText: "确定",
this.$axios.post('/platform/proposal/commissioner/doApproval', this.formData).then(res => { cancelButtonText: "取消",
if (res.code === 0) { type: "warning"
this.$message.success(res.msg) }).then(() => {
this.doSearch() return this.$axios.post("/platform/proposal/commissioner/doApproval", this.formData).then((res) => {
this.$refs.guava.index() if (res.code === 0) {
} this.$message.success(res.msg)
this.doSearch()
this.$refs.guava.index()
}
})
}) })
}) })
}) })
@@ -47,7 +47,7 @@ layout("/layouts/platform.html"){
<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" :disabled="$root.proposalSubmitting">并案审核</el-button>
<el-radio-group v-model="pageForm.approval" size="small" @change="doSearch"> <el-radio-group v-model="pageForm.approval" size="small" @change="doSearch">
<el-radio-button :label="true">已审核</el-radio-button> <el-radio-button :label="true">已审核</el-radio-button>
<el-radio-button :label="false">未审核</el-radio-button> <el-radio-button :label="false">未审核</el-radio-button>
@@ -82,10 +82,10 @@ layout("/layouts/platform.html"){
</el-table-column> </el-table-column>
<el-table-column label="操作" fixed="right" width="300px"> <el-table-column label="操作" fixed="right" width="300px">
<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" :disabled="$root.proposalSubmitting">查看</el-button>
<el-button v-if="row.taskState === 10" @click="openAudit(row)" size="mini" type="primary">审核 <el-button v-if="row.taskState === 10" @click="openAudit(row)" size="mini" type="primary" :disabled="$root.proposalSubmitting">审核
</el-button> </el-button>
<el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">撤回 <el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger" :disabled="$root.proposalSubmitting">撤回
</el-button> </el-button>
</template> </template>
</el-table-column> </el-table-column>
@@ -99,7 +99,7 @@ layout("/layouts/platform.html"){
<div class="process-title"> <div class="process-title">
{{formData.taskName}} {{formData.taskName}}
</div> </div>
<el-form :model="formData" ref="formRef" label-width="120px" :rules="formRules" label-suffix=""> <el-form :model="formData" ref="formRef" label-width="120px" :rules="formRules" label-suffix="" :disabled="$root.proposalSubmitting">
<el-form-item v-if="isCommitteeTask()" label="立案结果" prop="tf_caseFilingResult" <el-form-item v-if="isCommitteeTask()" label="立案结果" prop="tf_caseFilingResult"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]"> :rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-radio-group v-model="formData.tf_caseFilingResult" size="small"> <el-radio-group v-model="formData.tf_caseFilingResult" size="small">
@@ -172,15 +172,16 @@ layout("/layouts/platform.html"){
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="审核意见" prop="approvalOpinion" <!-- 本节点本人填写的审核意见统一提交为 tf_opinion,覆盖流程继承的前序意见。 -->
<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">
<el-button @click="$refs.guava.index()" size="small">取消</el-button> <el-button @click="$refs.guava.index()" size="small" :disabled="$root.proposalSubmitting">取消</el-button>
<el-button @click="handleTaskAction(6)" size="small" type="info">退回到提案人</el-button> <el-button @click="handleTaskAction(6)" size="small" type="info" :loading="formLoading && formAction === ('handleTaskAction:' + 6)" :disabled="$root.proposalSubmitting">退回到提案人</el-button>
<el-button @click="handleTaskAction(1)" size="small" type="primary">提交</el-button> <el-button @click="handleTaskAction(1)" size="small" type="primary" :loading="formLoading && formAction === ('handleTaskAction:' + 1)" :disabled="$root.proposalSubmitting">提交</el-button>
</el-row> </el-row>
</div> </div>
</proposal-info> </proposal-info>
@@ -193,6 +194,8 @@ layout("/layouts/platform.html"){
</div> </div>
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
<!--#include("/platform/zhgh/democratic/proposal/common/submit.js"){}#-->
<!--#include("../../common/info.js"){}#--> <!--#include("../../common/info.js"){}#-->
<!--#include('merge.js'){}#--> <!--#include('merge.js'){}#-->
@@ -200,7 +203,7 @@ layout("/layouts/platform.html"){
el: "#app", el: "#app",
store, store,
dicts: ["PROPOSAL_CASE_FILING_RESULT", "PROPOSAL_CASE_FILING_TYPE"], dicts: ["PROPOSAL_CASE_FILING_RESULT", "PROPOSAL_CASE_FILING_TYPE"],
mixins: [initTableMixins], mixins: [initTableMixins, PROPOSAL_SUBMIT_MIXIN],
components: { components: {
"proposal-info": PROPOSAL_INFO, "proposal-info": PROPOSAL_INFO,
merge merge
@@ -222,6 +225,7 @@ layout("/layouts/platform.html"){
approval: false approval: false
}, },
formData: { formData: {
tf_opinion: null,
tf_masterUnitId: null, tf_masterUnitId: null,
tf_slaveUnitIds: [] tf_slaveUnitIds: []
}, },
@@ -229,7 +233,7 @@ layout("/layouts/platform.html"){
tf_caseFilingResult: [{ required: true, message: "请选择立案结果", trigger: ["blur", "change"] }], tf_caseFilingResult: [{ required: true, message: "请选择立案结果", trigger: ["blur", "change"] }],
tf_caseFilingType: [{ required: true, message: "请选择立案类型", trigger: ["blur", "change"] }], tf_caseFilingType: [{ required: true, message: "请选择立案类型", trigger: ["blur", "change"] }],
tf_masterUnitId: [{ required: true, message: "请选择主办单位", trigger: "blur" }], tf_masterUnitId: [{ required: true, message: "请选择主办单位", trigger: "blur" }],
approvalOpinion: [{ required: true, message: "请填写审核意见", trigger: "blur" }] tf_opinion: [{ required: true, message: "请填写审核意见", trigger: "blur" }]
}, },
showApprovalForm: false, showApprovalForm: false,
sessionOptions: [], sessionOptions: [],
@@ -250,19 +254,22 @@ layout("/layouts/platform.html"){
return this.isCommitteeDirectorOpinionTask() || (this.isCommitteeTask() && this.formData.tf_caseFilingResult === "CONFIRM_FILING") return this.isCommitteeDirectorOpinionTask() || (this.isCommitteeTask() && this.formData.tf_caseFilingResult === "CONFIRM_FILING")
}, },
openView(row) { openView(row) {
if (this.$root.proposalSubmitting) return
this.$refs.guava.edit(() => { this.$refs.guava.edit(() => {
this.showApprovalForm = false this.$set(this, "showApprovalForm", false)
this.$refs.proposalInfoRef.onOpen(row) this.$refs.proposalInfoRef.onOpen(row)
}) })
}, },
openAudit(row) { openAudit(row) {
if (this.$root.proposalSubmitting) return
this.$refs.guava.edit(() => { this.$refs.guava.edit(() => {
this.showApprovalForm = true this.$set(this, "showApprovalForm", true)
this.$set(this, "formData", { this.$set(this, "formData", {
processTaskId: row.taskId, processTaskId: row.taskId,
taskKey: row.taskKey, taskKey: row.taskKey,
taskName: row.curTaskName, taskName: row.curTaskName,
userId: null, userId: null,
tf_opinion: null,
tf_masterUnitId: null, tf_masterUnitId: null,
tf_slaveUnitIds: [] tf_slaveUnitIds: []
}) })
@@ -272,46 +279,60 @@ layout("/layouts/platform.html"){
}, },
handleTaskAction(val) { handleTaskAction(val) {
if (val === 1 && this.isBranchSchoolLeaderRequired() && !this.formData.userId) { return this.runProposalSubmit("handleTaskAction" + ":" + val, () => {
this.$message.warning("请选择分管校领导") if (val === 1 && this.isBranchSchoolLeaderRequired() && !this.formData.userId) {
return this.$message.warning("请选择分管校领导")
} return
this.$refs.formRef.validate(valid => {
if (valid) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
// 是否有协办单位
let tf_helpunitreply
if (this.isCommitteeTask() && this.formData.tf_slaveUnitIds && this.formData.tf_slaveUnitIds.length > 0) {
tf_helpunitreply = "HAS_HELP_UNIT"
} else {
tf_helpunitreply = "NO_HELP_UNIT"
}
const loading = createLoading("提交中")
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...this.formData,
submitType: val,
tf_masterUnitName: this.formData.tf_masterUnitId ? this.underTakeOptions.find(v => v.id === this.formData.tf_masterUnitId)?.name : null,
tf_slaveUnitNames: this.formData.tf_slaveUnitIds.map(v => this.underTakeOptions.find(v2 => v2.id === v)?.name),
tf_slaveUnitNameStr: this.formData.tf_slaveUnitIds.map(v => this.underTakeOptions.find(v2 => v2.id === v)?.name).join(","),
tf_helpunitreply: tf_helpunitreply
})
}).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
}
}).finally(() => {
loading.close()
})
})
} }
return new Promise((resolve) => {
this.$refs.formRef.validate(resolve)
}).then((valid) => {
if (valid) {
return this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
// 是否有协办单位
let tf_helpunitreply
if (
this.isCommitteeTask() &&
this.formData.tf_slaveUnitIds &&
this.formData.tf_slaveUnitIds.length > 0
) {
tf_helpunitreply = "HAS_HELP_UNIT"
} else {
tf_helpunitreply = "NO_HELP_UNIT"
}
return this.$axios
.post("/flow/common/executeTask", {
data: JSON.stringify({
...this.formData,
submitType: val,
tf_masterUnitName: this.formData.tf_masterUnitId
? this.underTakeOptions.find((v) => v.id === this.formData.tf_masterUnitId)
?.name
: null,
tf_slaveUnitNames: this.formData.tf_slaveUnitIds.map(
(v) => this.underTakeOptions.find((v2) => v2.id === v)?.name
),
tf_slaveUnitNameStr: this.formData.tf_slaveUnitIds
.map((v) => this.underTakeOptions.find((v2) => v2.id === v)?.name)
.join(","),
tf_helpunitreply: tf_helpunitreply
})
})
.then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
}
})
})
}
})
}) })
}, },
@@ -344,6 +365,7 @@ layout("/layouts/platform.html"){
taskKey: selection[0].taskKey, taskKey: selection[0].taskKey,
taskName: selection[0].curTaskName, taskName: selection[0].curTaskName,
userId: null, userId: null,
tf_opinion: null,
tf_masterUnitId: null, tf_masterUnitId: null,
tf_slaveUnitIds: [] tf_slaveUnitIds: []
}) })
@@ -13,7 +13,7 @@ const merge = {
<el-table-column label="代表团" prop="delegationName"></el-table-column> <el-table-column label="代表团" prop="delegationName"></el-table-column>
<el-table-column label="操作" fixed="right" width="100px"> <el-table-column label="操作" fixed="right" width="100px">
<template scope="scope"> <template scope="scope">
<el-button @click="onRemove(scope.$index)" size="mini" type="danger">移除</el-button> <el-button @click="onRemove(scope.$index)" size="mini" type="danger" :disabled="$root.proposalSubmitting">移除</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@@ -22,7 +22,7 @@ const merge = {
<div class="process-title"> <div class="process-title">
{{formData.taskName}} {{formData.taskName}}
</div> </div>
<el-form :model="formData" ref="formRef" label-width="120px" :rules="formRules" label-suffix=""> <el-form :model="formData" ref="formRef" label-width="120px" :rules="formRules" label-suffix="" :disabled="$root.proposalSubmitting">
<el-form-item label="立案结果" prop="tf_caseFilingResult" <el-form-item label="立案结果" prop="tf_caseFilingResult"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]"> :rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-radio-group v-model="formData.tf_caseFilingResult" size="small"> <el-radio-group v-model="formData.tf_caseFilingResult" size="small">
@@ -95,24 +95,27 @@ const merge = {
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="审核意见" prop="approvalOpinion" <!-- 本节点本人填写的审核意见统一提交为 tf_opinion,覆盖流程继承的前序意见。 -->
<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">
<el-button @click="$emit('close')" size="small">取消</el-button> <el-button @click="$emit('close')" size="small" :disabled="$root.proposalSubmitting">取消</el-button>
<el-button @click="handleTaskAction(6)" size="small" type="info">退回到提案人</el-button> <el-button @click="handleTaskAction(6)" size="small" type="info" :loading="formLoading && formAction === ('handleTaskAction:' + 6)" :disabled="$root.proposalSubmitting">退回到提案人</el-button>
<el-button @click="handleTaskAction(1)" size="small" type="primary">提交</el-button> <el-button @click="handleTaskAction(1)" size="small" type="primary" :loading="formLoading && formAction === ('handleTaskAction:' + 1)" :disabled="$root.proposalSubmitting">提交</el-button>
</el-row> </el-row>
</div> </div>
</div> </div>
`, `,
dicts: ["PROPOSAL_CASE_FILING_RESULT", "PROPOSAL_CASE_FILING_TYPE"], dicts: ["PROPOSAL_CASE_FILING_RESULT", "PROPOSAL_CASE_FILING_TYPE"],
mixins: [PROPOSAL_SUBMIT_MIXIN],
data() { data() {
return { return {
selection: [], selection: [],
formData: { formData: {
tf_opinion: null,
tf_masterUnitId: null, tf_masterUnitId: null,
tf_slaveUnitIds: [] tf_slaveUnitIds: []
}, },
@@ -120,7 +123,7 @@ const merge = {
tf_caseFilingResult: [{ required: true, message: "请选择立案结果", trigger: ["blur", "change"] }], tf_caseFilingResult: [{ required: true, message: "请选择立案结果", trigger: ["blur", "change"] }],
tf_caseFilingType: [{ required: true, message: "请选择立案类型", trigger: ["blur", "change"] }], tf_caseFilingType: [{ required: true, message: "请选择立案类型", trigger: ["blur", "change"] }],
tf_masterUnitId: [{ required: true, message: "请选择主办单位", trigger: "blur" }], tf_masterUnitId: [{ required: true, message: "请选择主办单位", trigger: "blur" }],
approvalOpinion: [{ required: true, message: "请填写审核意见", trigger: "blur" }], tf_opinion: [{ required: true, message: "请填写审核意见", trigger: "blur" }],
}, },
underTakeOptions: [], underTakeOptions: [],
branchSchoolLeaderOptions: [], branchSchoolLeaderOptions: [],
@@ -165,43 +168,49 @@ const merge = {
}) })
}, },
handleTaskAction(val) { handleTaskAction(val) {
if (val === 1 && this.isBranchSchoolLeaderRequired() && !this.formData.userId) { return this.runProposalSubmit("handleTaskAction" + ":" + val, () => {
this.$message.warning("请选择分管校领导") if (val === 1 && this.isBranchSchoolLeaderRequired() && !this.formData.userId) {
return this.$message.warning("请选择分管校领导")
} return
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
debugger
// 是否有协办单位
let tf_helpunitreply;
if (this.formData.tf_slaveUnitIds && this.formData.tf_slaveUnitIds.length > 0) {
tf_helpunitreply = 'HAS_HELP_UNIT'
} else {
tf_helpunitreply = 'NO_HELP_UNIT'
} }
return this.$confirm("您确定要提交吗?", "提示", {
const loading = createLoading('提交中') confirmButtonText: "确定",
this.$axios.post("/platform/proposal/committeeFiling/merge", { cancelButtonText: "取消",
data: JSON.stringify({ type: "warning"
...this.formData, }).then(() => {
proposalIds: this.selection.map(v => v.id), debugger
submitType: val, // 是否有协办单位
tf_masterUnitName: this.formData.tf_masterUnitId ? this.underTakeOptions.find(v => v.id === this.formData.tf_masterUnitId)?.name : null, let tf_helpunitreply
tf_slaveUnitNames: this.formData.tf_slaveUnitIds.map(v => this.underTakeOptions.find(v2 => v2.id === v)?.name), if (this.formData.tf_slaveUnitIds && this.formData.tf_slaveUnitIds.length > 0) {
tf_slaveUnitNameStr: this.formData.tf_slaveUnitIds.map(v => this.underTakeOptions.find(v2 => v2.id === v)?.name).join(','), tf_helpunitreply = "HAS_HELP_UNIT"
tf_helpunitreply: tf_helpunitreply } else {
}) tf_helpunitreply = "NO_HELP_UNIT"
}).then((res) => {
if (res.code === 0) {
this.$emit('close')
this.$message.success(res.msg)
this.doSearch()
} }
}).finally(() => {
loading.close() return this.$axios
.post("/platform/proposal/committeeFiling/merge", {
data: JSON.stringify({
...this.formData,
proposalIds: this.selection.map((v) => v.id),
submitType: val,
tf_masterUnitName: this.formData.tf_masterUnitId
? this.underTakeOptions.find((v) => v.id === this.formData.tf_masterUnitId)?.name
: null,
tf_slaveUnitNames: this.formData.tf_slaveUnitIds.map(
(v) => this.underTakeOptions.find((v2) => v2.id === v)?.name
),
tf_slaveUnitNameStr: this.formData.tf_slaveUnitIds
.map((v) => this.underTakeOptions.find((v2) => v2.id === v)?.name)
.join(","),
tf_helpunitreply: tf_helpunitreply
})
})
.then((res) => {
if (res.code === 0) {
this.$emit("close")
this.$message.success(res.msg)
}
})
}) })
}) })
} }
@@ -56,10 +56,10 @@ layout("/layouts/platform.html"){
</el-table-column> </el-table-column>
<el-table-column label="操作" fixed="right" width="300px"> <el-table-column label="操作" fixed="right" width="300px">
<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" :disabled="$root.proposalSubmitting">查看</el-button>
<el-button v-if="row.taskState === 10" @click="openAudit(row)" size="mini" type="primary">审核 <el-button v-if="row.taskState === 10" @click="openAudit(row)" size="mini" type="primary" :disabled="$root.proposalSubmitting">审核
</el-button> </el-button>
<el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">撤回 <el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger" :disabled="$root.proposalSubmitting">撤回
</el-button> </el-button>
</template> </template>
</el-table-column> </el-table-column>
@@ -74,17 +74,17 @@ layout("/layouts/platform.html"){
{{formData.taskName}} {{formData.taskName}}
</div> </div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=":" <el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=":"
class="flow-task-form"> class="flow-task-form" :disabled="$root.proposalSubmitting">
<el-form-item label="审批意见" prop="tf_opinion" <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.tf_opinion"></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">
<el-button @click="$refs.guava.index()" size="small">取消</el-button> <el-button @click="$refs.guava.index()" size="small" :disabled="$root.proposalSubmitting">取消</el-button>
<el-button @click="handleTaskAction(6)" size="small" type="info">退回到提案人</el-button> <el-button @click="handleTaskAction(6)" size="small" type="info" :loading="formLoading && formAction === ('handleTaskAction:' + 6)" :disabled="$root.proposalSubmitting">退回到提案人</el-button>
<el-button @click="handleTaskAction(2)" size="small" type="danger">不同意</el-button> <el-button @click="handleTaskAction(2)" size="small" type="danger" :loading="formLoading && formAction === ('handleTaskAction:' + 2)" :disabled="$root.proposalSubmitting">不同意</el-button>
<el-button @click="handleTaskAction(1)" size="small" type="primary">同意</el-button> <el-button @click="handleTaskAction(1)" size="small" type="primary" :loading="formLoading && formAction === ('handleTaskAction:' + 1)" :disabled="$root.proposalSubmitting">同意</el-button>
</el-row> </el-row>
</div> </div>
</proposal-info> </proposal-info>
@@ -93,12 +93,14 @@ layout("/layouts/platform.html"){
</div> </div>
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
<!--#include("/platform/zhgh/democratic/proposal/common/submit.js"){}#-->
<!--#include('../../common/info.js'){}#--> <!--#include('../../common/info.js'){}#-->
new Vue({ new Vue({
el: "#app", el: "#app",
store, store,
mixins: [initTableMixins], mixins: [initTableMixins, PROPOSAL_SUBMIT_MIXIN],
components: { components: {
"proposal-info": PROPOSAL_INFO "proposal-info": PROPOSAL_INFO
}, },
@@ -121,14 +123,16 @@ layout("/layouts/platform.html"){
}, },
methods: { methods: {
openView(row) { openView(row) {
if (this.$root.proposalSubmitting) return
this.$refs.guava.edit(() => { this.$refs.guava.edit(() => {
this.showApprovalForm = false this.$set(this, "showApprovalForm", false)
this.$refs.proposalInfoRef.onOpen(row) this.$refs.proposalInfoRef.onOpen(row)
}) })
}, },
openAudit(row) { openAudit(row) {
if (this.$root.proposalSubmitting) return
this.$refs.guava.edit(() => { this.$refs.guava.edit(() => {
this.showApprovalForm = true this.$set(this, "showApprovalForm", true)
this.formData = { this.formData = {
processTaskId: row.taskId, processTaskId: row.taskId,
taskName: row.curTaskName taskName: row.curTaskName
@@ -138,24 +142,30 @@ layout("/layouts/platform.html"){
}, },
handleTaskAction(val) { handleTaskAction(val) {
this.$refs.formRef.validate(valid => { return this.runProposalSubmit("handleTaskAction" + ":" + val, () => {
if (!valid) return return new Promise((resolve) => {
this.$confirm("您确定要提交吗?", "提示", { this.$refs.formRef.validate(resolve)
confirmButtonText: "确定", }).then((valid) => {
cancelButtonText: "取消", if (!valid) return
type: "warning" return this.$confirm("您确定要提交吗?", "提示", {
}).then(() => { confirmButtonText: "确定",
this.$axios.post("/flow/common/executeTask", { cancelButtonText: "取消",
data: JSON.stringify({ type: "warning"
...this.formData, }).then(() => {
submitType: val return this.$axios
}) .post("/flow/common/executeTask", {
}).then((res) => { data: JSON.stringify({
if (res.code === 0) { ...this.formData,
this.$refs.guava.index() submitType: val
this.$message.success(res.msg) })
this.doSearch() })
} .then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
}
})
}) })
}) })
}) })
@@ -62,10 +62,10 @@ layout("/layouts/platform.html"){
</el-table-column> </el-table-column>
<el-table-column label="操作" fixed="right" width="300px"> <el-table-column label="操作" fixed="right" width="300px">
<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" :disabled="$root.proposalSubmitting">查看</el-button>
<el-button v-if="row.taskState === 10" @click="openAudit(row)" size="mini" type="primary">评价 <el-button v-if="row.taskState === 10" @click="openAudit(row)" size="mini" type="primary" :disabled="$root.proposalSubmitting">评价
</el-button> </el-button>
<el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">撤回 <el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger" :disabled="$root.proposalSubmitting">撤回
</el-button> </el-button>
</template> </template>
</el-table-column> </el-table-column>
@@ -79,7 +79,7 @@ layout("/layouts/platform.html"){
<div class="process-title"> <div class="process-title">
{{formData.taskName}} {{formData.taskName}}
</div> </div>
<el-form :model="formData" ref="formRef" label-width="120px" :rules="formRules" label-suffix=""> <el-form :model="formData" ref="formRef" label-width="120px" :rules="formRules" label-suffix="" :disabled="$root.proposalSubmitting">
<el-form-item label="满意度" prop="tf_feedback" <el-form-item label="满意度" prop="tf_feedback"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]"> :rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-radio-group v-model="formData.tf_feedback" size="small"> <el-radio-group v-model="formData.tf_feedback" size="small">
@@ -94,8 +94,8 @@ layout("/layouts/platform.html"){
</el-form-item> </el-form-item>
</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" :disabled="$root.proposalSubmitting">取消</el-button>
<el-button @click="handleTaskAction(1)" size="small" type="primary">提交</el-button> <el-button @click="handleTaskAction(1)" size="small" type="primary" :loading="formLoading && formAction === ('handleTaskAction:' + 1)" :disabled="$root.proposalSubmitting">提交</el-button>
</el-row> </el-row>
</div> </div>
</proposal-info> </proposal-info>
@@ -104,13 +104,15 @@ layout("/layouts/platform.html"){
</div> </div>
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
<!--#include("/platform/zhgh/democratic/proposal/common/submit.js"){}#-->
<!--#include('../../common/info.js'){}#--> <!--#include('../../common/info.js'){}#-->
new Vue({ new Vue({
el: "#app", el: "#app",
store, store,
dicts: ["PROPOSAL_FEEDBACK"], dicts: ["PROPOSAL_FEEDBACK"],
mixins: [initTableMixins], mixins: [initTableMixins, PROPOSAL_SUBMIT_MIXIN],
components: { components: {
"proposal-info": PROPOSAL_INFO "proposal-info": PROPOSAL_INFO
}, },
@@ -135,14 +137,16 @@ layout("/layouts/platform.html"){
}, },
methods: { methods: {
openView(row) { openView(row) {
if (this.$root.proposalSubmitting) return
this.$refs.guava.edit(() => { this.$refs.guava.edit(() => {
this.showApprovalForm = false this.$set(this, "showApprovalForm", false)
this.$refs.proposalInfoRef.onOpen(row) this.$refs.proposalInfoRef.onOpen(row)
}) })
}, },
openAudit(row) { openAudit(row) {
if (this.$root.proposalSubmitting) return
this.$refs.guava.edit(() => { this.$refs.guava.edit(() => {
this.showApprovalForm = true this.$set(this, "showApprovalForm", true)
this.formData = { this.formData = {
processTaskId: row.taskId, processTaskId: row.taskId,
taskKey: row.taskKey, taskKey: row.taskKey,
@@ -154,28 +158,35 @@ layout("/layouts/platform.html"){
}, },
handleTaskAction(val) { handleTaskAction(val) {
this.$confirm("您确定要提交吗?", "提示", { return this.runProposalSubmit("handleTaskAction" + ":" + val, () => {
confirmButtonText: "确定", return this.$confirm("您确定要提交吗?", "提示", {
cancelButtonText: "取消", confirmButtonText: "确定",
type: "warning" cancelButtonText: "取消",
}).then(async () => { type: "warning"
const formData = { }).then(() => {
...this.formData, const formData = {
submitType: val ...this.formData,
} submitType: val
// 不满意
if (this.formData.tf_feedback === 'DISSATISFIED') {
const caseInfo = await this.getCaseInfo(this.formData.instanceId)
formData.tf_masterUnitId = caseInfo.tf_masterUnitId
}
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify(formData)
}).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
} }
const lookup =
this.formData.tf_feedback === "DISSATISFIED"
? this.getCaseInfo(this.formData.instanceId).then((caseInfo) => {
formData.tf_masterUnitId = caseInfo.tf_masterUnitId
})
: Promise.resolve()
return lookup.then(() => {
return this.$axios
.post("/flow/common/executeTask", {
data: JSON.stringify(formData)
})
.then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
}
})
})
}) })
}) })
}, },
@@ -197,14 +208,8 @@ layout("/layouts/platform.html"){
}, },
// 获取立案信息 // 获取立案信息
async getCaseInfo(instId) { getCaseInfo(instId) {
const { return this.$axios.post("/platform/proposal/feedbackEvaluation/caseInfo", { instId }).then((res) => res.data)
data,
code
} = await this.$axios.post('/platform/proposal/feedbackEvaluation/caseInfo', {instId})
if (code === 0) {
return data
}
}, },
// 教代会 // 教代会
@@ -43,14 +43,18 @@
</el-table> </el-table>
<!--#include("/layouts/pagination.html"){}#--> <!--#include("/layouts/pagination.html"){}#-->
</div> </div>
<snaker-flow-task-form-action @task-action="handleTaskAction"></snaker-flow-task-form-action> <div v-loading="formLoading" element-loading-text="提交中…">
<snaker-flow-task-form-action @task-action="handleTaskAction"></snaker-flow-task-form-action>
</div>
</div> </div>
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
<!--#include("/platform/zhgh/democratic/proposal/common/submit.js"){}#-->
new Vue({ new Vue({
el: "#proposal-transact-apply-form", el: "#proposal-transact-apply-form",
store, store,
mixins: [initTableMixins], mixins: [initTableMixins, PROPOSAL_SUBMIT_MIXIN],
data() { data() {
return { return {
businessId: GetQueryString("businessId"), businessId: GetQueryString("businessId"),
@@ -104,42 +108,44 @@
handleTaskAction(val) { handleTaskAction(val) {
console.log(val) console.log(val)
this.invite(val) return this.invite(val)
}, },
// 邀请 // 邀请
invite(val) { invite(val) {
const selection = this.$refs.tableRef.selection return this.runProposalSubmit("invite", () => {
if (selection.length === 0) { const selection = this.$refs.tableRef.selection
this.$message.warning("请先选择附议人后再提交") if (selection.length === 0) {
return this.$message.warning("请先选择附议人后再提交")
} return
const loginNames = selection.map((s) => s.loginName) }
const userName = selection.map((s) => s.userName) const loginNames = selection.map((s) => s.loginName)
this.$confirm("您确定要邀请" + userName.join("、") + "代表附议吗?", "提示", { const userName = selection.map((s) => s.userName)
confirmButtonText: "确定", return this.$confirm("您确定要邀请" + userName.join("、") + "代表附议吗?", "提示", {
cancelButtonText: "取消", confirmButtonText: "确定",
type: "info" cancelButtonText: "取消",
}).then(() => { type: "info"
this.$axios }).then(() => {
.post("/flow/common/executeTask", { return this.$axios
data: JSON.stringify({ .post("/flow/common/executeTask", {
...val, data: JSON.stringify({
tf_nextNodeOperator: selection.map((s) => s.userId), ...val,
tf_proposalId: this.businessId, tf_nextNodeOperator: selection.map((s) => s.userId),
tf_seconders: JSON.stringify(selection) tf_proposalId: this.businessId,
}) tf_seconders: JSON.stringify(selection)
})
.then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
// 发送完成消息
window.GlobalBroadcastChannel.postMessage({
type: "task-complete",
payload: val
}) })
} })
}) .then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
// 发送完成消息
window.GlobalBroadcastChannel.postMessage({
type: "task-complete",
payload: val
})
}
})
})
}) })
} }
}, },
@@ -87,13 +87,15 @@ layout("/layouts/platform.html"){
</div> </div>
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
<!--#include("/platform/zhgh/democratic/proposal/common/submit.js"){}#-->
<!--#include("../../common/info.js"){}#--> <!--#include("../../common/info.js"){}#-->
<!--#include("inviteSeconder.js"){}#--> <!--#include("inviteSeconder.js"){}#-->
new Vue({ new Vue({
el: "#app", el: "#app",
store, store,
mixins: [initTableMixins], mixins: [initTableMixins, PROPOSAL_SUBMIT_MIXIN],
components: { components: {
"proposal-info": PROPOSAL_INFO, "proposal-info": PROPOSAL_INFO,
"invite-seconder": PROPOSAL_INVITE_SECONDER_COMPONENT "invite-seconder": PROPOSAL_INVITE_SECONDER_COMPONENT
@@ -21,7 +21,7 @@ const PROPOSAL_INVITE_SECONDER_COMPONENT = {
<el-divider class="mt10 mb10"></el-divider> <el-divider class="mt10 mb10"></el-divider>
<div> <div>
<table-tool label="代表数据"> <table-tool label="代表数据">
<!-- <el-button size="small" @click="invite" type="primary" icon="el-icon-plus"--> <!-- <el-button size="small" @click="invite" type="primary" icon="el-icon-plus"-- :loading="formLoading && formAction === ('invite')">
<!-- :disabled="pageForm.isInvite">邀请--> <!-- :disabled="pageForm.isInvite">邀请-->
<!-- </el-button>--> <!-- </el-button>-->
<el-radio-group v-model="pageForm.isInvite" @change="doSearch" size="small" <el-radio-group v-model="pageForm.isInvite" @change="doSearch" size="small"
@@ -44,7 +44,7 @@ const PROPOSAL_INVITE_SECONDER_COMPONENT = {
<el-table-column label="代表团" prop="delegationName"></el-table-column> <el-table-column label="代表团" prop="delegationName"></el-table-column>
<!-- <el-table-column label="操作" width="150px">--> <!-- <el-table-column label="操作" width="150px">-->
<!-- <template scope="{row}">--> <!-- <template scope="{row}">-->
<!-- <el-button size="mini" type="primary" @click="invite(row)">邀请</el-button>--> <!-- <el-button size="mini" type="primary" @click="invite(row)" :loading="formLoading && formAction === ('invite')">邀请</el-button>-->
<!-- </template>--> <!-- </template>-->
<!-- </el-table-column>--> <!-- </el-table-column>-->
</el-table> </el-table>
@@ -68,15 +68,15 @@ const PROPOSAL_INVITE_SECONDER_COMPONENT = {
</el-table> </el-table>
<el-row type="flex" justify="center" class="p10"> <el-row type="flex" justify="center" class="p10">
<el-button @click="">取消</el-button> <el-button @click="" :disabled="$root.proposalSubmitting">取消</el-button>
<el-button @click="invite" type="primary">邀请</el-button> <el-button @click="invite" type="primary" :loading="formLoading && formAction === ('invite')" :disabled="$root.proposalSubmitting">邀请</el-button>
</el-row> </el-row>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
`, `,
mixins: [initTableMixins], mixins: [initTableMixins, PROPOSAL_SUBMIT_MIXIN],
data() { data() {
return { return {
visible: false, visible: false,
@@ -123,32 +123,35 @@ const PROPOSAL_INVITE_SECONDER_COMPONENT = {
detail(id) { detail(id) {
}, },
invite() { invite() {
const selection = this.$refs.tableRef.selection return this.runProposalSubmit("invite", () => {
if (selection.length === 0) { const selection = this.$refs.tableRef.selection
this.$message.warning("请先选择附议人后再邀请") if (selection.length === 0) {
return this.$message.warning("请先选择附议人后再邀请")
} return
}
const loginNames = selection.map((s) => s.loginName) const loginNames = selection.map((s) => s.loginName)
const userName = selection.map((s) => s.userName) const userName = selection.map((s) => s.userName)
this.$confirm("您确定要邀请" + userName.join("、") + "代表附议吗?", "提示", { return this.$confirm("您确定要邀请" + userName.join("、") + "代表附议吗?", "提示", {
confirmButtonText: "确定", confirmButtonText: "确定",
cancelButtonText: "取消", cancelButtonText: "取消",
type: "info" type: "info"
}).then(() => { }).then(() => {
const loading = createLoading('邀请中...') return this.$axios
this.$axios.post("/platform/proposal/mine/inviteSeconder", { .post("/platform/proposal/mine/inviteSeconder", {
proposalId: this.record.id, proposalId: this.record.id,
seconders: JSON.stringify(loginNames) seconders: JSON.stringify(loginNames)
}).then((res) => { })
if (res.code === 0) { .then((res) => {
this.$message.success(res.msg) if (res.code === 0) {
this.$refs.tableRef.clearSelection() this.$message.success(res.msg)
this.pageData() this.$refs.tableRef.clearSelection()
this.visible = false this.pageData()
this.$emit("refresh", null) this.$set(this, "visible", false)
} this.$emit("refresh", null)
}).finally(() => loading.close()) }
})
})
}) })
}, },
pageData() { pageData() {
@@ -63,8 +63,8 @@ layout("/layouts/platform.html"){
</el-table-column> </el-table-column>
<el-table-column label="操作" fixed="right" width="300px"> <el-table-column label="操作" fixed="right" width="300px">
<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" :disabled="$root.proposalSubmitting">查看</el-button>
<el-button v-if="row.count === 0" @click="openAudit(row)" size="mini" type="primary">附议</el-button> <el-button v-if="row.count === 0" @click="openAudit(row)" size="mini" type="primary" :disabled="$root.proposalSubmitting">附议</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@@ -76,16 +76,16 @@ layout("/layouts/platform.html"){
<div v-if="showApprovalForm"> <div v-if="showApprovalForm">
<div class="process-title">主动附议</div> <div class="process-title">主动附议</div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=":" <el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=":"
class="flow-task-form"> class="flow-task-form" :disabled="$root.proposalSubmitting">
<el-form-item label="审批意见" prop="tf_opinion" <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.tf_opinion"></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">
<el-button @click="$refs.guava.index()" size="small">取消</el-button> <el-button @click="$refs.guava.index()" size="small" :disabled="$root.proposalSubmitting">取消</el-button>
<el-button @click="handleTaskAction(20)" size="small" type="danger">不同意</el-button> <el-button @click="handleTaskAction(20)" size="small" type="danger" :loading="formLoading && formAction === ('handleTaskAction:' + 20)" :disabled="$root.proposalSubmitting">不同意</el-button>
<el-button @click="handleTaskAction(1)" size="small" type="primary">同意</el-button> <el-button @click="handleTaskAction(1)" size="small" type="primary" :loading="formLoading && formAction === ('handleTaskAction:' + 1)" :disabled="$root.proposalSubmitting">同意</el-button>
</el-row> </el-row>
</div> </div>
</proposal-info> </proposal-info>
@@ -94,12 +94,14 @@ layout("/layouts/platform.html"){
</div> </div>
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
<!--#include("/platform/zhgh/democratic/proposal/common/submit.js"){}#-->
<!--#include('../../common/info.js'){}#--> <!--#include('../../common/info.js'){}#-->
new Vue({ new Vue({
el: "#app", el: "#app",
store, store,
mixins: [initTableMixins], mixins: [initTableMixins, PROPOSAL_SUBMIT_MIXIN],
components: { components: {
"proposal-info": PROPOSAL_INFO "proposal-info": PROPOSAL_INFO
}, },
@@ -125,19 +127,21 @@ layout("/layouts/platform.html"){
}, },
methods: { methods: {
openView(row) { openView(row) {
if (this.$root.proposalSubmitting) return
this.$refs.guava.edit(() => { this.$refs.guava.edit(() => {
this.showApprovalForm = false this.$set(this, "showApprovalForm", false)
this.$refs.proposalInfoRef.onOpen(row) this.$refs.proposalInfoRef.onOpen(row)
}) })
}, },
async openAudit(row) { async openAudit(row) {
const validatePass = await this.validateTime(); if (this.$root.proposalSubmitting) return
const validatePass = await this.validateTime()
if (!validatePass) { if (!validatePass) {
return; return
} }
this.row = row this.$set(this, "row", row)
this.$refs.guava.edit(() => { this.$refs.guava.edit(() => {
this.showApprovalForm = true this.$set(this, "showApprovalForm", true)
this.formData = { this.formData = {
processTaskId: row.taskId, processTaskId: row.taskId,
taskName: row.curTaskName, taskName: row.curTaskName,
@@ -160,23 +164,29 @@ layout("/layouts/platform.html"){
}, },
handleTaskAction(val) { handleTaskAction(val) {
this.$refs.formRef.validate(valid => { return this.runProposalSubmit("handleTaskAction" + ":" + val, () => {
if (!valid) return return new Promise((resolve) => {
this.$confirm("您确定要提交吗?", "提示", { this.$refs.formRef.validate(resolve)
confirmButtonText: "确定", }).then((valid) => {
cancelButtonText: "取消", if (!valid) return
type: "warning" return this.$confirm("您确定要提交吗?", "提示", {
}).then(() => { confirmButtonText: "确定",
this.$axios.post("/platform/proposal/positiveSeconded/handle", { cancelButtonText: "取消",
proposalId: this.row.id, type: "warning"
opinion: this.formData.tf_opinion, }).then(() => {
submitType: val, return this.$axios
}).then((res) => { .post("/platform/proposal/positiveSeconded/handle", {
if (res.code === 0) { proposalId: this.row.id,
this.$refs.guava.index() opinion: this.formData.tf_opinion,
this.$message.success(res.msg) submitType: val
this.doSearch() })
} .then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
}
})
}) })
}) })
}) })
@@ -83,10 +83,10 @@ layout("/layouts/platform.html"){
</el-table-column> </el-table-column>
<el-table-column label="操作" fixed="right" width="300px"> <el-table-column label="操作" fixed="right" width="300px">
<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" :disabled="$root.proposalSubmitting">查看</el-button>
<el-button v-if="row.taskState === 10" @click="openAudit(row)" size="mini" type="primary">审核 <el-button v-if="row.taskState === 10" @click="openAudit(row)" size="mini" type="primary" :disabled="$root.proposalSubmitting">审核
</el-button> </el-button>
<el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">撤回 <el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger" :disabled="$root.proposalSubmitting">撤回
</el-button> </el-button>
</template> </template>
</el-table-column> </el-table-column>
@@ -100,17 +100,17 @@ layout("/layouts/platform.html"){
<div class="process-title"> <div class="process-title">
{{formData.taskName}} {{formData.taskName}}
</div> </div>
<el-form :model="formData" ref="formRef" label-width="120px" :rules="formRules" label-suffix=""> <el-form :model="formData" ref="formRef" label-width="120px" :rules="formRules" label-suffix="" :disabled="$root.proposalSubmitting">
<el-form-item label="审批意见" prop="tf_opinion" <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.tf_opinion"></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">
<el-button @click="$refs.guava.index()" size="small">取消</el-button> <el-button @click="$refs.guava.index()" size="small" :disabled="$root.proposalSubmitting">取消</el-button>
<el-button v-if="isSchoolLeaderTask()" @click="handleTaskAction('back')" :loading="submitLoading" size="small" type="danger">退回重新答复 <el-button v-if="isSchoolLeaderTask()" @click="handleTaskAction('back')" size="small" type="danger" :loading="formLoading && formAction === ('handleTaskAction:' + 'back')" :disabled="$root.proposalSubmitting">退回重新答复
</el-button> </el-button>
<el-button @click="handleTaskAction('agree')" :loading="submitLoading" size="small" type="primary">{{submitButtonText()}}</el-button> <el-button @click="handleTaskAction('agree')" size="small" type="primary" :loading="formLoading && formAction === ('handleTaskAction:' + 'agree')" :disabled="$root.proposalSubmitting">{{submitButtonText()}}</el-button>
</el-row> </el-row>
</div> </div>
</proposal-info> </proposal-info>
@@ -119,13 +119,15 @@ layout("/layouts/platform.html"){
</div> </div>
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
<!--#include("/platform/zhgh/democratic/proposal/common/submit.js"){}#-->
<!--#include('../../common/info.js'){}#--> <!--#include('../../common/info.js'){}#-->
new Vue({ new Vue({
el: "#app", el: "#app",
store, store,
dicts: ["PROPOSAL_CASE_FILING_RESULT"], dicts: ["PROPOSAL_CASE_FILING_RESULT"],
mixins: [initTableMixins], mixins: [initTableMixins, PROPOSAL_SUBMIT_MIXIN],
components: { components: {
"proposal-info": PROPOSAL_INFO "proposal-info": PROPOSAL_INFO
}, },
@@ -145,7 +147,7 @@ layout("/layouts/platform.html"){
}, },
formData: {}, formData: {},
showApprovalForm: false, showApprovalForm: false,
submitLoading: false,
sessionOptions: [], sessionOptions: [],
delegationOptions: [], delegationOptions: [],
} }
@@ -161,12 +163,14 @@ layout("/layouts/platform.html"){
return this.isInstructionTask() ? "提交批示" : "同意答复" return this.isInstructionTask() ? "提交批示" : "同意答复"
}, },
openView(row) { openView(row) {
if (this.$root.proposalSubmitting) return
this.$refs.guava.edit(() => { this.$refs.guava.edit(() => {
this.$set(this, "showApprovalForm", false) this.$set(this, "showApprovalForm", false)
this.$refs.proposalInfoRef.onOpen(row) this.$refs.proposalInfoRef.onOpen(row)
}) })
}, },
openAudit(row) { openAudit(row) {
if (this.$root.proposalSubmitting) return
this.$refs.guava.edit(() => { this.$refs.guava.edit(() => {
this.$set(this, "showApprovalForm", true) this.$set(this, "showApprovalForm", true)
this.$set(this, "formData", { this.$set(this, "formData", {
@@ -180,35 +184,35 @@ layout("/layouts/platform.html"){
}, },
handleTaskAction(val) { handleTaskAction(val) {
if (this.submitLoading) { return this.runProposalSubmit("handleTaskAction" + ":" + val, () => {
return return new Promise((resolve) => {
} this.$refs.formRef.validate(resolve)
this.$refs.formRef.validate(valid => { }).then((valid) => {
if (!valid) return if (!valid) return
this.$confirm("您确定要提交吗?", "提示", { return this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定", confirmButtonText: "确定",
cancelButtonText: "取消", cancelButtonText: "取消",
type: "warning" type: "warning"
}).then(() => { }).then(() => {
const formData = { const formData = {
...this.formData, ...this.formData,
tf_approval: val tf_approval: val
}
delete formData.taskKey
delete formData.taskName
this.$set(this, "submitLoading", true)
this.$axios.post("/platform/proposal/schoolLeaderApproval/executeTask", {
data: JSON.stringify(formData)
}).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
} }
}).finally(() => { delete formData.taskKey
this.$set(this, "submitLoading", false) delete formData.taskName
return this.$axios
.post("/platform/proposal/schoolLeaderApproval/executeTask", {
data: JSON.stringify(formData)
})
.then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
}
})
}) })
}) })
}) })
@@ -78,8 +78,8 @@ layout("/layouts/platform.html"){
</el-table-column> </el-table-column>
<el-table-column label="操作" fixed="right" width="300px"> <el-table-column label="操作" fixed="right" width="300px">
<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" :disabled="$root.proposalSubmitting">查看</el-button>
<el-button v-if="showAuditButton(row)" @click="openAudit(row)" size="mini" type="primary">附议</el-button> <el-button v-if="showAuditButton(row)" @click="openAudit(row)" size="mini" type="primary" :disabled="$root.proposalSubmitting">附议</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@@ -93,16 +93,16 @@ layout("/layouts/platform.html"){
{{approvalTitle}} {{approvalTitle}}
</div> </div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=":" <el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=":"
class="flow-task-form"> class="flow-task-form" :disabled="$root.proposalSubmitting">
<el-form-item label="审批意见" prop="tf_opinion" <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.tf_opinion"></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">
<el-button @click="$refs.guava.index()" size="small">取消</el-button> <el-button @click="$refs.guava.index()" size="small" :disabled="$root.proposalSubmitting">取消</el-button>
<el-button @click="handleTaskAction(20)" size="small" type="danger">不同意</el-button> <el-button @click="handleTaskAction(20)" size="small" type="danger" :loading="formLoading && formAction === ('handleTaskAction:' + 20)" :disabled="$root.proposalSubmitting">不同意</el-button>
<el-button @click="handleTaskAction(1)" size="small" type="primary">同意</el-button> <el-button @click="handleTaskAction(1)" size="small" type="primary" :loading="formLoading && formAction === ('handleTaskAction:' + 1)" :disabled="$root.proposalSubmitting">同意</el-button>
</el-row> </el-row>
</div> </div>
</proposal-info> </proposal-info>
@@ -111,12 +111,14 @@ layout("/layouts/platform.html"){
</div> </div>
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
<!--#include("/platform/zhgh/democratic/proposal/common/submit.js"){}#-->
<!--#include('../../common/info.js'){}#--> <!--#include('../../common/info.js'){}#-->
new Vue({ new Vue({
el: "#app", el: "#app",
store, store,
mixins: [initTableMixins], mixins: [initTableMixins, PROPOSAL_SUBMIT_MIXIN],
components: { components: {
"proposal-info": PROPOSAL_INFO "proposal-info": PROPOSAL_INFO
}, },
@@ -249,7 +251,8 @@ layout("/layouts/platform.html"){
return row.count === 0 return row.count === 0
}, },
openView: function (row) { openView(row) {
if (this.$root.proposalSubmitting) return
this.$refs.guava.edit(() => { this.$refs.guava.edit(() => {
this.$set(this, "showApprovalForm", false) this.$set(this, "showApprovalForm", false)
this.$refs.proposalInfoRef.onOpen(row) this.$refs.proposalInfoRef.onOpen(row)
@@ -285,42 +288,52 @@ layout("/layouts/platform.html"){
}) })
}, },
handleTaskAction: function (val) { handleTaskAction(val) {
this.$refs.formRef.validate((valid) => { return this.runProposalSubmit("handleTaskAction" + ":" + val, () => {
if (!valid) return return new Promise((resolve) => {
this.$confirm("您确定要提交吗?", "提示", { this.$refs.formRef.validate(resolve)
confirmButtonText: "确定", }).then((valid) => {
cancelButtonText: "取消", if (!valid) return
type: "warning" return this.$confirm("您确定要提交吗?", "提示", {
}).then(() => { confirmButtonText: "确定",
if (this.activeTab === "inviteSeconded") { cancelButtonText: "取消",
this.handleInviteSeconded(val) type: "warning"
} else { }).then(() => {
this.handlePositiveSeconded(val) if (this.activeTab === "inviteSeconded") {
} return this.handleInviteSeconded(val)
} else {
return this.handlePositiveSeconded(val)
}
})
}) })
}) })
}, },
// 受邀附议需要先执行流程任务,再同步附议结果。 // 受邀附议需要先执行流程任务,再同步附议结果。
handleInviteSeconded: function (val) { handleInviteSeconded(val) {
this.$axios.post("/flow/common/executeTask", { return this.$axios
data: JSON.stringify({ .post("/flow/common/executeTask", {
...this.formData, data: JSON.stringify({ ...this.formData, submitType: val })
submitType: val })
.then((res) => {
// WF 已办理后只回写附议结果;第二步失败不得再次执行已完成的 WF 任务。
return this.updateInviteSeconded(val)
.then(() => {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
})
.catch((error) => {
this.$refs.guava.index()
this.$message.error("流程已办理,但附议结果同步失败,请刷新核对,勿重复提交")
this.doSearch()
throw error
})
}) })
}).then((res) => {
if (res.code === 0) {
this.updateInviteSeconded(val)
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
}
})
}, },
updateInviteSeconded: function (submitType) { updateInviteSeconded(submitType) {
this.$axios.post("/platform/proposal/seconded/updateInfo", { return this.$axios.post("/platform/proposal/seconded/updateInfo", {
proposalId: this.row.id, proposalId: this.row.id,
taskActorUserId: this.row.taskActorUserId, taskActorUserId: this.row.taskActorUserId,
opinion: this.formData.tf_opinion, opinion: this.formData.tf_opinion,
@@ -329,18 +342,20 @@ layout("/layouts/platform.html"){
}, },
// 主动附议走独立业务接口处理。 // 主动附议走独立业务接口处理。
handlePositiveSeconded: function (val) { handlePositiveSeconded(val) {
this.$axios.post("/platform/proposal/positiveSeconded/handle", { return this.$axios
proposalId: this.row.id, .post("/platform/proposal/positiveSeconded/handle", {
opinion: this.formData.tf_opinion, proposalId: this.row.id,
submitType: val opinion: this.formData.tf_opinion,
}).then((res) => { submitType: val
if (res.code === 0) { })
this.$refs.guava.index() .then((res) => {
this.$message.success(res.msg) if (res.code === 0) {
this.doSearch() this.$refs.guava.index()
} this.$message.success(res.msg)
}) this.doSearch()
}
})
}, },
validatePositiveTime: function () { validatePositiveTime: function () {
@@ -131,8 +131,8 @@ layout("/layouts/platform.html"){
</el-table-column> </el-table-column>
<el-table-column label="操作" fixed="right" min-width="160px"> <el-table-column label="操作" fixed="right" min-width="160px">
<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" :disabled="$root.proposalSubmitting">查看</el-button>
<el-button @click="openAudit(row)" size="mini" type="primary">反馈意见</el-button> <el-button @click="openAudit(row)" size="mini" type="primary" :disabled="$root.proposalSubmitting">反馈意见</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@@ -145,7 +145,7 @@ layout("/layouts/platform.html"){
<div class="process-title"> <div class="process-title">
承办单位意见 承办单位意见
</div> </div>
<el-form :model="formData" ref="formRef" label-width="80px" :rules="formRules" label-suffix=""> <el-form :model="formData" ref="formRef" label-width="80px" :rules="formRules" label-suffix="" :disabled="$root.proposalSubmitting">
<el-form-item label="承办意向" prop="result" <el-form-item label="承办意向" prop="result"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]"> :rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-radio-group v-model="formData.result" size="small"> <el-radio-group v-model="formData.result" size="small">
@@ -160,8 +160,8 @@ layout("/layouts/platform.html"){
</el-form-item> </el-form-item>
</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" :disabled="$root.proposalSubmitting">取消</el-button>
<el-button @click="onAudit()" size="small" type="primary">提交</el-button> <el-button @click="onAudit()" size="small" type="primary" :loading="formLoading && formAction === ('onAudit')" :disabled="$root.proposalSubmitting">提交</el-button>
</el-row> </el-row>
</div> </div>
</proposal-info> </proposal-info>
@@ -172,7 +172,7 @@ layout("/layouts/platform.html"){
<div style="display: flex; justify-content: space-between; align-items: center"> <div style="display: flex; justify-content: space-between; align-items: center">
<div class="left-span-label">意见{{ index + 1 }}</div> <div class="left-span-label">意见{{ index + 1 }}</div>
<div> <div>
<el-button @click="onDelete(item)" size="mini" type="danger">删除</el-button> <el-button @click="onDelete(item)" size="mini" type="danger" :disabled="$root.proposalSubmitting">删除</el-button>
</div> </div>
</div> </div>
<el-descriptions :column="2" border> <el-descriptions :column="2" border>
@@ -191,12 +191,14 @@ layout("/layouts/platform.html"){
</div> </div>
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
<!--#include("/platform/zhgh/democratic/proposal/common/submit.js"){}#-->
<!--#include('../../common/info.js'){}#--> <!--#include('../../common/info.js'){}#-->
new Vue({ new Vue({
el: "#app", el: "#app",
store, store,
dicts: ["UNDERTAKE_SUGGESTION"], dicts: ["UNDERTAKE_SUGGESTION"],
mixins: [initTableMixins], mixins: [initTableMixins, PROPOSAL_SUBMIT_MIXIN],
components: { components: {
"proposal-info": PROPOSAL_INFO "proposal-info": PROPOSAL_INFO
}, },
@@ -259,34 +261,40 @@ layout("/layouts/platform.html"){
}) })
}, },
openView(row) { openView(row) {
if (this.$root.proposalSubmitting) return
this.$refs.guava.edit(() => { this.$refs.guava.edit(() => {
this.showApprovalForm = false this.$set(this, "showApprovalForm", false)
this.$refs.proposalInfoRef.onOpen(row) this.$refs.proposalInfoRef.onOpen(row)
}) })
}, },
openAudit(row) { openAudit(row) {
if (this.$root.proposalSubmitting) return
this.$refs.guava.edit(() => { this.$refs.guava.edit(() => {
this.showApprovalForm = true this.$set(this, "showApprovalForm", true)
this.formData = { this.formData = {
proposalId: row.id, proposalId: row.id
} }
this.$refs.proposalInfoRef.onOpen(row) this.$refs.proposalInfoRef.onOpen(row)
}) })
}, },
onAudit() { onAudit() {
this.$refs.formRef.validate(valid => { return this.runProposalSubmit("onAudit", () => {
if (!valid) return return new Promise((resolve) => {
this.$confirm("您确定要提交吗?", "提示", { this.$refs.formRef.validate(resolve)
confirmButtonText: "确定", }).then((valid) => {
cancelButtonText: "取消", if (!valid) return
type: "warning" return this.$confirm("您确定要提交吗?", "提示", {
}).then(() => { confirmButtonText: "确定",
this.$axios.post("/platform/proposal/suggestion/suggest", this.formData).then((res) => { cancelButtonText: "取消",
if (res.code === 0) { type: "warning"
this.$refs.guava.index() }).then(() => {
this.$message.success(res.msg) return this.$axios.post("/platform/proposal/suggestion/suggest", this.formData).then((res) => {
this.doSearch() if (res.code === 0) {
} this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
}
})
}) })
}) })
}) })
@@ -139,14 +139,14 @@ layout("/layouts/platform.html"){
</el-table-column> </el-table-column>
<el-table-column label="操作" fixed="right" min-width="250px"> <el-table-column label="操作" fixed="right" min-width="250px">
<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" :disabled="$root.proposalSubmitting">查看</el-button>
<el-button v-if="row.taskState === 10" @click="openAudit(row)" size="mini" type="primary">答复 <el-button v-if="row.taskState === 10" @click="openAudit(row)" size="mini" type="primary" :disabled="$root.proposalSubmitting">答复
</el-button> </el-button>
<el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">撤回 <el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger" :disabled="$root.proposalSubmitting">撤回
</el-button> </el-button>
<!--承办单位领导、超级管理员才能转办--> <!--承办单位领导、超级管理员才能转办-->
<el-button v-if="!pageForm.approval && $auth.hasRoleOr('SYSADMIN,PROPOSAL_UNIT_LEADER')" <el-button v-if="!pageForm.approval && $auth.hasRoleOr('SYSADMIN,PROPOSAL_UNIT_LEADER')"
@click="openTransfer(row)" size="mini" type="primary">转交 @click="openTransfer(row)" size="mini" type="primary" :disabled="$root.proposalSubmitting">转交
</el-button> </el-button>
</template> </template>
</el-table-column> </el-table-column>
@@ -160,7 +160,7 @@ layout("/layouts/platform.html"){
<div class="process-title"> <div class="process-title">
{{formData.taskName}} {{formData.taskName}}
</div> </div>
<el-form :model="formData" ref="formRef" label-width="80px" :rules="formRules" label-suffix=""> <el-form :model="formData" ref="formRef" label-width="80px" :rules="formRules" label-suffix="" :disabled="$root.proposalSubmitting">
<el-form-item label="承办单位"> <el-form-item label="承办单位">
<el-input :value="formData.underTakeName" disabled></el-input> <el-input :value="formData.underTakeName" disabled></el-input>
</el-form-item> </el-form-item>
@@ -186,8 +186,8 @@ layout("/layouts/platform.html"){
</el-form-item> </el-form-item>
</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" :disabled="$root.proposalSubmitting">取消</el-button>
<el-button @click="handleTaskAction(1)" size="small" type="primary">提交</el-button> <el-button @click="handleTaskAction(1)" size="small" type="primary" :loading="formLoading && formAction === ('handleTaskAction:' + 1)" :disabled="$root.proposalSubmitting">提交</el-button>
</el-row> </el-row>
</div> </div>
</proposal-info> </proposal-info>
@@ -213,7 +213,7 @@ layout("/layouts/platform.html"){
</div> </div>
</div> </div>
<el-form ref="transferFormRef" :model="transferForm" label-position="top"> <el-form ref="transferFormRef" :model="transferForm" label-position="top" :disabled="$root.proposalSubmitting">
<el-form-item label="转交给" prop="userId" <el-form-item label="转交给" prop="userId"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]"> :rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-select v-model="transferForm.userId" <el-select v-model="transferForm.userId"
@@ -231,21 +231,23 @@ layout("/layouts/platform.html"){
</el-form-item> </el-form-item>
</el-form> </el-form>
<el-row type="flex" justify="end"> <el-row type="flex" justify="end">
<el-button @click="showTransferDialog = false" size="small">取消</el-button> <el-button @click="$set(this, 'showTransferDialog', false)" size="small" :disabled="$root.proposalSubmitting">取消</el-button>
<el-button @click="handleTransfer" size="small" type="primary">提交</el-button> <el-button @click="handleTransfer" size="small" type="primary" :loading="formLoading && formAction === ('handleTransfer')" :disabled="$root.proposalSubmitting">提交</el-button>
</el-row> </el-row>
</el-dialog> </el-dialog>
</div> </div>
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
<!--#include("/platform/zhgh/democratic/proposal/common/submit.js"){}#-->
<!--#include('../../common/info.js'){}#--> <!--#include('../../common/info.js'){}#-->
new Vue({ new Vue({
el: "#app", el: "#app",
store, store,
dicts: ["PROPOSAL_CASE_FILING_RESULT", "PROPOSAL_REPLY_IMPLEMENT"], dicts: ["PROPOSAL_CASE_FILING_RESULT", "PROPOSAL_REPLY_IMPLEMENT"],
mixins: [initTableMixins], mixins: [initTableMixins, PROPOSAL_SUBMIT_MIXIN],
components: { components: {
"proposal-info": PROPOSAL_INFO "proposal-info": PROPOSAL_INFO
}, },
@@ -281,16 +283,18 @@ layout("/layouts/platform.html"){
}, },
methods: { methods: {
openView(row) { openView(row) {
if (this.$root.proposalSubmitting) return
this.$refs.guava.edit(() => { this.$refs.guava.edit(() => {
this.showApprovalForm = false this.$set(this, "showApprovalForm", false)
this.$refs.proposalInfoRef.onOpen(row) this.$refs.proposalInfoRef.onOpen(row)
}) })
}, },
openAudit(row) { openAudit(row) {
if (this.$root.proposalSubmitting) return
this.loadCandidates(row.taskId) this.loadCandidates(row.taskId)
this.$refs.guava.edit(() => { this.$refs.guava.edit(() => {
this.showApprovalForm = true this.$set(this, "showApprovalForm", true)
this.formData = { this.formData = {
processTaskId: row.taskId, processTaskId: row.taskId,
taskKey: row.taskKey, taskKey: row.taskKey,
@@ -304,31 +308,33 @@ layout("/layouts/platform.html"){
}, },
handleTaskAction(val) { handleTaskAction(val) {
this.$refs.formRef.validate(valid => { return this.runProposalSubmit("handleTaskAction" + ":" + val, () => {
if (!valid) return return new Promise((resolve) => {
this.$confirm("您确定要提交吗?", "提示", { this.$refs.formRef.validate(resolve)
confirmButtonText: "确定", }).then((valid) => {
cancelButtonText: "取消", if (!valid) return
type: "warning" return this.$confirm("您确定要提交吗?", "提示", {
}).then(() => { confirmButtonText: "确定",
const loading = createLoading('提交中') cancelButtonText: "取消",
type: "warning"
}).then(() => {
delete this.formData.underTakeIsMaster
delete this.formData.underTakeName
delete this.formData.underTakeIsMaster return this.$axios
delete this.formData.underTakeName .post("/platform/proposal/unitReply/executeTask", {
data: JSON.stringify({
this.$axios.post("/platform/proposal/unitReply/executeTask", { ...this.formData,
data: JSON.stringify({ submitType: val
...this.formData, })
submitType: val })
}) .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)
this.$message.success(res.msg) this.doSearch()
this.doSearch() }
} })
}).finally(() => {
loading.close()
}) })
}) })
}) })
@@ -362,14 +368,14 @@ layout("/layouts/platform.html"){
// 打开转办 // 打开转办
openTransfer(row) { openTransfer(row) {
this.showTransferDialog = true if (this.$root.proposalSubmitting) return
this.$set(this, "showTransferDialog", true)
this.transferForm = { this.transferForm = {
taskId: row.taskId, taskId: row.taskId,
name: row.name, name: row.name,
code: row.code, code: row.code,
delegationName: row.delegationName delegationName: row.delegationName
} }
}, },
// 查询转办用户 // 查询转办用户
@@ -383,22 +389,28 @@ layout("/layouts/platform.html"){
// 转办 // 转办
handleTransfer() { handleTransfer() {
this.$refs.transferFormRef.validate(valid => { return this.runProposalSubmit("handleTransfer", () => {
if (!valid) return return new Promise((resolve) => {
const transferUserName = this.transferUserOptions.find(item => item.id === this.transferForm.userId)?.username this.$refs.transferFormRef.validate(resolve)
const name = this.transferForm.name }).then((valid) => {
if (!valid) return
const transferUserName = this.transferUserOptions.find(
(item) => item.id === this.transferForm.userId
)?.username
const name = this.transferForm.name
this.$confirm("您确定要将" + name + "提案转交给" + transferUserName + "办理吗?", "提示", { return this.$confirm("您确定要将" + name + "提案转交给" + transferUserName + "办理吗?", "提示", {
confirmButtonText: "确定", confirmButtonText: "确定",
cancelButtonText: "取消", cancelButtonText: "取消",
type: "info" type: "info"
}).then(() => { }).then(() => {
this.$axios.post('/platform/proposal/unitReply/transfer', this.transferForm).then(res => { return this.$axios.post("/platform/proposal/unitReply/transfer", this.transferForm).then((res) => {
if (res.code === 0) { if (res.code === 0) {
this.$message.success(res.msg) this.$message.success(res.msg)
this.showTransferDialog = false this.$set(this, "showTransferDialog", false)
this.doSearch() this.doSearch()
} }
})
}) })
}) })
}) })
@@ -8,7 +8,7 @@ layout("/layouts/platform.html"){
<custom-card> <custom-card>
<snaker-start slot="header" label="撰写提案" define_key="JDHTA"></snaker-start> <snaker-start slot="header" label="撰写提案" define_key="JDHTA"></snaker-start>
<el-form :model="formData" :rules="formRules" label-width="120px" ref="addForm"> <el-form :model="formData" :rules="formRules" label-width="120px" ref="addForm" :disabled="$root.proposalSubmitting">
<el-row :gutter="20" type="flex"> <el-row :gutter="20" type="flex">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="代表姓名" prop="createUserName"> <el-form-item label="代表姓名" prop="createUserName">
@@ -154,9 +154,9 @@ layout("/layouts/platform.html"){
</el-form> </el-form>
<template slot="footer" > <template slot="footer" >
<el-button type="primary" @click="onSave">保存</el-button> <el-button type="primary" @click="onSave" :loading="formLoading && formAction === ('onSave')" :disabled="$root.proposalSubmitting">保存</el-button>
<el-button type="primary" @click="onSubmit" v-if="!taskId">提交</el-button> <el-button type="primary" @click="onSubmit" v-if="!taskId" :loading="formLoading && formAction === ('onSubmit')" :disabled="$root.proposalSubmitting">提交</el-button>
<el-button type="primary" @click="onSubmitAgain" v-else>提交</el-button> <el-button type="primary" @click="onSubmitAgain" v-else :loading="formLoading && formAction === ('onSubmitAgain')" :disabled="$root.proposalSubmitting">提交</el-button>
</template> </template>
</custom-card> </custom-card>
@@ -164,16 +164,18 @@ layout("/layouts/platform.html"){
<div v-html="proposalConfig.writeRemind" style="max-height: 50vh; overflow-y: auto"></div> <div v-html="proposalConfig.writeRemind" style="max-height: 50vh; overflow-y: auto"></div>
<div slot="footer"> <div slot="footer">
<el-button type="primary" @click="noticeDialogVisible = false">我已知晓</el-button> <el-button type="primary" @click="$set(this, 'noticeDialogVisible', false)" :disabled="$root.proposalSubmitting">我已知晓</el-button>
</div> </div>
</el-dialog> </el-dialog>
</div> </div>
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
<!--#include("/platform/zhgh/democratic/proposal/common/submit.js"){}#-->
const vue = new Vue({ const vue = new Vue({
el: "#app", el: "#app",
store, store,
mixins: [initTableMixins], mixins: [initTableMixins, PROPOSAL_SUBMIT_MIXIN],
data() { data() {
return { return {
bizId: GetQueryString("bizId"), bizId: GetQueryString("bizId"),
@@ -214,103 +216,115 @@ layout("/layouts/platform.html"){
} }
}, },
methods: { methods: {
async onSave() { onSave() {
const valid = await this.$refs["addForm"].validate() return this.runProposalSubmit("onSave", async () => {
if (valid) { const valid = await this.$refs["addForm"].validate()
if (!this.formData.name || this.formData.name.trim().length < 1) { if (valid) {
this.$message.warning("请填写提案名称") if (!this.formData.name || this.formData.name.trim().length < 1) {
return this.$message.warning("请填写提案名称")
} return
this.$axios.post("/platform/proposal/write/save", {info: JSON.stringify(this.formData)}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.formData = res.data
commonUtil.pjaxPush('/platform/proposal/mine')
} }
})
} return this.$axios
.post("/platform/proposal/write/save", { info: JSON.stringify(this.formData) })
.then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.$set(this, "formData", res.data)
commonUtil.pjaxPush("/platform/proposal/mine")
}
})
}
})
}, },
// 提交 // 提交
async onSubmit() { onSubmit() {
const valid = await this.$refs["addForm"].validate() return this.runProposalSubmit("onSubmit", async () => {
if (valid) { const valid = await this.$refs["addForm"].validate()
if (!this.formData.name || this.formData.name.trim().length < 1) { if (valid) {
this.$message.warning("请填写提案名称") if (!this.formData.name || this.formData.name.trim().length < 1) {
return this.$message.warning("请填写提案名称")
} return
let brief = clone(this.formData.brief) }
brief = removeHTMLTag(brief) let brief = clone(this.formData.brief)
if (brief.length < this.proposalConfig.briefMinLength) { brief = removeHTMLTag(brief)
this.$message.warning("提案内容和依据最少为" + this.proposalConfig.briefMinLength + "字") if (brief.length < this.proposalConfig.briefMinLength) {
return this.$message.warning("提案内容和依据最少为" + this.proposalConfig.briefMinLength + "字")
} return
}
this.$confirm("您确定要提交吗?", "提示", { return this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定", confirmButtonText: "确定",
cancelButtonText: "取消", cancelButtonText: "取消",
type: "warning" type: "warning"
}).then(() => { }).then(() => {
const loading = createLoading('正在提交中') return this.$axios
this.$axios.post('/platform/proposal/write/submit', {info: JSON.stringify(this.formData)}).then(res => { .post("/platform/proposal/write/submit", { info: JSON.stringify(this.formData) })
loading.close() .then((res) => {
if (res.code === 0) { if (res.code === 0) {
this.$message.success("提交成功") this.$message.success("提交成功")
if (this.formData.source==="PERSONAL"){ if (this.formData.source === "PERSONAL") {
this.$confirm("提交成功,是否立即去邀请附议人?", "提示", { return this.$confirm("提交成功,是否立即去邀请附议人?", "提示", {
confirmButtonText: "确定", confirmButtonText: "确定",
cancelButtonText: "取消", cancelButtonText: "取消",
type: "warning" type: "warning"
}).then(() => { })
commonUtil.pjaxPush('/platform/proposal/mine?bizId=' + res.data.id + "&operation=invite") .then(() => {
}).catch(() => { commonUtil.pjaxPush(
this.$message.info("请到我的提案界面邀请附议人") "/platform/proposal/mine?bizId=" + res.data.id + "&operation=invite"
commonUtil.pjaxPush('/platform/proposal/mine') )
}) })
}else{ .catch(() => {
commonUtil.pjaxPush('/platform/proposal/mine') this.$message.info("请到我的提案界面邀请附议人")
} commonUtil.pjaxPush("/platform/proposal/mine")
})
} } else {
commonUtil.pjaxPush("/platform/proposal/mine")
}
}
})
}) })
}) }
} })
}, },
// 重新提交 // 重新提交
async onSubmitAgain() { onSubmitAgain() {
return this.runProposalSubmit("onSubmitAgain", async () => {
const valid = await this.$refs["addForm"].validate()
if (valid) {
if (!this.formData.name || this.formData.name.trim().length < 1) {
this.$message.warning("请填写提案名称")
return
}
let brief = clone(this.formData.brief)
brief = removeHTMLTag(brief)
if (brief.length < this.proposalConfig.briefMinLength) {
this.$message.warning("提案内容和依据最少为" + this.proposalConfig.briefMinLength + "字")
return
}
const valid = await this.$refs["addForm"].validate() return this.$confirm("您确定要提交吗?", "提示", {
if (valid) { confirmButtonText: "确定",
if (!this.formData.name || this.formData.name.trim().length < 1) { cancelButtonText: "取消",
this.$message.warning("请填写提案名称") type: "warning"
return }).then(() => {
} return this.$axios
let brief = clone(this.formData.brief) .post("/platform/proposal/write/submitAgain", {
brief = removeHTMLTag(brief) info: JSON.stringify(this.formData),
if (brief.length < this.proposalConfig.briefMinLength) { taskId: GetQueryString("taskId")
this.$message.warning("提案内容和依据最少为" + this.proposalConfig.briefMinLength + "字") })
return .then((res) => {
} if (res.code === 0) {
this.$message.success("提交成功")
this.$confirm("您确定要提交吗?", "提示", { commonUtil.pjaxPush("/platform/proposal/mine")
confirmButtonText: "确定", }
cancelButtonText: "取消", })
type: "warning"
}).then(() => {
this.$axios.post('/platform/proposal/write/submitAgain', {
info: JSON.stringify(this.formData),
taskId: GetQueryString("taskId")
}).then(res => {
if (res.code === 0) {
this.$message.success("提交成功")
commonUtil.pjaxPush('/platform/proposal/mine')
}
}) })
}) }
} })
}, },
// 获取提案类别 // 获取提案类别
@@ -3,7 +3,7 @@ layout("/layouts/platform.html"){
#--> #-->
<div id="app" v-cloak> <div id="app" v-cloak>
<el-card shadow="never"> <custom-card>
<snaker-start slot="header" label="职工慰问" define_key="ZGWW"></snaker-start> <snaker-start slot="header" label="职工慰问" define_key="ZGWW"></snaker-start>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=":" <el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=":"
class="flow-task-form"> class="flow-task-form">
@@ -89,24 +89,7 @@ layout("/layouts/platform.html"){
<!-- </el-form-item>--> <!-- </el-form-item>-->
<!-- </el-descriptions-item>--> <!-- </el-descriptions-item>-->
<el-descriptions-item label="收款人"> <el-descriptions-item label="收款人">
<el-form-item prop="payUserId" label="收款人"> {{formData.applyUserName}}
<el-select style="width: 100%"
v-model="formData.payUserId"
filterable
clearable
remote
reserve-keyword
placeholder="请输入姓名或工号查询"
:remote-method="createRemoteMethod(payUserOptions)"
@change="payUserChange">
<el-option
v-for="item in payUserOptions"
:key="item.id"
:label="item.userName+'('+item.loginName+')'+'('+item.unitName+')'"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="慰问类型"> <el-descriptions-item label="慰问类型">
<el-form-item prop="type" label="慰问类型"> <el-form-item prop="type" label="慰问类型">
@@ -239,7 +222,7 @@ layout("/layouts/platform.html"){
</el-descriptions-item> </el-descriptions-item>
</el-descriptions> </el-descriptions>
</el-form> </el-form>
<el-row type="flex" justify="end" class="mt20"> <template slot="footer">
<el-button type="primary" plain @click="onSave" :loading="submitLoading"> <el-button type="primary" plain @click="onSave" :loading="submitLoading">
{{ submitLoading ? "提交中..." : "保存" }} {{ submitLoading ? "提交中..." : "保存" }}
</el-button> </el-button>
@@ -249,8 +232,8 @@ layout("/layouts/platform.html"){
<el-button type="primary" @click="onFinishTask" :loading="submitLoading" v-else> <el-button type="primary" @click="onFinishTask" :loading="submitLoading" v-else>
{{ submitLoading ? "提交中..." : "提交" }} {{ submitLoading ? "提交中..." : "提交" }}
</el-button> </el-button>
</el-row> </template>
</el-card> </custom-card>
</div> </div>
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
@@ -267,7 +250,6 @@ layout("/layouts/platform.html"){
submitLoading: false, submitLoading: false,
formRules: { formRules: {
helpUserId: [{required: true, message: "必填", trigger: ["change", "blur"]}], helpUserId: [{required: true, message: "必填", trigger: ["change", "blur"]}],
payUserId: [{required: true, message: "必填", trigger: ["change", "blur"]}],
type: [{required: true, message: "必填", trigger: ["change", "blur"]}], type: [{required: true, message: "必填", trigger: ["change", "blur"]}],
way: [{required: true, message: "必填", trigger: ["change", "blur"]}], way: [{required: true, message: "必填", trigger: ["change", "blur"]}],
money: [{required: true, message: "必填", trigger: ["change", "blur"]}], money: [{required: true, message: "必填", trigger: ["change", "blur"]}],
@@ -291,7 +273,6 @@ layout("/layouts/platform.html"){
hospitalizationTime: [{required: true, message: "必填", trigger: ["change", "blur"]}], hospitalizationTime: [{required: true, message: "必填", trigger: ["change", "blur"]}],
}, },
chooseType: {}, chooseType: {},
payUserOptions: [],
helpUserOptions: [], helpUserOptions: [],
typeOptions: [], typeOptions: [],
@@ -350,14 +331,6 @@ layout("/layouts/platform.html"){
this.$set(this.formData, "certifierUnionName", unionName) this.$set(this.formData, "certifierUnionName", unionName)
} }
}, },
payUserChange(val) {
const user = this.payUserOptions.find(o => o.id === val)
if (user) {
const {userName, loginName} = user
this.$set(this.formData, "payUserName", userName)
this.$set(this.formData, "payLoginName", loginName)
}
},
typeChange(id) { typeChange(id) {
this.chooseType = this.typeOptions.find(o => o.id === id) this.chooseType = this.typeOptions.find(o => o.id === id)
if (this.chooseType) { if (this.chooseType) {
@@ -436,7 +409,6 @@ layout("/layouts/platform.html"){
if (res.code === 0) { if (res.code === 0) {
this.formData = res.data this.formData = res.data
this.selectQueryUser(this.formData.helpLoginName, this.helpUserOptions) this.selectQueryUser(this.formData.helpLoginName, this.helpUserOptions)
this.selectQueryUser(this.formData.payLoginName, this.payUserOptions)
this.selectQueryUser(this.formData.certifierLoginName, this.certifierUserOptions) this.selectQueryUser(this.formData.certifierLoginName, this.certifierUserOptions)
this.selectQueryUser(this.formData.handlerLoginName, this.handlerUserOptions) this.selectQueryUser(this.formData.handlerLoginName, this.handlerUserOptions)
this.chooseType = this.typeOptions.find(o => o.id === this.formData.type) this.chooseType = this.typeOptions.find(o => o.id === this.formData.type)
@@ -15,7 +15,8 @@ layout("/layouts/platform_h5.html"){
<div v-if="!answerRecord.isFinish"> <div v-if="!answerRecord.isFinish">
<div v-for="(subject, index) in subjects" :key="index" class="subject"> <div v-for="(subject, index) in subjects" :key="index" class="subject">
<p>{{index+1}}、{{ subject.title }}</p> <!-- 必填标识与提交校验一致,旧题未配置时默认必填。 -->
<p><span v-if="subject.required !== false" style="color: #ee0a24; margin-right: 4px;" aria-label="必填">*</span>{{index+1}}、{{ subject.title }}</p>
<div class="tag"> <div class="tag">
<van-tag v-if="subject.type === 'checkbox'" type="primary" size="large">多选</van-tag> <van-tag v-if="subject.type === 'checkbox'" type="primary" size="large">多选</van-tag>
<van-tag v-if="subject.type === 'radio'" type="primary" size="large">单选</van-tag> <van-tag v-if="subject.type === 'radio'" type="primary" size="large">单选</van-tag>
@@ -261,6 +262,10 @@ layout("/layouts/platform_h5.html"){
//提示那些题没有作答 //提示那些题没有作答
for (let i = 0; i < this.subjects.length; i++) { for (let i = 0; i < this.subjects.length; i++) {
let subject = this.subjects[i] let subject = this.subjects[i]
// 明确设置非必填的题目允许留空,旧题缺失该属性时仍须作答。
if (subject.required === false) {
continue
}
//["radio", "checkbox"].includes(subject.type) && //["radio", "checkbox"].includes(subject.type) &&
if (!subject.userSelectOptionIds || subject.userSelectOptionIds.length === 0) { if (!subject.userSelectOptionIds || subject.userSelectOptionIds.length === 0) {
this.$toast.fail("第" + (i + 1) + "题未做答") this.$toast.fail("第" + (i + 1) + "题未做答")
@@ -83,12 +83,17 @@ layout("/layouts/platform_h5.html"){
</style> </style>
<div id="app" v-cloak> <div id="app" v-cloak>
<van-nav-bar title="问卷调查" left-arrow @click-left="historyBack" placeholder fixed></van-nav-bar> <van-nav-bar title="问卷调查" left-arrow @click-left="onBack" placeholder fixed></van-nav-bar>
<div class="container" :style="{'padding-bottom': answerRecord.isFinish ? 0 : '84px'}"> <van-loading v-if="tableLoading" vertical style="padding: 40px 0">正在加载问卷</van-loading>
<van-empty v-else-if="loadError" :description="loadError">
<van-button type="primary" @click="onBack">返回首页</van-button>
</van-empty>
<div v-else-if="surveyReady" class="container" :style="{'padding-bottom': answerRecord.isFinish ? 0 : '84px'}">
<h2 class="title">{{ activity.title }}</h2> <h2 class="title">{{ activity.title }}</h2>
<div v-if="!isFinished"> <div v-if="!isFinished">
<div v-for="(subject, index) in subjects" :key="index" class="subject"> <div v-for="(subject, index) in visibleSubjects" :key="subject.id" class="subject">
<p>{{index+1}}、{{ subject.title }}</p> <!-- 必填标识与提交校验一致,旧题未配置时默认必填。 -->
<p><span v-if="subject.required !== false" style="color: #ee0a24; margin-right: 4px;" aria-label="必填">*</span>{{index+1}}、{{ subject.title }}</p>
<div class="tag"> <div class="tag">
<van-tag v-if="subject.type === 'checkbox'" type="primary" size="large">多选</van-tag> <van-tag v-if="subject.type === 'checkbox'" type="primary" size="large">多选</van-tag>
<van-tag v-if="subject.type === 'radio'" type="primary" size="large">单选</van-tag> <van-tag v-if="subject.type === 'radio'" type="primary" size="large">单选</van-tag>
@@ -98,6 +103,7 @@ layout("/layouts/platform_h5.html"){
<!--单选、多选--> <!--单选、多选-->
<van-checkbox-group <van-checkbox-group
v-model="subject.userSelectOptionIds" v-model="subject.userSelectOptionIds"
@change="onSubjectAnswerChange"
:ref="'subject'+subject.id" :ref="'subject'+subject.id"
v-if="['radio','checkbox'].includes(subject.type)" v-if="['radio','checkbox'].includes(subject.type)"
> >
@@ -148,11 +154,24 @@ layout("/layouts/platform_h5.html"){
remainingTime: 0, remainingTime: 0,
isFinished: false, isFinished: false,
answerRecord: {}, answerRecord: {},
answerRecordId: null answerRecordId: null,
tableLoading: false,
surveyReady: false,
loadError: ""
} }
}, },
computed: { computed: {
//按题目顺序计算隐显,只有当前可见的前置题答案可以触发后续题目。
visibleSubjects() {
const visible = []
this.subjects.forEach((subject) => {
if (this.isSubjectVisible(subject, visible)) {
visible.push(subject)
}
})
return visible
},
isEnd() { isEnd() {
if (this.activity) { if (this.activity) {
return this.$moment().unix() > this.$moment(this.activity.endTime).unix() return this.$moment().unix() > this.$moment(this.activity.endTime).unix()
@@ -162,45 +181,131 @@ layout("/layouts/platform_h5.html"){
}, },
methods: { methods: {
//获取活动、题目 //失败页直接替换为首页,避免扫码认证历史将用户再次带回无权参与的问卷。
listSubjects() { onBack() {
this.$axios.post("/platform/h5/qsv/survey/subjects", { activityId: this.id }).then((res) => { if (this.loadError) {
if (res.code === 0) { window.h5PopupHistory.clear().then(() => {
this.activity = res.data.activity window.location.replace("/platform/h5/home")
this.subjects = res.data.subjects })
this.answerRecordId = res.data.answerRecordId return
this.getAnswerRecord() }
} this.historyBack()
})
}, },
//获取回答记录 //error 为接口业务错误或网络异常;持久展示提示,并禁止空问卷提交。
onLoadError(error) {
this.$set(this, "surveyReady", false)
this.$set(this, "loadError", (error && (error.msg || error.message)) || "问卷加载失败,请返回首页后重试")
},
//activityId 传扫码地址中的 id;成功返回活动、题目及答题记录 ID,再加载历史答案。
listSubjects() {
this.$set(this, "tableLoading", true)
this.$set(this, "surveyReady", false)
this.$set(this, "loadError", "")
return this.$axios.post("/platform/h5/qsv/survey/subjects", { activityId: this.id })
.then((res) => {
if (res.code !== 0 || !res.data || !res.data.activity || !res.data.answerRecordId || !Array.isArray(res.data.subjects)) {
throw new Error(res.msg || "问卷数据不完整,请返回首页后重试")
}
this.$set(this, "activity", res.data.activity)
this.$set(this, "subjects", res.data.subjects)
this.$set(this, "answerRecordId", res.data.answerRecordId)
return this.getAnswerRecord()
})
.catch((error) => {
this.onLoadError(error)
})
.finally(() => {
this.$set(this, "tableLoading", false)
})
},
//answerRecordId 传题目接口返回的记录 ID;答案回显完成后才允许展示和提交问卷。
getAnswerRecord() { getAnswerRecord() {
this.$axios.post("/platform/h5/qsv/survey/answerRecord", { answerRecordId: this.answerRecordId }).then((res) => { this.$set(this, "tableLoading", true)
if (res.code === 0) { this.$set(this, "surveyReady", false)
this.answerRecord = res.data return this.$axios.post("/platform/h5/qsv/survey/answerRecord", { answerRecordId: this.answerRecordId })
.then((res) => {
if (res.code !== 0 || !res.data) {
throw new Error(res.msg || "答题记录加载失败,请返回首页后重试")
}
this.$set(this, "answerRecord", res.data)
if (this.answerRecord.isFinish) { if (this.answerRecord.isFinish) {
this.$toast.success("您已完成该调查") this.$toast.success("您已完成该调查")
} }
this.initAnswer() this.initAnswer()
} this.$set(this, "loadError", "")
}) this.$set(this, "surveyReady", true)
})
.catch((error) => {
this.onLoadError(error)
})
.finally(() => {
this.$set(this, "tableLoading", false)
})
}, },
//答案回显 //直接回填答案数据,隐藏题没有组件引用,也能安全完成历史答卷回显。
initAnswer() { initAnswer() {
this.subjects.forEach((subject, subjectIndex) => { this.subjects.forEach((subject) => {
const answer = this.answerRecord.extJson[subject.id] const answer = (this.answerRecord.extJson || {})[subject.id]
if (["radio", "checkbox"].includes(subject.type)) { if (["radio", "checkbox"].includes(subject.type)) {
this.$refs["subject" + subject.id][0].toggleAll(false) this.$set(subject, "userSelectOptionIds", answer?.optionIds || [])
answer?.optionIds.forEach((optionId) => {
this.$nextTick(() => {
this.$refs["option" + optionId][0].toggle()
})
})
} else if (subject.type === "text") { } else if (subject.type === "text") {
subject.userFillContent = answer?.text this.$set(subject, "userFillContent", answer?.text || null)
}
})
this.onSubjectAnswerChange()
},
//subject 为当前题目,visible 为已判定可见的前置题;返回布尔值决定是否显示。
isSubjectVisible(subject, visible) {
if (!subject.visibleRuleEnabled) {
return true
}
let conditions = subject.visibleRuleConditions || []
if (typeof conditions === "string") {
try {
conditions = JSON.parse(conditions)
} catch (e) {
conditions = []
}
}
//旧数据或无有效条件时默认展示,避免整题无法填写。
if (!Array.isArray(conditions) || conditions.length === 0) {
return true
}
const results = conditions.map((condition) => {
if (!condition) {
return false
}
const trigger = visible.find((item) => item.id === condition.subjectId)
return !!trigger && ["radio", "checkbox"].includes(trigger.type)
&& (trigger.options || []).some((option) => option.id === condition.optionId)
&& (trigger.userSelectOptionIds || []).includes(condition.optionId)
})
const matched = subject.visibleRuleLogic === "OR"
? results.some((value) => value)
: results.every((value) => value)
return subject.visibleRuleAction === "hide" ? !matched : matched
},
//选择变化后清理所有隐藏题答案;保留已提交记录,避免回显时改动历史数据。
onSubjectAnswerChange() {
if (this.answerRecord.isFinish) {
return
}
const visibleIds = this.visibleSubjects.map((subject) => subject.id)
this.subjects.forEach((subject) => {
if (visibleIds.includes(subject.id)) {
return
}
if ((subject.userSelectOptionIds || []).length > 0) {
this.$set(subject, "userSelectOptionIds", [])
}
if (subject.userFillContent) {
this.$set(subject, "userFillContent", null)
} }
}) })
}, },
@@ -224,6 +329,10 @@ layout("/layouts/platform_h5.html"){
//手动提交 //手动提交
onSubmit() { onSubmit() {
//范围校验失败、加载未完成或已提交时,不发送无效答卷。
if (!this.surveyReady || this.tableLoading || this.loadError || !this.answerRecordId || this.answerRecord.isFinish) {
return
}
const endTime = this.activity.endTime const endTime = this.activity.endTime
if (this.isEnd) { if (this.isEnd) {
this.$toast("调查已结束") this.$toast("调查已结束")
@@ -231,8 +340,12 @@ layout("/layouts/platform_h5.html"){
} }
//提示那些题没有作答 //提示那些题没有作答
for (let i = 0; i < this.subjects.length; i++) { for (let i = 0; i < this.visibleSubjects.length; i++) {
const subject = this.subjects[i] const subject = this.visibleSubjects[i]
// 仅校验可见的必填题;旧题属性缺失或为空时仍按必填处理。
if (subject.required === false) {
continue
}
if (["radio", "checkbox"].includes(subject.type)) { if (["radio", "checkbox"].includes(subject.type)) {
if (!subject.userSelectOptionIds || subject.userSelectOptionIds.length === 0) { if (!subject.userSelectOptionIds || subject.userSelectOptionIds.length === 0) {
this.$toast.fail("第" + (i + 1) + "题未做答") this.$toast.fail("第" + (i + 1) + "题未做答")
@@ -250,12 +363,16 @@ layout("/layouts/platform_h5.html"){
//自动提交 //自动提交
autoSubmit(loading = null) { autoSubmit(loading = null) {
//同时保护直接调用入口,避免绕过按钮状态提交空记录。
if (!this.surveyReady || this.tableLoading || this.loadError || !this.answerRecordId || this.answerRecord.isFinish) {
return
}
this.$axios this.$axios
.post("/platform/h5/qsv/survey/submitAnswer", { .post("/platform/h5/qsv/survey/submitAnswer", {
answer: JSON.stringify({ answer: JSON.stringify({
activityId: this.id, activityId: this.id,
answerRecordId: this.answerRecordId, answerRecordId: this.answerRecordId,
subjects: this.subjects.map((subject) => { subjects: this.visibleSubjects.map((subject) => {
return { return {
id: subject.id, id: subject.id,
userSelectOptionIds: ["checkbox", "radio"].includes(subject.type) ? subject.userSelectOptionIds : [], userSelectOptionIds: ["checkbox", "radio"].includes(subject.type) ? subject.userSelectOptionIds : [],
@@ -280,8 +397,10 @@ layout("/layouts/platform_h5.html"){
created() { created() {
const id = GetQueryString("id") const id = GetQueryString("id")
if (id) { if (id) {
this.id = id this.$set(this, "id", id)
this.listSubjects() this.listSubjects()
} else {
this.onLoadError({ msg: "问卷链接缺少活动信息,请返回首页" })
} }
} }
}) })
@@ -162,11 +162,12 @@ const PROPOSAL_INFO = {
</div> </div>
</van-cell> </van-cell>
<van-cell title="主办单位">{{ task.ext.tf_masterUnitName }}</van-cell> <van-cell title="主办单位">{{ task.ext.tf_masterUnitName }}</van-cell>
<van-cell title="协办单位">{{ task?.ext?.tf_slaveUnitNameStr }}</van-cell> <van-cell title="协办单位">{{ getSlaveUnitNames(task) }}</van-cell>
<van-cell title="指定分管校领导" v-if="getBranchSchoolLeaderName(task)"> <van-cell title="指定分管校领导" v-if="getBranchSchoolLeaderName(task)">
{{ getBranchSchoolLeaderName(task) }} {{ getBranchSchoolLeaderName(task) }}
</van-cell> </van-cell>
<van-cell title="办理意见" class="direction-column-cell"> <van-cell title="办理意见" class="direction-column-cell">
<!-- 主任意见统一读取本节点提交的 tf_opinion;历史意见由专项 SQL 修正。 -->
<div v-html="task.taskFormData.tf_opinion"></div> <div v-html="task.taskFormData.tf_opinion"></div>
</van-cell> </van-cell>
</van-cell-group> </van-cell-group>
@@ -184,13 +185,19 @@ const PROPOSAL_INFO = {
{{ getBranchSchoolLeaderName(task) }} {{ getBranchSchoolLeaderName(task) }}
</van-cell> </van-cell>
<van-cell title="办理意见" class="direction-column-cell"> <van-cell title="办理意见" class="direction-column-cell">
<!-- 主任审核统一读取本节点提交的 tf_opinion,避免展示前序单位的答复。 -->
<div v-html="task.taskFormData.tf_opinion"></div> <div v-html="task.taskFormData.tf_opinion"></div>
</van-cell> </van-cell>
</van-cell-group> </van-cell-group>
<van-cell-group :title="task.displayName" v-else> <van-cell-group :title="task.displayName" v-else>
<van-cell title="办理单位" v-if="['master_reply','slave_reply'].includes(task.taskName)"> <van-cell title="办理单位" v-if="isReplyTask(task)">
{{task.ext.underTakeName}} {{getReplyUnitName(task)}}
</van-cell>
<van-cell title="落实情况" v-if="isReplyTask(task)">
<dict-tag v-if="task.ext.tf_implementState" :options="dict.type.PROPOSAL_REPLY_IMPLEMENT"
:value="task.ext.tf_implementState"></dict-tag>
<span v-else>未记录</span>
</van-cell> </van-cell>
<van-cell title="办理用户">{{ task.taskFormData.userName }}({{task.taskFormData.loginName}}) <van-cell title="办理用户">{{ task.taskFormData.userName }}({{task.taskFormData.loginName}})
@@ -201,6 +208,9 @@ const PROPOSAL_INFO = {
<dict-tag :options="dict.type.PROPOSAL_FEEDBACK" <dict-tag :options="dict.type.PROPOSAL_FEEDBACK"
:value="task.ext.tf_feedback"></dict-tag> :value="task.ext.tf_feedback"></dict-tag>
</van-cell> </van-cell>
<van-cell title="办理结果" v-else-if="getSchoolLeaderResult(task)">
{{getSchoolLeaderResult(task)}}
</van-cell>
<van-cell title="办理结果" v-else> <van-cell title="办理结果" v-else>
<dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE" <dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE"
:value="task.ext.submitType"></dict-tag> :value="task.ext.submitType"></dict-tag>
@@ -215,7 +225,7 @@ const PROPOSAL_INFO = {
<slot></slot> <slot></slot>
</van-action-sheet> </van-action-sheet>
`, `,
dicts: ["PROPOSAL_TYPE", "PROPOSAL_CASE_FILING_RESULT", "PROPOSAL_SUGGESTION_CASE_FILING_RESULT", "PROPOSAL_CASE_FILING_TYPE", "PROCESS_TASK_SUBMIT_TYPE", "PROPOSAL_FEEDBACK"], dicts: ["PROPOSAL_TYPE", "PROPOSAL_CASE_FILING_RESULT", "PROPOSAL_SUGGESTION_CASE_FILING_RESULT", "PROPOSAL_CASE_FILING_TYPE", "PROCESS_TASK_SUBMIT_TYPE", "PROPOSAL_FEEDBACK", "PROPOSAL_REPLY_IMPLEMENT"],
data() { data() {
return { return {
visible:false, visible:false,
@@ -225,13 +235,32 @@ const PROPOSAL_INFO = {
originalRow: null, // 用于保存原始数据,支持返回功能 originalRow: null, // 用于保存原始数据,支持返回功能
positiveSecondList: [], positiveSecondList: [],
branchSchoolLeaderOptions: [], branchSchoolLeaderOptions: [],
detailRequestVersion: 0,
}
},
created() {
// 仅办理页面提供历史栈管理;普通查询页面沿用原有查看行为。
if (this.$root.trackProposalPopup) this.$root.trackProposalPopup(this, 'visible')
},
beforeDestroy() {
if (this.proposalPopupUnwatch) this.proposalPopupUnwatch.forEach((stop) => stop())
if (this.$root.proposalPopupRecords) {
this.$root.proposalPopupRecords.forEach((record, key) => {
if (record.vm === this) this.$root.proposalPopupRecords.delete(key)
})
} }
}, },
methods: { methods: {
// 打开 // 打开
onOpen(row) { onOpen(row) {
this.row = row if (this.$root.proposalSubmitting) return
this.visible = true // 每次打开递增版本,阻止前一次查看的迟到响应覆盖当前提案(包括 A→B→A)。
this.$set(this, "detailRequestVersion", this.detailRequestVersion + 1)
this.$set(this, "row", row)
this.$set(this, "viewData", {})
this.$set(this, "doneTasks", [])
this.$set(this, "positiveSecondList", [])
this.$set(this, 'visible', true)
this.getInfo() this.getInfo()
this.getDoneTasks() this.getDoneTasks()
this.listPositiveSeconded() this.listPositiveSeconded()
@@ -240,14 +269,15 @@ const PROPOSAL_INFO = {
// 关闭 // 关闭
onClose(){ onClose(){
this.visible = false this.$set(this, 'visible', false)
}, },
// 获取申请信息 // 获取申请信息
getInfo() { getInfo() {
const requestVersion = this.detailRequestVersion
this.$axios.post("/platform/proposal/common/proposalInfo", {id: this.row.id}).then((res) => { this.$axios.post("/platform/proposal/common/proposalInfo", {id: this.row.id}).then((res) => {
if (res.code === 0) { if (res.code === 0 && requestVersion === this.detailRequestVersion) {
this.viewData = res.data this.$set(this, "viewData", res.data)
} }
}) })
}, },
@@ -256,16 +286,9 @@ const PROPOSAL_INFO = {
openView(row) { openView(row) {
// 如果传入的是并案对象,则打开新的详情页面 // 如果传入的是并案对象,则打开新的详情页面
if (row && typeof row === 'object' && row.id) { if (row && typeof row === 'object' && row.id) {
// 创建一个新的提案详情组件实例来显示并案详情 // 并案切换必须同步刷新基础信息、流程记录和主动附议,避免展示原提案的意见。
this.$nextTick(() => { this.$set(this, "originalRow", this.row)
// 可以通过事件总线或者其他方式来打开新的详情页面 this.onOpen(row)
// 这里暂时使用简单的方式,直接在当前组件中显示
const currentRow = this.row;
this.row = row;
this.getInfo();
// 保存原来的数据,以便返回时恢复
this.originalRow = currentRow;
})
} else { } else {
// 原有的逻辑,通过ID查看 // 原有的逻辑,通过ID查看
this.$nextTick(() => { this.$nextTick(() => {
@@ -278,22 +301,57 @@ const PROPOSAL_INFO = {
// 获取已办任务审批记录 // 获取已办任务审批记录
getDoneTasks() { getDoneTasks() {
const requestVersion = this.detailRequestVersion
this.$axios.post("/flow/common/doneTasks", {bizId: this.row.id}).then((res) => { this.$axios.post("/flow/common/doneTasks", {bizId: this.row.id}).then((res) => {
if (res.code === 0) { if (res.code === 0 && requestVersion === this.detailRequestVersion) {
this.doneTasks = res.data this.$set(this, "doneTasks", res.data)
} }
}) })
}, },
// 获取主动附议信息 // 获取主动附议信息
listPositiveSeconded() { listPositiveSeconded() {
const requestVersion = this.detailRequestVersion
this.$axios.post("/platform/proposal/positiveSeconded/listPositiveSeconded", {bizId: this.row.id}).then((res) => { this.$axios.post("/platform/proposal/positiveSeconded/listPositiveSeconded", {bizId: this.row.id}).then((res) => {
if (res.code === 0) { if (res.code === 0 && requestVersion === this.detailRequestVersion) {
this.positiveSecondList = res.data this.$set(this, "positiveSecondList", res.data)
} }
}) })
}, },
// task 为主任已办任务;返回分号分隔的单位名称,旧记录仅转换原拼接用的英文逗号,不拆分单位内部顿号。
getSlaveUnitNames(task) {
const ext = task.ext || {}
if (Array.isArray(ext.tf_slaveUnitNames)) {
return ext.tf_slaveUnitNames.join(";")
}
return (ext.tf_slaveUnitNameStr || "").split(",").join(";")
},
// 三类答复节点均展示单位和落实情况,其他节点不能展示继承的答复字段。
isReplyTask(task) {
return ["master_reply", "slave_reply", "opinion_master_reply"].includes(task.taskName)
},
// task 为已办任务;返回单位名称。仅主办允许使用本任务保存的主办名称补齐历史缺失值。
getReplyUnitName(task) {
const ext = task.ext || {}
if (ext.underTakeName) {
return ext.underTakeName
}
return ["master_reply", "opinion_master_reply"].includes(task.taskName)
? (ext.tf_masterUnitName || "未记录") : "未记录"
},
// task 为已办任务;校领导返回实际审批动作文本,其他节点或旧记录缺少动作时返回空串沿用提交结果。
getSchoolLeaderResult(task) {
if (!["school_leader", "school_leader_instruction"].includes(task.taskName)) {
return ""
}
const approval = task.ext?.tf_approval
return approval === "back" ? "退回重新答复" : (approval === "agree" ? "同意" : "")
},
// 查询分管校领导,用于把流程任务中保存的 userId 显示成姓名。 // 查询分管校领导,用于把流程任务中保存的 userId 显示成姓名。
listBranchSchoolLeader() { listBranchSchoolLeader() {
if (this.branchSchoolLeaderOptions.length > 0) { if (this.branchSchoolLeaderOptions.length > 0) {
@@ -64,7 +64,7 @@ layout("/layouts/platform_h5.html"){
required required
is-link is-link
@click="openCaseFilingResultPicker" @click="openCaseFilingResultPicker"
></van-field> :disabled="$root.proposalSubmitting"></van-field>
<van-popup v-model="showCaseFilingResultPicker" position="bottom"> <van-popup v-model="showCaseFilingResultPicker" position="bottom">
<van-picker <van-picker
show-toolbar show-toolbar
@@ -104,23 +104,28 @@ layout("/layouts/platform_h5.html"){
required required
maxlength="100" maxlength="100"
show-word-limit show-word-limit
></van-field> :disabled="$root.proposalSubmitting"></van-field>
</van-form> </van-form>
<div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px"> <div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px">
<van-button block @click="$refs.proposalInfoRef.onClose()">取消</van-button> <van-button block @click="$refs.proposalInfoRef.onClose()" :disabled="$root.proposalSubmitting">取消</van-button>
<van-button type="primary" block @click="doSubmit">提交</van-button> <van-button type="primary" block @click="doSubmit" :loading="formLoading && formAction === ('doSubmit')" loading-text="提交中…" :disabled="$root.proposalSubmitting">提交</van-button>
</div> </div>
</div> </div>
</proposal-info> </proposal-info>
</div> </div>
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
<!--#include("/platform/zhgh/democratic/proposal/common/submit.js"){}#-->
<!--#include("../../common/info.js"){}#--> <!--#include("../../common/info.js"){}#-->
const vue = new Vue({ const vue = new Vue({
el: "#app", el: "#app",
store, store,
proposalH5: true,
dicts: ["PROPOSAL_CASE_FILING_RESULT", "PROPOSAL_SUGGESTION_CASE_FILING_RESULT", "PROPOSAL_CASE_FILING_TYPE"], dicts: ["PROPOSAL_CASE_FILING_RESULT", "PROPOSAL_SUGGESTION_CASE_FILING_RESULT", "PROPOSAL_CASE_FILING_TYPE"],
mixins: [PROPOSAL_SUBMIT_MIXIN],
proposalPopupFields: ["showCaseFilingResultPicker", "showCaseFilingTypePicker"],
data() { data() {
return { return {
pageForm: { pageForm: {
@@ -184,6 +189,7 @@ layout("/layouts/platform_h5.html"){
}, },
onView(row) { onView(row) {
if (this.$root.proposalSubmitting) return
this.$set(this, "showApprovalForm", false) this.$set(this, "showApprovalForm", false)
this.$refs.proposalInfoRef.onOpen(row) this.$refs.proposalInfoRef.onOpen(row)
}, },
@@ -227,26 +233,30 @@ layout("/layouts/platform_h5.html"){
}) })
}, },
async doSubmit() { doSubmit() {
try { return this.runProposalSubmit("doSubmit", async () => {
await this.$refs.formRef.validate(); try {
this.$dialog.confirm({ await this.$refs.formRef.validate()
title: '提示', return this.proposalConfirm({
message: "您确定要提交吗?", title: "提示",
}).then(() => { message: "您确定要提交吗?"
this.$axios.post('/platform/proposal/commissioner/doApproval', this.formData).then(res => {
if (res.code === 0) {
this.$refs.proposalInfoRef.onClose()
this.$toast.success(res.msg)
this.doSearch()
}
}) })
}).catch(() => { .then(() => {
return this.$axios
}) .post("/platform/proposal/commissioner/doApproval", this.formData)
} catch (error) { .then((res) => {
if (res.code === 0) {
} return this.finishProposalSubmit(() => {
this.$refs.proposalInfoRef.onClose()
this.$toast.success(res.msg)
this.doSearch()
})
}
})
})
.catch(() => {})
} catch (error) {}
})
}, },
doSearch() { doSearch() {
@@ -64,7 +64,7 @@ layout("/layouts/platform_h5.html"){
required required
is-link is-link
@click="openCaseFilingResultPicker" @click="openCaseFilingResultPicker"
></van-field> :disabled="$root.proposalSubmitting"></van-field>
<van-popup v-model="showCaseFilingResultPicker" position="bottom"> <van-popup v-model="showCaseFilingResultPicker" position="bottom">
<van-picker <van-picker
show-toolbar show-toolbar
@@ -84,7 +84,7 @@ layout("/layouts/platform_h5.html"){
required required
is-link is-link
@click="openCaseFilingTypePicker" @click="openCaseFilingTypePicker"
></van-field> :disabled="$root.proposalSubmitting"></van-field>
<van-popup v-model="showCaseFilingTypePicker" position="bottom"> <van-popup v-model="showCaseFilingTypePicker" position="bottom">
<van-picker <van-picker
show-toolbar show-toolbar
@@ -104,7 +104,7 @@ layout("/layouts/platform_h5.html"){
required required
is-link is-link
@click="openMasterUnitPicker" @click="openMasterUnitPicker"
></van-field> :disabled="$root.proposalSubmitting"></van-field>
<van-popup v-model="showMasterUnitPicker" position="bottom"> <van-popup v-model="showMasterUnitPicker" position="bottom">
<van-picker <van-picker
show-toolbar show-toolbar
@@ -123,12 +123,12 @@ layout("/layouts/platform_h5.html"){
readonly readonly
is-link is-link
@click="openSlaveUnitPicker" @click="openSlaveUnitPicker"
></van-field> :disabled="$root.proposalSubmitting"></van-field>
<van-popup v-model="showSlaveUnitPicker" position="bottom"> <van-popup v-model="showSlaveUnitPicker" position="bottom">
<div style="padding: 12px 16px; display: flex; justify-content: space-between; align-items: center;"> <div style="padding: 12px 16px; display: flex; justify-content: space-between; align-items: center;">
<van-button size="small" @click="hideSlaveUnitPicker">取消</van-button> <van-button size="small" @click="hideSlaveUnitPicker" :disabled="$root.proposalSubmitting">取消</van-button>
<span>选择协办单位</span> <span>选择协办单位</span>
<van-button size="small" type="primary" @click="onSlaveUnitConfirm">确定</van-button> <van-button size="small" type="primary" @click="onSlaveUnitConfirm" :disabled="$root.proposalSubmitting">确定</van-button>
</div> </div>
<van-checkbox-group v-model="slaveUnitTempIds" style="max-height: 320px; overflow-y: auto;"> <van-checkbox-group v-model="slaveUnitTempIds" style="max-height: 320px; overflow-y: auto;">
<van-cell-group> <van-cell-group>
@@ -159,7 +159,7 @@ layout("/layouts/platform_h5.html"){
required required
is-link is-link
@click="openBranchSchoolLeaderPicker" @click="openBranchSchoolLeaderPicker"
></van-field> :disabled="$root.proposalSubmitting"></van-field>
<van-popup v-model="showBranchSchoolLeaderPicker" position="bottom"> <van-popup v-model="showBranchSchoolLeaderPicker" position="bottom">
<van-picker <van-picker
show-toolbar show-toolbar
@@ -169,31 +169,37 @@ layout("/layouts/platform_h5.html"){
></van-picker> ></van-picker>
</van-popup> </van-popup>
<!-- 本节点本人填写的审核意见统一提交为 tf_opinion,覆盖流程继承的前序意见。 -->
<van-field <van-field
v-model="formData.approvalOpinion" v-model="formData.tf_opinion"
name="approvalOpinion" name="tf_opinion"
label="审核意见" label="审核意见"
placeholder="请输入审核意见" placeholder="请输入审核意见"
:rules="[{ required: true, message: '请填写审核意见' }]" :rules="[{ required: true, message: '请填写审核意见' }]"
required required
maxlength="100" maxlength="100"
show-word-limit show-word-limit
></van-field> :disabled="$root.proposalSubmitting"></van-field>
</van-form> </van-form>
<div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px"> <div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px">
<van-button type="danger" block :loading="submitLoading" @click="handleTaskAction(6)">退回到提案人</van-button> <van-button type="danger" block @click="handleTaskAction(6)" :loading="formLoading && formAction === ('handleTaskAction:' + 6)" loading-text="提交中…" :disabled="$root.proposalSubmitting">退回到提案人</van-button>
<van-button type="primary" block :loading="submitLoading" @click="handleTaskAction(1)">提交</van-button> <van-button type="primary" block @click="handleTaskAction(1)" :loading="formLoading && formAction === ('handleTaskAction:' + 1)" loading-text="提交中…" :disabled="$root.proposalSubmitting">提交</van-button>
</div> </div>
</div> </div>
</proposal-info> </proposal-info>
</div> </div>
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
<!--#include("/platform/zhgh/democratic/proposal/common/submit.js"){}#-->
<!--#include("../../common/info.js"){}#--> <!--#include("../../common/info.js"){}#-->
const vue = new Vue({ const vue = new Vue({
el: "#app", el: "#app",
store, store,
proposalH5: true,
dicts: ["PROPOSAL_CASE_FILING_RESULT", "PROPOSAL_CASE_FILING_TYPE"], dicts: ["PROPOSAL_CASE_FILING_RESULT", "PROPOSAL_CASE_FILING_TYPE"],
mixins: [PROPOSAL_SUBMIT_MIXIN],
proposalPopupFields: ["showCaseFilingResultPicker", "showCaseFilingTypePicker", "showMasterUnitPicker", "showSlaveUnitPicker", "showBranchSchoolLeaderPicker"],
data() { data() {
return { return {
pageForm: { pageForm: {
@@ -211,7 +217,7 @@ layout("/layouts/platform_h5.html"){
slaveUnitTempIds: [], slaveUnitTempIds: [],
formData: {}, formData: {},
showApprovalForm: false, showApprovalForm: false,
submitLoading: false,
showCaseFilingResultPicker: false, showCaseFilingResultPicker: false,
showCaseFilingTypePicker: false, showCaseFilingTypePicker: false,
showMasterUnitPicker: false, showMasterUnitPicker: false,
@@ -285,6 +291,7 @@ layout("/layouts/platform_h5.html"){
}) })
}, },
onView(row) { onView(row) {
if (this.$root.proposalSubmitting) return
this.$set(this, "showApprovalForm", false) this.$set(this, "showApprovalForm", false)
this.$refs.proposalInfoRef.onOpen(row) this.$refs.proposalInfoRef.onOpen(row)
}, },
@@ -305,7 +312,7 @@ layout("/layouts/platform_h5.html"){
tf_slaveUnitIds: [], tf_slaveUnitIds: [],
tf_slaveUnitNames: [], tf_slaveUnitNames: [],
tf_slaveUnitNameStr: null, tf_slaveUnitNameStr: null,
approvalOpinion: null tf_opinion: null
}) })
this.$refs.proposalInfoRef.onOpen(row) this.$refs.proposalInfoRef.onOpen(row)
}, },
@@ -413,58 +420,64 @@ layout("/layouts/platform_h5.html"){
this.$set(this.formData, "userId", value.value) this.$set(this.formData, "userId", value.value)
this.$set(this, "showBranchSchoolLeaderPicker", false) this.$set(this, "showBranchSchoolLeaderPicker", false)
}, },
async handleTaskAction(val) { handleTaskAction(val) {
if (this.submitLoading) { return this.runProposalSubmit("handleTaskAction" + ":" + val, async () => {
return try {
} await this.$refs.formRef.validate()
try { if (val === 1 && this.isBranchSchoolLeaderRequired() && !this.formData.userId) {
await this.$refs.formRef.validate() this.$toast("请选择分管校领导")
if (val === 1 && this.isBranchSchoolLeaderRequired() && !this.formData.userId) { return
this.$toast("请选择分管校领导") }
return return this.proposalConfirm({
} title: "提示",
this.$dialog.confirm({ message: "您确定要提交吗?"
title: "提示", })
message: "您确定要提交吗?" .then(() => {
}).then(() => { var data = Object.assign({}, this.formData)
var data = Object.assign({}, this.formData) data.submitType = val
data.submitType = val data.tf_helpunitreply =
data.tf_helpunitreply = this.formData.tf_slaveUnitIds.length > 0 ? "HAS_HELP_UNIT" : "NO_HELP_UNIT" this.formData.tf_slaveUnitIds.length > 0 ? "HAS_HELP_UNIT" : "NO_HELP_UNIT"
this.$set(this, "submitLoading", true) return this.$axios
this.$axios.post("/flow/common/executeTask", { .post("/flow/common/executeTask", {
data: JSON.stringify(data) data: JSON.stringify(data)
}).then((res) => { })
if (res.code === 0) { .then((res) => {
this.$refs.proposalInfoRef.onClose() if (res.code === 0) {
return this.finishProposalSubmit(() => {
this.$refs.proposalInfoRef.onClose()
this.$toast.success(res.msg)
this.doSearch()
})
}
})
})
.catch(() => {})
} catch (error) {}
})
},
// row 提供当前记录的流程任务 ID;确认与请求共用办理锁,离开页面后不再刷新旧表格。
onRevoke(row) {
return this.runProposalSubmit("onRevoke", () => {
return this.proposalConfirm({
title: "提示",
message: "您确定要撤回吗?"
}).then(() => {
if (this.proposalDisposed) return
return this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
// code 为 0 表示撤回成功;已销毁页面不提示、不访问失效的组件引用。
if (res.code === 0 && !this.proposalDisposed) {
this.$toast.success(res.msg) this.$toast.success(res.msg)
this.doSearch() this.doSearch()
} }
}).finally(() => {
this.$set(this, "submitLoading", false)
}) })
}).catch(() => {
})
} catch (error) {
}
},
onRevoke(row) {
this.$dialog.confirm({
title: "提示",
message: "您确定要撤回吗?"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
this.doSearch()
}
}) })
}) })
}, },
doSearch() { doSearch() {
this.$nextTick(() => { this.$nextTick(() => {
// nextTick 执行前页面可能已被 PJAX 替换,不能访问已销毁的表格。
if (this.proposalDisposed || !this.$refs.tableListRef) return
this.$set(this.pageForm, "pageNumber", 1) this.$set(this.pageForm, "pageNumber", 1)
this.$set(this.pageForm, "totalCount", 0) this.$set(this.pageForm, "totalCount", 0)
this.$refs.tableListRef.doSearch() this.$refs.tableListRef.doSearch()
@@ -62,23 +62,27 @@ layout("/layouts/platform_h5.html"){
required required
maxlength="100" maxlength="100"
show-word-limit show-word-limit
></van-field> :disabled="$root.proposalSubmitting"></van-field>
</van-form> </van-form>
<div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px"> <div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px">
<van-button type="danger" block @click="handleTaskAction(6)">退回</van-button> <van-button type="danger" block @click="handleTaskAction(6)" :loading="formLoading && formAction === ('handleTaskAction:' + 6)" loading-text="提交中…" :disabled="$root.proposalSubmitting">退回</van-button>
<van-button type="danger" block @click="handleTaskAction(2)">不同意</van-button> <van-button type="danger" block @click="handleTaskAction(2)" :loading="formLoading && formAction === ('handleTaskAction:' + 2)" loading-text="提交中…" :disabled="$root.proposalSubmitting">不同意</van-button>
<van-button type="primary" block @click="handleTaskAction(1)">同意</van-button> <van-button type="primary" block @click="handleTaskAction(1)" :loading="formLoading && formAction === ('handleTaskAction:' + 1)" loading-text="提交中…" :disabled="$root.proposalSubmitting">同意</van-button>
</div> </div>
</div> </div>
</proposal-info> </proposal-info>
</div> </div>
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
<!--#include("/platform/zhgh/democratic/proposal/common/submit.js"){}#-->
<!--#include("../../common/info.js"){}#--> <!--#include("../../common/info.js"){}#-->
const vue = new Vue({ const vue = new Vue({
el: "#app", el: "#app",
store, store,
proposalH5: true,
mixins: [PROPOSAL_SUBMIT_MIXIN],
data() { data() {
return { return {
pageForm: { pageForm: {
@@ -121,7 +125,8 @@ layout("/layouts/platform_h5.html"){
}, },
onView(row) { onView(row) {
this.showApprovalForm = false if (this.$root.proposalSubmitting) return
this.$set(this, "showApprovalForm", false)
this.$refs.proposalInfoRef.onOpen(row) this.$refs.proposalInfoRef.onOpen(row)
}, },
@@ -134,49 +139,60 @@ layout("/layouts/platform_h5.html"){
} }
}, },
async handleTaskAction(val) { handleTaskAction(val) {
try { return this.runProposalSubmit("handleTaskAction" + ":" + val, async () => {
await this.$refs.formRef.validate(); try {
this.$dialog.confirm({ await this.$refs.formRef.validate()
title: "提示", return this.proposalConfirm({
message: "您确定要提交吗?" title: "提示",
}).then(() => { message: "您确定要提交吗?"
this.$axios.post("/flow/common/executeTask", { })
data: JSON.stringify({ .then(() => {
...this.formData, return this.$axios
submitType: val .post("/flow/common/executeTask", {
data: JSON.stringify({
...this.formData,
submitType: val
})
})
.then((res) => {
if (res.code === 0) {
return this.finishProposalSubmit(() => {
this.$refs.proposalInfoRef.onClose()
this.$toast.success(res.msg)
this.doSearch()
})
}
})
}) })
}).then((res) => { .catch(() => {})
if (res.code === 0) { } catch (error) {}
this.$refs.proposalInfoRef.onClose() })
},
// row 提供当前记录的流程任务 ID;确认与请求共用办理锁,离开页面后不再刷新旧表格。
onRevoke(row) {
return this.runProposalSubmit("onRevoke", () => {
return this.proposalConfirm({
title: "提示",
message: "您确定要撤回吗?"
}).then(() => {
if (this.proposalDisposed) return
return this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
// code 为 0 表示撤回成功;已销毁页面不提示、不访问失效的组件引用。
if (res.code === 0 && !this.proposalDisposed) {
this.$toast.success(res.msg) this.$toast.success(res.msg)
this.doSearch() this.doSearch()
} }
}) })
}).catch(() => {
})
} catch (error) {
}
},
onRevoke(row){
this.$dialog.confirm({
title: "提示",
message: "您确定要撤回吗?"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
this.doSearch()
}
}) })
}) })
}, },
doSearch() { doSearch() {
this.$nextTick(() => { this.$nextTick(() => {
// nextTick 执行前页面可能已被 PJAX 替换,不能访问已销毁的表格。
if (this.proposalDisposed || !this.$refs.tableListRef) return
this.pageForm.pageNumber = 1 this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0 this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch() this.$refs.tableListRef.doSearch()
@@ -62,7 +62,7 @@ layout("/layouts/platform_h5.html"){
required required
is-link is-link
@click="showFeedBackPicker = true" @click="showFeedBackPicker = true"
></van-field> :disabled="$root.proposalSubmitting"></van-field>
<van-popup v-model="showFeedBackPicker" position="bottom"> <van-popup v-model="showFeedBackPicker" position="bottom">
<van-picker <van-picker
show-toolbar show-toolbar
@@ -81,7 +81,7 @@ layout("/layouts/platform_h5.html"){
required required
maxlength="100" maxlength="100"
show-word-limit show-word-limit
></van-field> :disabled="$root.proposalSubmitting"></van-field>
<template v-if="['SATISFIED','FAIRLY_SATISFIED'].includes(formData.tf_feedback)"> <template v-if="['SATISFIED','FAIRLY_SATISFIED'].includes(formData.tf_feedback)">
<van-field <van-field
@@ -92,7 +92,7 @@ layout("/layouts/platform_h5.html"){
:rules="[{ required: true, message: '请输入通讯地址' }]" :rules="[{ required: true, message: '请输入通讯地址' }]"
required required
show-word-limit show-word-limit
></van-field> :disabled="$root.proposalSubmitting"></van-field>
<!--联系电话--> <!--联系电话-->
<van-field <van-field
v-model="formData.tf_phone" v-model="formData.tf_phone"
@@ -102,7 +102,7 @@ layout("/layouts/platform_h5.html"){
:rules="[{ required: true, message: '请输入联系电话' }]" :rules="[{ required: true, message: '请输入联系电话' }]"
required required
show-word-limit show-word-limit
></van-field> :disabled="$root.proposalSubmitting"></van-field>
<!--邮政编码--> <!--邮政编码-->
<van-field <van-field
v-model="formData.tf_postcode" v-model="formData.tf_postcode"
@@ -112,24 +112,29 @@ layout("/layouts/platform_h5.html"){
:rules="[{ required: true, message: '请输入邮政编码' }]" :rules="[{ required: true, message: '请输入邮政编码' }]"
required required
show-word-limit show-word-limit
></van-field> :disabled="$root.proposalSubmitting"></van-field>
</template> </template>
</van-form> </van-form>
<div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px"> <div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px">
<van-button type="danger" block @click="$refs.proposalInfoRef.onClose()">取消</van-button> <van-button type="danger" block @click="$refs.proposalInfoRef.onClose()" :disabled="$root.proposalSubmitting">取消</van-button>
<van-button type="primary" block @click="handleTaskAction(1)">提交</van-button> <van-button type="primary" block @click="handleTaskAction(1)" :loading="formLoading && formAction === ('handleTaskAction:' + 1)" loading-text="提交中…" :disabled="$root.proposalSubmitting">提交</van-button>
</div> </div>
</div> </div>
</proposal-info> </proposal-info>
</div> </div>
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
<!--#include("/platform/zhgh/democratic/proposal/common/submit.js"){}#-->
<!--#include("../../common/info.js"){}#--> <!--#include("../../common/info.js"){}#-->
const vue = new Vue({ const vue = new Vue({
el: "#app", el: "#app",
dicts: ["PROPOSAL_FEEDBACK"], dicts: ["PROPOSAL_FEEDBACK"],
store, store,
proposalH5: true,
mixins: [PROPOSAL_SUBMIT_MIXIN],
proposalPopupFields: ["showFeedBackPicker"],
data() { data() {
return { return {
pageForm: { pageForm: {
@@ -174,7 +179,8 @@ layout("/layouts/platform_h5.html"){
}, },
onView(row) { onView(row) {
this.showApprovalForm = false if (this.$root.proposalSubmitting) return
this.$set(this, "showApprovalForm", false)
this.$refs.proposalInfoRef.onOpen(row) this.$refs.proposalInfoRef.onOpen(row)
}, },
@@ -194,66 +200,72 @@ layout("/layouts/platform_h5.html"){
this.showFeedBackPicker = false this.showFeedBackPicker = false
}, },
async handleTaskAction(val) { handleTaskAction(val) {
try { return this.runProposalSubmit("handleTaskAction" + ":" + val, async () => {
await this.$refs.formRef.validate(); try {
this.$dialog.confirm({ await this.$refs.formRef.validate()
return this.proposalConfirm({
title: "提示",
message: "您确定要提交吗?"
})
.then(() => {
const formData = {
...this.formData,
submitType: val
}
const lookup =
this.formData.tf_feedback === "DISSATISFIED"
? this.getCaseInfo(this.formData.instanceId).then((caseInfo) => {
formData.tf_masterUnitId = caseInfo.tf_masterUnitId
})
: Promise.resolve()
return lookup.then(() => {
return this.$axios
.post("/flow/common/executeTask", {
data: JSON.stringify(formData)
})
.then((res) => {
if (res.code === 0) {
return this.finishProposalSubmit(() => {
this.$refs.proposalInfoRef.onClose()
this.$toast.success(res.msg)
this.doSearch()
})
}
})
})
})
.catch(() => {})
} catch (error) {}
})
},
// 获取立案信息
getCaseInfo(instId) {
return this.$axios.post("/platform/proposal/feedbackEvaluation/caseInfo", { instId }).then((res) => res.data)
},
// row 提供当前记录的流程任务 ID;确认与请求共用办理锁,离开页面后不再刷新旧表格。
onRevoke(row) {
return this.runProposalSubmit("onRevoke", () => {
return this.proposalConfirm({
title: "提示", title: "提示",
message: "您确定要提交吗?" message: "您确定要撤回吗?"
}).then(async () => { }).then(() => {
debugger if (this.proposalDisposed) return
const formData = { return this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
...this.formData, // code 为 0 表示撤回成功;已销毁页面不提示、不访问失效的组件引用。
submitType: val if (res.code === 0 && !this.proposalDisposed) {
}
// 不满意
if (this.formData.tf_feedback === 'DISSATISFIED') {
const caseInfo = await this.getCaseInfo(this.formData.instanceId)
formData.tf_masterUnitId = caseInfo.tf_masterUnitId
}
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify(formData)
}).then((res) => {
if (res.code === 0) {
this.$refs.proposalInfoRef.onClose()
this.$toast.success(res.msg) this.$toast.success(res.msg)
this.doSearch() this.doSearch()
} }
}) })
}).catch(() => {
})
} catch (error) {
}
},
// 获取立案信息
async getCaseInfo(instId) {
const {
data,
code
} = await this.$axios.post('/platform/proposal/feedbackEvaluation/caseInfo', {instId})
if (code === 0) {
return data
}
},
onRevoke(row) {
this.$dialog.confirm({
title: "提示",
message: "您确定要撤回吗?"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
this.doSearch()
}
}) })
}) })
}, },
doSearch() { doSearch() {
this.$nextTick(() => { this.$nextTick(() => {
// nextTick 执行前页面可能已被 PJAX 替换,不能访问已销毁的表格。
if (this.proposalDisposed || !this.$refs.tableListRef) return
this.pageForm.pageNumber = 1 this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0 this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch() this.$refs.tableListRef.doSearch()
@@ -61,16 +61,20 @@ layout("/layouts/platform_h5.html"){
</div> </div>
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
<!--#include("/platform/zhgh/democratic/proposal/common/submit.js"){}#-->
<!--#include("../../common/info.js"){}#--> <!--#include("../../common/info.js"){}#-->
<!--#include("inviteSeconder.js"){}#--> <!--#include("inviteSeconder.js"){}#-->
const vue = new Vue({ const vue = new Vue({
el: "#app", el: "#app",
store, store,
proposalH5: true,
components: { components: {
"invite-seconder": PROPOSAL_INVITE_SECONDER_COMPONENT, "invite-seconder": PROPOSAL_INVITE_SECONDER_COMPONENT,
"proposal-info": PROPOSAL_INFO "proposal-info": PROPOSAL_INFO
}, },
mixins: [PROPOSAL_SUBMIT_MIXIN],
data() { data() {
return { return {
pageForm: { pageForm: {
@@ -109,36 +113,42 @@ layout("/layouts/platform_h5.html"){
}, },
onEdit(row) { onEdit(row) {
if (this.$root.proposalSubmitting) return
this.$pjaxReplace("/platform/proposal/write/h5?bizId=" + row.id + "&taskId=" + (row.startTaskId || '')) this.$pjaxReplace("/platform/proposal/write/h5?bizId=" + row.id + "&taskId=" + (row.startTaskId || ''))
}, },
doSearch() { doSearch() {
this.$nextTick(() => { this.$nextTick(() => {
// nextTick 执行前页面可能已被 PJAX 替换,不能访问已销毁的表格。
if (this.proposalDisposed || !this.$refs.tableListRef) return
this.pageForm.pageNumber = 1 this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0 this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch() this.$refs.tableListRef.doSearch()
}) })
}, },
// row 提供当前记录的流程任务 ID;确认与请求共用办理锁,离开页面后不再刷新旧表格。
onRevoke(row) { onRevoke(row) {
this.$dialog return this.runProposalSubmit("onRevoke", () => {
.confirm({ return this.proposalConfirm({
title: "提示", title: "提示",
message: "您确定要撤销申请吗?" message: "您确定要撤销申请吗?"
}) }).then(() => {
.then(() => { if (this.proposalDisposed) return
this.$axios.post("/flow/common/revokeTask", {taskId: row.startTaskId}).then((res) => { return this.$axios.post("/flow/common/revokeTask", {taskId: row.startTaskId}).then((res) => {
if(res.code===0){ // code 为 0 表示撤回成功;已销毁页面不提示、不访问失效的组件引用。
if (res.code === 0 && !this.proposalDisposed) {
this.$toast.success(res.msg) this.$toast.success(res.msg)
this.doSearch() this.doSearch()
} }
}) })
}) })
})
}, },
onDelete(id) { onDelete(id) {
this.$dialog if (this.$root.proposalSubmitting) return
.confirm({ this.proposalConfirm({
title: "提示", title: "提示",
message: "您确定要删除吗?" message: "您确定要删除吗?"
}) })
@@ -153,6 +163,7 @@ layout("/layouts/platform_h5.html"){
}, },
onInvite(row) { onInvite(row) {
if (this.$root.proposalSubmitting) return
this.$axios.post("/platform/proposal/mine/inviteCheck", {id: row.id}).then((res) => { this.$axios.post("/platform/proposal/mine/inviteCheck", {id: row.id}).then((res) => {
if (res.code === 0) { if (res.code === 0) {
this.$refs.inviteSeconderRef.onOpen(row) this.$refs.inviteSeconderRef.onOpen(row)
@@ -41,12 +41,14 @@ const PROPOSAL_INVITE_SECONDER_COMPONENT = {
:items-per-page="pageForm.pageSize" :items-per-page="pageForm.pageSize"
@change="pageData" @change="pageData"
></van-pagination> ></van-pagination>
<van-button @click="invite" type="primary" block :disabled="pageForm.isInvite" class="mt10">邀请</van-button> <van-button @click="invite" type="primary" block :disabled="(pageForm.isInvite) || $root.proposalSubmitting" class="mt10" :loading="formLoading && formAction === ('invite')" loading-text="提交中…">邀请</van-button>
</div> </div>
</van-checkbox-group> </van-checkbox-group>
<van-empty v-else :figure="2"></van-empty> <van-empty v-else :figure="2"></van-empty>
</van-action-sheet> </van-action-sheet>
`, `,
mixins: [PROPOSAL_SUBMIT_MIXIN],
proposalPopupFields: ["visible"],
data() { data() {
return { return {
visible: false, visible: false,
@@ -77,34 +79,38 @@ const PROPOSAL_INVITE_SECONDER_COMPONENT = {
detail(id) { detail(id) {
}, },
invite() { invite() {
if (this.tableSelection.length === 0) { return this.runProposalSubmit("invite", () => {
this.$toast("请先选择附议人后在点击邀请") if (this.tableSelection.length === 0) {
return this.$toast("请先选择附议人后在点击邀请")
} return
}
const loginNames = [...new Set(this.tableSelection.map((s) => s.loginName))] const loginNames = [...new Set(this.tableSelection.map((s) => s.loginName))]
const userName = [...new Set(this.tableSelection.map((s) => s.userName))] const userName = [...new Set(this.tableSelection.map((s) => s.userName))]
console.log(this.tableSelection) console.log(this.tableSelection)
this.$dialog.confirm({ return this.proposalConfirm({
title: '提示', title: "提示",
message: "您确定要邀请" + userName.join("、") + "代表附议吗?", message: "您确定要邀请" + userName.join("、") + "代表附议吗?"
}).then(() => {
this.$axios.post("/platform/proposal/mine/inviteSeconder", {
proposalId: this.record.id,
seconders: JSON.stringify(loginNames)
}).then((res) => {
if (res.code === 0) {
this.pageData()
this.$toast.success(res.msg)
this.tableSelection = []
// this.visible = false
this.$emit("refresh", null)
}
}) })
}).catch(() => { .then(() => {
return this.$axios
.post("/platform/proposal/mine/inviteSeconder", {
proposalId: this.record.id,
seconders: JSON.stringify(loginNames)
})
.then((res) => {
if (res.code === 0) {
this.pageData()
this.$toast.success(res.msg)
this.$set(this, "tableSelection", [])
// this.visible = false
this.$emit("refresh", null)
}
})
})
.catch(() => {})
}) })
}, },
pageData() { pageData() {
@@ -63,22 +63,26 @@ layout("/layouts/platform_h5.html"){
required required
maxlength="100" maxlength="100"
show-word-limit show-word-limit
></van-field> :disabled="$root.proposalSubmitting"></van-field>
</van-form> </van-form>
<div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px"> <div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px">
<van-button type="danger" block @click="handleTaskAction(20)">不同意</van-button> <van-button type="danger" block @click="handleTaskAction(20)" :loading="formLoading && formAction === ('handleTaskAction:' + 20)" loading-text="提交中…" :disabled="$root.proposalSubmitting">不同意</van-button>
<van-button type="primary" block @click="handleTaskAction(1)">同意</van-button> <van-button type="primary" block @click="handleTaskAction(1)" :loading="formLoading && formAction === ('handleTaskAction:' + 1)" loading-text="提交中…" :disabled="$root.proposalSubmitting">同意</van-button>
</div> </div>
</div> </div>
</proposal-info> </proposal-info>
</div> </div>
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
<!--#include("/platform/zhgh/democratic/proposal/common/submit.js"){}#-->
<!--#include("../../common/info.js"){}#--> <!--#include("../../common/info.js"){}#-->
const vue = new Vue({ const vue = new Vue({
el: "#app", el: "#app",
store, store,
proposalH5: true,
mixins: [PROPOSAL_SUBMIT_MIXIN],
data() { data() {
return { return {
pageForm: { pageForm: {
@@ -154,7 +158,8 @@ layout("/layouts/platform_h5.html"){
}, },
onView(row) { onView(row) {
this.showApprovalForm = false if (this.$root.proposalSubmitting) return
this.$set(this, "showApprovalForm", false)
this.$refs.proposalInfoRef.onOpen(row) this.$refs.proposalInfoRef.onOpen(row)
}, },
@@ -185,26 +190,34 @@ layout("/layouts/platform_h5.html"){
}) })
}, },
async handleTaskAction(val) { handleTaskAction(val) {
try { return this.runProposalSubmit("handleTaskAction" + ":" + val, async () => {
await this.$refs.formRef.validate(); try {
this.$dialog.confirm({ await this.$refs.formRef.validate()
title: "提示", return this.proposalConfirm({
message: "您确定要提交吗?" title: "提示",
}).then(() => { message: "您确定要提交吗?"
this.$axios.post("/platform/proposal/positiveSeconded/handle", {
proposalId: this.row.id,
opinion: this.formData.tf_opinion,
submitType: val,
}).then((res) => {
if (res.code === 0) {
this.$refs.proposalInfoRef.onClose()
this.$toast.success(res.msg)
this.doSearch()
}
}) })
}).catch(() => {}) .then(() => {
} catch (error) {} return this.$axios
.post("/platform/proposal/positiveSeconded/handle", {
proposalId: this.row.id,
opinion: this.formData.tf_opinion,
submitType: val
})
.then((res) => {
if (res.code === 0) {
return this.finishProposalSubmit(() => {
this.$refs.proposalInfoRef.onClose()
this.$toast.success(res.msg)
this.doSearch()
})
}
})
})
.catch(() => {})
} catch (error) {}
})
}, },
doSearch() { doSearch() {
@@ -62,22 +62,26 @@ layout("/layouts/platform_h5.html"){
required required
maxlength="100" maxlength="100"
show-word-limit show-word-limit
></van-field> :disabled="$root.proposalSubmitting"></van-field>
</van-form> </van-form>
<div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px"> <div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px">
<van-button v-if="isSchoolLeaderTask()" type="danger" block :loading="submitLoading" @click="handleTaskAction('back')">退回答复</van-button> <van-button v-if="isSchoolLeaderTask()" type="danger" block @click="handleTaskAction('back')" :loading="formLoading && formAction === ('handleTaskAction:' + 'back')" loading-text="提交中…" :disabled="$root.proposalSubmitting">退回答复</van-button>
<van-button type="primary" block :loading="submitLoading" @click="handleTaskAction('agree')">{{submitButtonText()}}</van-button> <van-button type="primary" block @click="handleTaskAction('agree')" :loading="formLoading && formAction === ('handleTaskAction:' + 'agree')" loading-text="提交中…" :disabled="$root.proposalSubmitting">{{submitButtonText()}}</van-button>
</div> </div>
</div> </div>
</proposal-info> </proposal-info>
</div> </div>
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
<!--#include("/platform/zhgh/democratic/proposal/common/submit.js"){}#-->
<!--#include("../../common/info.js"){}#--> <!--#include("../../common/info.js"){}#-->
const vue = new Vue({ const vue = new Vue({
el: "#app", el: "#app",
store, store,
proposalH5: true,
mixins: [PROPOSAL_SUBMIT_MIXIN],
data() { data() {
return { return {
pageForm: { pageForm: {
@@ -92,7 +96,7 @@ layout("/layouts/platform_h5.html"){
sessionOptions: [], sessionOptions: [],
formData: {}, formData: {},
submitLoading: false,
showApprovalForm: false showApprovalForm: false
} }
}, },
@@ -121,6 +125,7 @@ layout("/layouts/platform_h5.html"){
}, },
onView(row) { onView(row) {
if (this.$root.proposalSubmitting) return
this.$set(this, "showApprovalForm", false) this.$set(this, "showApprovalForm", false)
this.$refs.proposalInfoRef.onOpen(row) this.$refs.proposalInfoRef.onOpen(row)
}, },
@@ -148,60 +153,64 @@ layout("/layouts/platform_h5.html"){
return this.isInstructionTask() ? "提交批示" : "同意答复" return this.isInstructionTask() ? "提交批示" : "同意答复"
}, },
async handleTaskAction(val) { handleTaskAction(val) {
if (this.submitLoading) { return this.runProposalSubmit("handleTaskAction" + ":" + val, async () => {
return try {
} await this.$refs.formRef.validate()
try { return this.proposalConfirm({
await this.$refs.formRef.validate(); title: "提示",
this.$dialog.confirm({ message: "您确定要提交吗?"
})
.then(() => {
const formData = {
...this.formData,
tf_approval: val
}
delete formData.taskKey
delete formData.taskName
return this.$axios
.post("/platform/proposal/schoolLeaderApproval/executeTask", {
data: JSON.stringify(formData)
})
.then((res) => {
if (res.code === 0) {
return this.finishProposalSubmit(() => {
this.$refs.proposalInfoRef.onClose()
this.$toast.success(res.msg)
this.doSearch()
})
}
})
})
.catch(() => {})
} catch (error) {}
})
},
// row 提供当前记录的流程任务 ID;确认与请求共用办理锁,离开页面后不再刷新旧表格。
onRevoke(row) {
return this.runProposalSubmit("onRevoke", () => {
return this.proposalConfirm({
title: "提示", title: "提示",
message: "您确定要提交吗?" message: "您确定要撤回吗?"
}).then(() => { }).then(() => {
if (this.proposalDisposed) return
const formData = { return this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
...this.formData, // code 为 0 表示撤回成功;已销毁页面不提示、不访问失效的组件引用。
tf_approval: val if (res.code === 0 && !this.proposalDisposed) {
}
delete formData.taskKey
delete formData.taskName
this.$set(this, "submitLoading", true)
this.$axios.post("/platform/proposal/schoolLeaderApproval/executeTask", {
data: JSON.stringify(formData)
}).then((res) => {
if (res.code === 0) {
this.$refs.proposalInfoRef.onClose()
this.$toast.success(res.msg) this.$toast.success(res.msg)
this.doSearch() this.doSearch()
} }
}).finally(() => {
this.$set(this, "submitLoading", false)
}) })
}).catch(() => {
})
} catch (error) {
}
},
onRevoke(row){
this.$dialog.confirm({
title: "提示",
message: "您确定要撤回吗?"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
this.doSearch()
}
}) })
}) })
}, },
doSearch() { doSearch() {
this.$nextTick(() => { this.$nextTick(() => {
// nextTick 执行前页面可能已被 PJAX 替换,不能访问已销毁的表格。
if (this.proposalDisposed || !this.$refs.tableListRef) return
this.pageForm.pageNumber = 1 this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0 this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch() this.$refs.tableListRef.doSearch()
@@ -73,25 +73,29 @@ layout("/layouts/platform_h5.html"){
required required
maxlength="100" maxlength="100"
show-word-limit show-word-limit
></van-field> :disabled="$root.proposalSubmitting"></van-field>
<!-- <van-field v-if="false" label="签字" name="approvalSignature" v-model="formData.signature" required class="direction-column-field">--> <!-- <van-field v-if="false" label="签字" name="approvalSignature" v-model="formData.signature" required class="direction-column-field">-->
<!-- <h5-signature v-if="false" v-model="formData.approvalSignature" slot="input"></h5-signature>--> <!-- <h5-signature v-if="false" v-model="formData.approvalSignature" slot="input"></h5-signature>-->
<!-- </van-field>--> <!-- </van-field>-->
</van-form> </van-form>
<div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px"> <div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px">
<van-button type="danger" block @click="handleTaskAction(20)">不同意</van-button> <van-button type="danger" block @click="handleTaskAction(20)" :loading="formLoading && formAction === ('handleTaskAction:' + 20)" loading-text="提交中…" :disabled="$root.proposalSubmitting">不同意</van-button>
<van-button type="primary" block @click="handleTaskAction(1)">同意</van-button> <van-button type="primary" block @click="handleTaskAction(1)" :loading="formLoading && formAction === ('handleTaskAction:' + 1)" loading-text="提交中…" :disabled="$root.proposalSubmitting">同意</van-button>
</div> </div>
</div> </div>
</proposal-info> </proposal-info>
</div> </div>
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
<!--#include("/platform/zhgh/democratic/proposal/common/submit.js"){}#-->
<!--#include("../../common/info.js"){}#--> <!--#include("../../common/info.js"){}#-->
const vue = new Vue({ const vue = new Vue({
el: "#app", el: "#app",
store, store,
proposalH5: true,
mixins: [PROPOSAL_SUBMIT_MIXIN],
data() { data() {
return { return {
activeTab: "inviteSeconded", activeTab: "inviteSeconded",
@@ -217,6 +221,7 @@ layout("/layouts/platform_h5.html"){
}, },
onView(row) { onView(row) {
if (this.$root.proposalSubmitting) return
this.$set(this, "showApprovalForm", false) this.$set(this, "showApprovalForm", false)
this.$refs.proposalInfoRef.onOpen(row) this.$refs.proposalInfoRef.onOpen(row)
}, },
@@ -258,63 +263,77 @@ layout("/layouts/platform_h5.html"){
}) })
}, },
async handleTaskAction(val) { handleTaskAction(val) {
try { return this.runProposalSubmit("handleTaskAction" + ":" + val, async () => {
await this.$refs.formRef.validate() try {
this.$dialog.confirm({ await this.$refs.formRef.validate()
title: "提示", return this.proposalConfirm({
message: "您确定要提交吗?" title: "提示",
}).then(() => { message: "您确定要提交吗?"
if (this.activeTab === "inviteSeconded") { })
this.handleInviteSeconded(val) .then(() => {
} else { if (this.activeTab === "inviteSeconded") {
this.handlePositiveSeconded(val) return this.handleInviteSeconded(val)
} } else {
}).catch(() => { return this.handlePositiveSeconded(val)
}
}) })
} catch (error) { .catch(() => {})
} catch (error) {}
} })
}, },
// 受邀附议先走流程任务提交,再回写附议结果,与 PC 端保持一致。 // 受邀附议先走流程任务提交,再回写附议结果,与 PC 端保持一致。
handleInviteSeconded(val) { handleInviteSeconded(val) {
this.$axios.post("/flow/common/executeTask", { return this.$axios
data: JSON.stringify({ .post("/flow/common/executeTask", {
...this.formData, data: JSON.stringify({ ...this.formData, submitType: val })
submitType: val })
.then((res) => {
// WF 已办理后只回写附议结果;第二步失败不得再次执行已完成的 WF 任务。
return this.updateSecond(val)
.then(() => {
return this.finishProposalSubmit(() => {
this.$refs.proposalInfoRef.onClose()
this.$toast.success(res.msg)
this.doSearch()
})
})
.catch((error) => {
return this.finishProposalSubmit(() => {
this.$refs.proposalInfoRef.onClose()
this.$toast.fail("流程已办理,但附议结果同步失败,请刷新核对,勿重复提交")
this.doSearch()
throw error
})
})
}) })
}).then((res) => {
if (res.code === 0) {
this.$refs.proposalInfoRef.onClose()
this.$toast.success(res.msg)
this.doSearch()
this.updateSecond(val)
}
})
}, },
handlePositiveSeconded(val) { handlePositiveSeconded(val) {
this.$axios.post("/platform/proposal/positiveSeconded/handle", { return this.$axios
proposalId: this.row.id, .post("/platform/proposal/positiveSeconded/handle", {
opinion: this.formData.tf_opinion, proposalId: this.row.id,
submitType: val opinion: this.formData.tf_opinion,
}).then((res) => { submitType: val
if (res.code === 0) { })
this.$refs.proposalInfoRef.onClose() .then((res) => {
this.$toast.success(res.msg) if (res.code === 0) {
this.doSearch() return this.finishProposalSubmit(() => {
} this.$refs.proposalInfoRef.onClose()
}) this.$toast.success(res.msg)
this.doSearch()
})
}
})
}, },
updateSecond(submitType) { updateSecond(submitType) {
this.$axios.post("/platform/proposal/seconded/updateInfo", { return this.$axios.post("/platform/proposal/seconded/updateInfo", {
proposalId: this.row.id, proposalId: this.row.id,
taskActorUserId: this.row.taskActorUserId, taskActorUserId: this.row.taskActorUserId,
opinion: this.formData.tf_opinion, opinion: this.formData.tf_opinion,
submitType: submitType, submitType: submitType
}) })
}, },
@@ -70,7 +70,7 @@ layout("/layouts/platform_h5.html"){
required required
is-link is-link
@click="showPicker = true" @click="showPicker = true"
></van-field> :disabled="$root.proposalSubmitting"></van-field>
<van-popup v-model="showPicker" position="bottom"> <van-popup v-model="showPicker" position="bottom">
<van-picker <van-picker
show-toolbar show-toolbar
@@ -87,11 +87,11 @@ layout("/layouts/platform_h5.html"){
:rules="[{ required: true, message: '必填' }]" :rules="[{ required: true, message: '必填' }]"
required required
show-word-limit show-word-limit
></van-field> :disabled="$root.proposalSubmitting"></van-field>
</van-form> </van-form>
<div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px"> <div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px">
<van-button block @click="">取消</van-button> <van-button block @click="" :disabled="$root.proposalSubmitting">取消</van-button>
<van-button type="primary" block @click="doSubmit">提交</van-button> <van-button type="primary" block @click="doSubmit" :loading="formLoading && formAction === ('doSubmit')" loading-text="提交中…" :disabled="$root.proposalSubmitting">提交</van-button>
</div> </div>
</div> </div>
</proposal-info> </proposal-info>
@@ -103,7 +103,7 @@ layout("/layouts/platform_h5.html"){
<div style="display: flex; justify-content: space-between; align-items: center"> <div style="display: flex; justify-content: space-between; align-items: center">
<div>{{ '意见' + (index + 1) }}</div> <div>{{ '意见' + (index + 1) }}</div>
<div> <div>
<van-button type="danger" @click="onDelete(item)" size="small">删除</van-button> <van-button type="danger" @click="onDelete(item)" size="small" :disabled="$root.proposalSubmitting">删除</van-button>
</div> </div>
</div> </div>
</template> </template>
@@ -120,14 +120,19 @@ layout("/layouts/platform_h5.html"){
</div> </div>
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
<!--#include("/platform/zhgh/democratic/proposal/common/submit.js"){}#-->
<!--#include("../../common/info.js"){}#--> <!--#include("../../common/info.js"){}#-->
new Vue({ new Vue({
el: "#app", el: "#app",
store, store,
proposalH5: true,
dicts: ["UNDERTAKE_SUGGESTION"], dicts: ["UNDERTAKE_SUGGESTION"],
components: { components: {
"proposal-info": PROPOSAL_INFO "proposal-info": PROPOSAL_INFO
}, },
mixins: [PROPOSAL_SUBMIT_MIXIN],
proposalPopupFields: ["showPicker", "visible"],
data() { data() {
return { return {
pageForm: { pageForm: {
@@ -151,7 +156,8 @@ layout("/layouts/platform_h5.html"){
}, },
methods: { methods: {
onDelete(row) { onDelete(row) {
this.$dialog.confirm({ if (this.$root.proposalSubmitting) return
this.proposalConfirm({
title: "提示", title: "提示",
message: "您确定要删除吗?" message: "您确定要删除吗?"
}).then(() => { }).then(() => {
@@ -203,32 +209,39 @@ layout("/layouts/platform_h5.html"){
}) })
}, },
onAudit(row) { onAudit(row) {
this.showApprovalForm = true if (this.$root.proposalSubmitting) return
this.$set(this, "showApprovalForm", true)
this.$refs.proposalInfoRef.onOpen(row) this.$refs.proposalInfoRef.onOpen(row)
this.formData = { this.formData = {
proposalId: row.id, proposalId: row.id
} }
}, },
async doSubmit() { doSubmit() {
try { return this.runProposalSubmit("doSubmit", async () => {
await this.$refs.formRef.validate() try {
this.$dialog.confirm({ await this.$refs.formRef.validate()
title: "提示", return this.proposalConfirm({
message: "您确定要提交吗?" title: "提示",
}).then(() => { message: "您确定要提交吗?"
this.$axios.post("/platform/proposal/suggestion/suggest", this.formData) })
.then((res) => { .then(() => {
if (res.code === 0) { return this.$axios.post("/platform/proposal/suggestion/suggest", this.formData).then((res) => {
this.$refs.proposalInfoRef.onClose() if (res.code === 0) {
this.$toast.success(res.msg) return this.finishProposalSubmit(() => {
this.doSearch() this.$refs.proposalInfoRef.onClose()
} this.$toast.success(res.msg)
this.doSearch()
})
}
})
}) })
}).catch(() => {}) .catch(() => {})
} catch (error) {} } catch (error) {}
})
}, },
onView(row) { onView(row) {
this.showApprovalForm = false if (this.$root.proposalSubmitting) return
this.$set(this, "showApprovalForm", false)
this.$refs.proposalInfoRef.onOpen(row) this.$refs.proposalInfoRef.onOpen(row)
}, },
doSearch() { doSearch() {
@@ -65,7 +65,7 @@ layout("/layouts/platform_h5.html"){
<van-form ref="formRef"> <van-form ref="formRef">
<van-field :value="formData.underTakeName" <van-field :value="formData.underTakeName"
label="承办单位" label="承办单位"
readonly></van-field> readonly :disabled="$root.proposalSubmitting"></van-field>
<van-field <van-field
v-model="formData.tf_implementStateName" v-model="formData.tf_implementStateName"
@@ -76,7 +76,7 @@ layout("/layouts/platform_h5.html"){
required required
is-link is-link
@click="showImplementPicker = true" @click="showImplementPicker = true"
></van-field> :disabled="$root.proposalSubmitting"></van-field>
<van-popup v-model="showImplementPicker" position="bottom"> <van-popup v-model="showImplementPicker" position="bottom">
<van-picker <van-picker
show-toolbar show-toolbar
@@ -95,7 +95,7 @@ layout("/layouts/platform_h5.html"){
required required
maxlength="100" maxlength="100"
show-word-limit show-word-limit
></van-field> :disabled="$root.proposalSubmitting"></van-field>
<van-field <van-field
v-if="supportCandidate && formData.underTakeIsMaster" v-if="supportCandidate && formData.underTakeIsMaster"
@@ -107,7 +107,7 @@ layout("/layouts/platform_h5.html"){
required required
is-link is-link
@click="showCandidatesPicker = true" @click="showCandidatesPicker = true"
></van-field> :disabled="$root.proposalSubmitting"></van-field>
<van-popup v-model="showCandidatesPicker" position="bottom"> <van-popup v-model="showCandidatesPicker" position="bottom">
<van-picker <van-picker
show-toolbar show-toolbar
@@ -119,22 +119,27 @@ layout("/layouts/platform_h5.html"){
</van-form> </van-form>
<div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px"> <div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px">
<van-button block @click="$refs.proposalInfoRef.onClose()">取消</van-button> <van-button block @click="$refs.proposalInfoRef.onClose()" :disabled="$root.proposalSubmitting">取消</van-button>
<van-button type="primary" block @click="handleTaskAction(1)">提交</van-button> <van-button type="primary" block @click="handleTaskAction(1)" :loading="formLoading && formAction === ('handleTaskAction:' + 1)" loading-text="提交中…" :disabled="$root.proposalSubmitting">提交</van-button>
</div> </div>
</div> </div>
</proposal-info> </proposal-info>
<transfer ref="transferRef"></transfer> <transfer ref="transferRef" @refresh="doSearch"></transfer>
</div> </div>
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
<!--#include("/platform/zhgh/democratic/proposal/common/submit.js"){}#-->
<!--#include("../../common/info.js"){}#--> <!--#include("../../common/info.js"){}#-->
<!--#include("transfer.js"){}#--> <!--#include("transfer.js"){}#-->
const vue = new Vue({ const vue = new Vue({
el: "#app", el: "#app",
store, store,
proposalH5: true,
dicts: ['PROPOSAL_REPLY_IMPLEMENT'], dicts: ['PROPOSAL_REPLY_IMPLEMENT'],
mixins: [PROPOSAL_SUBMIT_MIXIN],
proposalPopupFields: ["showImplementPicker", "showCandidatesPicker"],
data() { data() {
return { return {
pageForm: { pageForm: {
@@ -185,7 +190,8 @@ layout("/layouts/platform_h5.html"){
}, },
onView(row) { onView(row) {
this.showApprovalForm = false if (this.$root.proposalSubmitting) return
this.$set(this, "showApprovalForm", false)
this.$refs.proposalInfoRef.onOpen(row) this.$refs.proposalInfoRef.onOpen(row)
}, },
@@ -226,56 +232,68 @@ layout("/layouts/platform_h5.html"){
this.showCandidatesPicker = false this.showCandidatesPicker = false
}, },
async handleTaskAction(val) { handleTaskAction(val) {
try { return this.runProposalSubmit("handleTaskAction" + ":" + val, async () => {
await this.$refs.formRef.validate(); try {
this.$dialog.confirm({ await this.$refs.formRef.validate()
title: "提示", return this.proposalConfirm({
message: "您确定要提交吗?" title: "提示",
}).then(() => { message: "您确定要提交吗?"
delete this.formData.underTakeIsMaster })
delete this.formData.underTakeName .then(() => {
this.$axios.post("/flow/common/executeTask", { delete this.formData.underTakeIsMaster
data: JSON.stringify({ delete this.formData.underTakeName
...this.formData, return this.$axios
submitType: val .post("/flow/common/executeTask", {
data: JSON.stringify({
...this.formData,
submitType: val
})
})
.then((res) => {
if (res.code === 0) {
return this.finishProposalSubmit(() => {
this.$refs.proposalInfoRef.onClose()
this.$toast.success(res.msg)
this.doSearch()
})
}
})
}) })
}).then((res) => { .catch(() => {})
if (res.code === 0) { } catch (error) {}
this.$refs.proposalInfoRef.onClose() })
},
// row 提供当前记录的流程任务 ID;确认与请求共用办理锁,离开页面后不再刷新旧表格。
onRevoke(row) {
return this.runProposalSubmit("onRevoke", () => {
return this.proposalConfirm({
title: "提示",
message: "您确定要撤回吗?"
}).then(() => {
if (this.proposalDisposed) return
return this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
// code 为 0 表示撤回成功;已销毁页面不提示、不访问失效的组件引用。
if (res.code === 0 && !this.proposalDisposed) {
this.$toast.success(res.msg) this.$toast.success(res.msg)
this.doSearch() this.doSearch()
} }
}) })
}).catch(() => {
})
} catch (error) {
}
},
onRevoke(row) {
this.$dialog.confirm({
title: "提示",
message: "您确定要撤回吗?"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
this.doSearch()
}
}) })
}) })
}, },
// 打开转办 // 打开转办
openTransfer(row){ openTransfer(row) {
if (this.$root.proposalSubmitting) return
this.$refs.transferRef.openTransfer(row) this.$refs.transferRef.openTransfer(row)
}, },
doSearch() { doSearch() {
this.$nextTick(() => { this.$nextTick(() => {
// nextTick 执行前页面可能已被 PJAX 替换,不能访问已销毁的表格。
if (this.proposalDisposed || !this.$refs.tableListRef) return
this.pageForm.pageNumber = 1 this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0 this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch() this.$refs.tableListRef.doSearch()
@@ -10,7 +10,7 @@ const transfer = {
</div> </div>
<!-- 用户选择 --> <!-- 用户选择 -->
<van-field v-model="searchKeyword" label="转交给" placeholder="搜索用户" required readonly @click="showUserList=true"></van-field> <van-field v-model="searchKeyword" label="转交给" placeholder="搜索用户" required readonly @click="showUserList=true" :disabled="$root.proposalSubmitting"></van-field>
<van-popup v-model="showUserList" position="bottom"> <van-popup v-model="showUserList" position="bottom">
<van-search v-model="keyword" placeholder="搜索用户" @search="selectTransferUser(keyword)" @cancel="showUserList=false"></van-search> <van-search v-model="keyword" placeholder="搜索用户" @search="selectTransferUser(keyword)" @cancel="showUserList=false"></van-search>
<van-empty v-if="transferUserOptions.length === 0" class="empty-tip">请搜索需要转办的用户</van-empty> <van-empty v-if="transferUserOptions.length === 0" class="empty-tip">请搜索需要转办的用户</van-empty>
@@ -19,12 +19,14 @@ const transfer = {
<!-- 底部按钮 --> <!-- 底部按钮 -->
<div class="button-group"> <div class="button-group">
<van-button block plain @click="showTransferDialog = false" class="cancel-btn">取消</van-button> <van-button block plain @click="$set(this, 'showTransferDialog', false)" class="cancel-btn" :disabled="$root.proposalSubmitting">取消</van-button>
<van-button block type="info" @click="handleTransfer" class="submit-btn">提交</van-button> <van-button block type="info" @click="handleTransfer" class="submit-btn" :loading="formLoading && formAction === ('handleTransfer')" loading-text="提交中…" :disabled="$root.proposalSubmitting">提交</van-button>
</div> </div>
</div> </div>
</van-action-sheet> </van-action-sheet>
`, `,
mixins: [PROPOSAL_SUBMIT_MIXIN],
proposalPopupFields: ["showTransferDialog", "showUserList"],
data() { data() {
return { return {
showTransferDialog: false, showTransferDialog: false,
@@ -37,9 +39,15 @@ const transfer = {
}, },
methods: { methods: {
openTransfer(row) { openTransfer(row) {
this.showTransferDialog = true if (this.$root.proposalSubmitting) return
this.transferForm = { taskId: row.taskId, name: row.name, code: row.code, delegationName: row.delegationName } this.$set(this, "showTransferDialog", true)
this.searchKeyword = '' this.$set(this, "transferForm", {
taskId: row.taskId,
name: row.name,
code: row.code,
delegationName: row.delegationName
})
this.$set(this, "searchKeyword", "")
}, },
selectUser(item) { selectUser(item) {
this.transferForm.userId = item.id this.transferForm.userId = item.id
@@ -54,29 +62,37 @@ const transfer = {
// 转办 // 转办
handleTransfer() { handleTransfer() {
if (!this.transferForm.userId) { return this.runProposalSubmit("handleTransfer", () => {
this.$toast('请选择转交用户') if (!this.transferForm.userId) {
return this.$toast("请选择转交用户")
} return
}
const transferUserName = this.transferUserOptions.find(item => item.id === this.transferForm.userId)?.username const transferUserName = this.transferUserOptions.find(
const name = this.transferForm.name (item) => item.id === this.transferForm.userId
)?.username
const name = this.transferForm.name
this.$dialog.confirm({ return this.proposalConfirm({
title: '提示', title: "提示",
message: `您确定要将` + name + `提案转交给` + transferUserName + `办理吗?`, message: "您确定要将" + name + "提案转交给" + transferUserName + "办理吗?",
confirmButtonText: '确定', confirmButtonText: "确定",
cancelButtonText: '取消' cancelButtonText: "取消"
}).then(() => {
this.$axios.post('/platform/proposal/unitReply/transfer', this.transferForm).then(res => {
if (res.code === 0) {
this.$toast.success(res.msg)
this.showTransferDialog = false
this.doSearch()
}
}) })
}).catch(() => { .then(() => {
// 取消操作 return this.$axios.post("/platform/proposal/unitReply/transfer", this.transferForm).then((res) => {
if (res.code === 0) {
return this.finishProposalSubmit(() => {
this.$toast.success(res.msg)
this.$set(this, "showTransferDialog", false)
this.$emit("refresh")
})
}
})
})
.catch(() => {
// 取消操作
})
}) })
} }
}, },
@@ -45,11 +45,15 @@ layout("/layouts/platform_h5.html"){
</div> </div>
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
<!--#include("/platform/zhgh/democratic/proposal/common/submit.js"){}#-->
<!--#include("../../common/info.js"){}#--> <!--#include("../../common/info.js"){}#-->
const vue = new Vue({ const vue = new Vue({
el: "#app", el: "#app",
store, store,
// 查看详情也需要同步弹框历史,返回键先关闭详情而非离开列表。
proposalH5: true,
mixins: [PROPOSAL_SUBMIT_MIXIN],
data() { data() {
return { return {
pageForm: { pageForm: {
@@ -100,14 +100,14 @@ layout("/layouts/platform_h5.html"){
label="代表姓名" label="代表姓名"
readonly readonly
:rules="[{ required: true, message: '请填写提案人' }]" :rules="[{ required: true, message: '请填写提案人' }]"
></van-field> :disabled="$root.proposalSubmitting"></van-field>
<van-field <van-field
v-model="formData.createTime" v-model="formData.createTime"
label="提案时间" label="提案时间"
readonly readonly
:rules="[{ required: true, message: '请填写提案时间' }]" :rules="[{ required: true, message: '请填写提案时间' }]"
></van-field> :disabled="$root.proposalSubmitting"></van-field>
<van-field <van-field
v-model="formData.sessionName" v-model="formData.sessionName"
@@ -118,7 +118,7 @@ layout("/layouts/platform_h5.html"){
placeholder="请选择所属教代会" placeholder="请选择所属教代会"
@click="showSessionPicker = true" @click="showSessionPicker = true"
:rules="[{ required: true, message: '请选择所属教代会' }]" :rules="[{ required: true, message: '请选择所属教代会' }]"
></van-field> :disabled="$root.proposalSubmitting"></van-field>
<van-popup v-model="showSessionPicker" position="bottom"> <van-popup v-model="showSessionPicker" position="bottom">
<van-picker <van-picker
show-toolbar show-toolbar
@@ -133,7 +133,7 @@ layout("/layouts/platform_h5.html"){
label="所属代表团" label="所属代表团"
readonly readonly
:rules="[{ required: true, message: '请选择所属代表团' }]" :rules="[{ required: true, message: '请选择所属代表团' }]"
></van-field> :disabled="$root.proposalSubmitting"></van-field>
<van-field <van-field
v-if="formData.mannerCode=='W03'" v-if="formData.mannerCode=='W03'"
@@ -145,7 +145,7 @@ layout("/layouts/platform_h5.html"){
placeholder="请选择所属委员会" placeholder="请选择所属委员会"
@click="showCommitteePicker = true" @click="showCommitteePicker = true"
:rules="[{ required: true, message: '请选择所属委员会' }]" :rules="[{ required: true, message: '请选择所属委员会' }]"
></van-field> :disabled="$root.proposalSubmitting"></van-field>
<van-popup v-model="showCommitteePicker" position="bottom"> <van-popup v-model="showCommitteePicker" position="bottom">
<van-picker <van-picker
show-toolbar show-toolbar
@@ -161,7 +161,7 @@ layout("/layouts/platform_h5.html"){
label="单位" label="单位"
readonly readonly
:rules="[{ required: true, message: '请填写单位' }]" :rules="[{ required: true, message: '请填写单位' }]"
></van-field> :disabled="$root.proposalSubmitting"></van-field>
<van-field <van-field
v-model="formData.mobile" v-model="formData.mobile"
@@ -169,7 +169,7 @@ layout("/layouts/platform_h5.html"){
type="tel" type="tel"
placeholder="请输入联系电话" placeholder="请输入联系电话"
:rules="[{ required: true, message: '请填写联系电话' }]" :rules="[{ required: true, message: '请填写联系电话' }]"
></van-field> :disabled="$root.proposalSubmitting"></van-field>
</van-cell-group> </van-cell-group>
@@ -183,7 +183,7 @@ layout("/layouts/platform_h5.html"){
required required
maxlength="100" maxlength="100"
show-word-limit show-word-limit
></van-field> :disabled="$root.proposalSubmitting"></van-field>
<van-field <van-field
v-model="formData.sourceName" v-model="formData.sourceName"
@@ -195,7 +195,7 @@ layout("/layouts/platform_h5.html"){
@click="showSourcePicker = true" @click="showSourcePicker = true"
:rules="[{ required: true, message: '请选择提案方式' }]" :rules="[{ required: true, message: '请选择提案方式' }]"
required required
></van-field> :disabled="$root.proposalSubmitting"></van-field>
<van-popup v-model="showSourcePicker" position="bottom"> <van-popup v-model="showSourcePicker" position="bottom">
<van-picker <van-picker
show-toolbar show-toolbar
@@ -215,7 +215,7 @@ layout("/layouts/platform_h5.html"){
@click="showTypePicker = true" @click="showTypePicker = true"
:rules="[{ required: true, message: '请选择提案类别' }]" :rules="[{ required: true, message: '请选择提案类别' }]"
required required
></van-field> :disabled="$root.proposalSubmitting"></van-field>
<van-popup v-model="showTypePicker" position="bottom"> <van-popup v-model="showTypePicker" position="bottom">
<van-picker <van-picker
show-toolbar show-toolbar
@@ -226,7 +226,7 @@ layout("/layouts/platform_h5.html"){
</van-popup> </van-popup>
<van-field <van-field
:value="formData.suggestUnits.length > 0 ? formData.suggestUnits.join(', ') : ''" :value="formData.suggestUnits.length :disabled="$root.proposalSubmitting"> 0 ? formData.suggestUnits.join(', ') : ''"
is-link is-link
readonly readonly
name="suggestUnits" name="suggestUnits"
@@ -304,7 +304,7 @@ layout("/layouts/platform_h5.html"){
placeholder="请输入案由" placeholder="请输入案由"
:rules="[{ required: true, message: '请填写案由' }]" :rules="[{ required: true, message: '请填写案由' }]"
required required
></van-field> :disabled="$root.proposalSubmitting"></van-field>
<van-field <van-field
v-model="formData.measures" v-model="formData.measures"
@@ -315,13 +315,13 @@ layout("/layouts/platform_h5.html"){
placeholder="请输入建议措施" placeholder="请输入建议措施"
:rules="[{ required: true, message: '请填写建议措施' }]" :rules="[{ required: true, message: '请填写建议措施' }]"
required required
></van-field> :disabled="$root.proposalSubmitting"></van-field>
</van-cell-group> </van-cell-group>
<!-- 附件上传 --> <!-- 附件上传 -->
<van-cell-group title="附件上传" class="form-group"> <van-cell-group title="附件上传" class="form-group">
<van-field label="附件" name="files" class="direction-column-field"> <van-field label="附件" name="files" class="direction-column-field" :disabled="$root.proposalSubmitting">
<h5-file-upload <h5-file-upload
slot="input" slot="input"
:value.sync="formData.files" :value.sync="formData.files"
@@ -336,9 +336,9 @@ layout("/layouts/platform_h5.html"){
<!-- 按钮区域 --> <!-- 按钮区域 -->
<div class="form-actions" v-if="isWriteTime"> <div class="form-actions" v-if="isWriteTime">
<van-button plain type="info" @click="onSave">保存</van-button> <van-button plain type="info" @click="onSave" :loading="formLoading && formAction === ('onSave')" loading-text="提交中…" :disabled="$root.proposalSubmitting">保存</van-button>
<van-button type="primary" @click="onSubmit" v-if="!taskId">提交</van-button> <van-button type="primary" @click="onSubmit" v-if="!taskId" :loading="formLoading && formAction === ('onSubmit')" loading-text="提交中…" :disabled="$root.proposalSubmitting">提交</van-button>
<van-button type="primary" @click="onSubmitAgain" v-else>提交</van-button> <van-button type="primary" @click="onSubmitAgain" v-else :loading="formLoading && formAction === ('onSubmitAgain')" loading-text="提交中…" :disabled="$root.proposalSubmitting">提交</van-button>
</div> </div>
</van-form> </van-form>
</div> </div>
@@ -353,9 +353,14 @@ layout("/layouts/platform_h5.html"){
</div> </div>
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
<!--#include("/platform/zhgh/democratic/proposal/common/submit.js"){}#-->
new Vue({ new Vue({
el: '#app', el: '#app',
store, store,
proposalH5: true,
mixins: [PROPOSAL_SUBMIT_MIXIN],
proposalPopupFields: ["showSessionPicker", "showCommitteePicker", "showSourcePicker", "showTypePicker", "showSuggestionUnitPicker", "noticeDialogVisible"],
data() { data() {
return { return {
bizId: GetQueryString("bizId"), bizId: GetQueryString("bizId"),
@@ -462,131 +467,134 @@ layout("/layouts/platform_h5.html"){
this.showCommitteePicker = false; this.showCommitteePicker = false;
}, },
async onSave() { onSave() {
// 表单验证 return this.runProposalSubmit("onSave", async () => {
try { // 表单验证
await this.$refs.formRef.validate(); try {
await this.$refs.formRef.validate()
this.$toast.loading({ return this.$axios
message: '保存中...', .post("/platform/proposal/write/save", { info: JSON.stringify(this.formData) })
forbidClick: true, .then((res) => {
}); if (res.code === 0) {
return this.finishProposalSubmit(() => {
this.$axios.post("/platform/proposal/write/save", {info: JSON.stringify(this.formData)}) this.$toast.success(res.msg)
.then((res) => { pjaxReplace("/platform/proposal/mine/h5")
this.$toast.clear(); })
if (res.code === 0) { } else {
this.$toast.success(res.msg); this.$toast.fail(res.msg || "保存失败")
pjaxReplace('/platform/proposal/mine/h5') }
} else { })
this.$toast.fail(res.msg || '保存失败'); .catch((err) => {
} this.$toast.fail("网络错误,请稍后重试")
}) })
.catch(err => { } catch (error) {
this.$toast.clear(); // 表单验证失败
this.$toast.fail('网络错误,请稍后重试'); console.log("表单验证失败", error)
}); }
} catch (error) { })
// 表单验证失败
console.log('表单验证失败', error);
}
}, },
// 提交 // 提交
async onSubmit() { onSubmit() {
try { return this.runProposalSubmit("onSubmit", async () => {
await this.$refs.formRef.validate(); try {
await this.$refs.formRef.validate()
if (!this.formData.name || this.formData.name.trim().length < 1) { if (!this.formData.name || this.formData.name.trim().length < 1) {
this.$toast("请填写提案名称"); this.$toast("请填写提案名称")
return; return
} }
if (this.formData.brief.length < this.proposalConfig.briefMinLength) { if (this.formData.brief.length < this.proposalConfig.briefMinLength) {
this.$toast("案由" + this.proposalConfig.briefMinLength + "字"); this.$toast("案由" + this.proposalConfig.briefMinLength + "字")
return; return
} }
this.$dialog.confirm({ return this.proposalConfirm({
title: '提示', title: "提示",
message: '您确定要提交吗?', message: "您确定要提交吗?"
}).then(() => { })
this.$toast.loading({ .then(() => {
message: '提交中...', return this.$axios
forbidClick: true, .post("/platform/proposal/write/submit", { info: JSON.stringify(this.formData) })
}); .then((res) => {
if (res.code === 0) {
this.$axios.post('/platform/proposal/write/submit', {info: JSON.stringify(this.formData)}) return this.finishProposalSubmit(() => {
.then(res => { this.$toast.success("提交成功")
this.$toast.clear(); pjaxReplace("/platform/proposal/mine/h5")
if (res.code === 0) { })
this.$toast.success("提交成功"); } else {
pjaxReplace('/platform/proposal/mine/h5') this.$toast.fail(res.msg || "提交失败")
} else { }
this.$toast.fail(res.msg || '提交失败'); })
} .catch((err) => {
this.$toast.fail("网络错误,请稍后重试")
})
}) })
.catch(err => { .catch(() => {
this.$toast.clear(); // 取消提交
this.$toast.fail('网络错误,请稍后重试'); })
}); } catch (error) {
}).catch(() => { // 表单验证失败
// 取消提交 console.log("表单验证失败", error)
}); }
} catch (error) { })
// 表单验证失败
console.log('表单验证失败', error);
}
}, },
// 重新提交 // 重新提交
async onSubmitAgain() { onSubmitAgain() {
try { return this.runProposalSubmit("onSubmitAgain", async () => {
await this.$refs.formRef.validate(); try {
await this.$refs.formRef.validate()
if (!this.formData.name || this.formData.name.trim().length < 1) { if (!this.formData.name || this.formData.name.trim().length < 1) {
this.$toast("请填写提案名称"); this.$toast("请填写提案名称")
return; return
}
if (this.formData.brief.length < this.proposalConfig.briefMinLength) {
this.$toast("提案内容和依据最少为" + this.proposalConfig.briefMinLength + "字")
return
}
return this.proposalConfirm({
title: "提示",
message: "您确定要提交吗?"
})
.then(() => {
return this.$axios
.post("/platform/proposal/write/submitAgain", {
info: JSON.stringify(this.formData),
taskId: this.taskId
})
.then((res) => {
if (res.code === 0) {
return this.finishProposalSubmit(() => {
this.$toast.success("提交成功")
return new Promise((resolve) =>
setTimeout(() => {
pjaxReplace("/platform/proposal/mine/h5")
resolve()
}, 1500)
)
})
} else {
this.$toast.fail(res.msg || "提交失败")
}
})
.catch((err) => {
this.$toast.fail("网络错误,请稍后重试")
})
})
.catch(() => {
// 取消提交
})
} catch (error) {
// 表单验证失败
console.log("表单验证失败", error)
} }
})
if (this.formData.brief.length < this.proposalConfig.briefMinLength) {
this.$toast("提案内容和依据最少为" + this.proposalConfig.briefMinLength + "字");
return;
}
this.$dialog.confirm({
title: '提示',
message: '您确定要提交吗?',
}).then(() => {
this.$toast.loading({
message: '提交中...',
forbidClick: true,
});
this.$axios.post('/platform/proposal/write/submitAgain', {
info: JSON.stringify(this.formData),
taskId: this.taskId
}).then(res => {
this.$toast.clear();
if (res.code === 0) {
this.$toast.success("提交成功");
setTimeout(() => {
pjaxReplace('/platform/proposal/mine/h5')
}, 1500);
} else {
this.$toast.fail(res.msg || '提交失败');
}
}).catch(err => {
this.$toast.clear();
this.$toast.fail('网络错误,请稍后重试');
});
}).catch(() => {
// 取消提交
});
} catch (error) {
// 表单验证失败
console.log('表单验证失败', error);
}
}, },
// 获取提案类别 // 获取提案类别
@@ -150,39 +150,13 @@ layout("/layouts/platform_h5.html"){
<!-- </van-action-sheet>--> <!-- </van-action-sheet>-->
<van-field <van-field
v-model="formData.payUserName" :value="formData.applyUserName"
name="payUserName" name="payUserName"
label="收款人" label="收款人"
required required
readonly readonly
:rules="[{ required: true }]" :rules="[{ required: true }]"
placeholder="请点击选择收款人"
@click="payUserSelectShow = true"
is-link
></van-field> ></van-field>
<van-action-sheet v-model="payUserSelectShow" title="收款人" class="height100">
<van-search
v-model="searchKeyword"
:show-action="false"
:reverse-color="false"
input-align="left"
placeholder="请输入工号或姓名选择收款人"
@input="(val) => {userRemoteMethod(val, 'pay')}"
@clear="(val) => {userRemoteMethod(val, 'pay')}"
shape="round"
></van-search>
<div class="van-action-sheet__content mt5" v-if="userOptions && userOptions.length>0">
<template>
<template v-for="item in userOptions">
<van-button native-type="button" @click="payUserChange(item)"
class="van-action-sheet__item van-hairline--bottom">
<span class="van-action-sheet__name">{{item.userName}}({{item.loginName}})</span>
</van-button>
</template>
</template>
</div>
<van-empty description="暂无数据" v-else></van-empty>
</van-action-sheet>
<van-field <van-field
v-model="formData.typeName" v-model="formData.typeName"
@@ -409,7 +383,6 @@ layout("/layouts/platform_h5.html"){
typeOptions: [], typeOptions: [],
helpUserSelectShow: false, helpUserSelectShow: false,
payUserSelectShow: false,
showTypePicker: false, showTypePicker: false,
typeColumns: [], typeColumns: [],
searchKeyword: "", searchKeyword: "",
@@ -498,8 +471,6 @@ layout("/layouts/platform_h5.html"){
this.certifierUserSelectShow = true this.certifierUserSelectShow = true
} else if (type === "handler") { } else if (type === "handler") {
this.handlerUserSelectShow = true this.handlerUserSelectShow = true
}else if (type === "pay") {
this.payUserSelectShow = true
} }
} }
}, },
@@ -521,15 +492,6 @@ layout("/layouts/platform_h5.html"){
this.searchKeyword = "" this.searchKeyword = ""
this.userOptions = [] this.userOptions = []
}, },
payUserChange(user) {
const { id, userName, loginName } = user
this.$set(this.formData, "payUserId", id)
this.$set(this.formData, "payUserName", userName)
this.$set(this.formData, "payLoginName", loginName)
this.payUserSelectShow = false
this.searchKeyword = ""
this.userOptions = []
},
typeChange(id) { typeChange(id) {
this.chooseType = this.typeOptions.find(o => o.id === id) this.chooseType = this.typeOptions.find(o => o.id === id)
if (this.chooseType) { if (this.chooseType) {
@@ -615,7 +577,6 @@ layout("/layouts/platform_h5.html"){
if (res.code === 0) { if (res.code === 0) {
this.formData = res.data this.formData = res.data
this.selectQueryUser(this.formData.helpLoginName, this.helpUserOptions) this.selectQueryUser(this.formData.helpLoginName, this.helpUserOptions)
this.selectQueryUser(this.formData.payLoginName, this.payUserOptions)
this.chooseType = this.typeOptions.find(o => o.id === this.formData.type) this.chooseType = this.typeOptions.find(o => o.id === this.formData.type)
} }
}) })