This commit is contained in:
2026-07-14 16:28:22 +08:00
parent 24e2d9e826
commit f39735f1f2
37 changed files with 468 additions and 251 deletions
@@ -8,18 +8,25 @@ import com.budwk.app.sys.models.Sys_user;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.FieldFilter;
import org.nutz.dao.util.Daos;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
@@ -29,11 +36,23 @@ import java.util.stream.Collectors;
@Api(tags = "用户审批意见")
public class SysUserApprovalOpinionController {
/**
* 系统内置的常用审批意见,统一提供给所有使用审核意见组件的页面。
*/
private static final List<String> DEFAULT_APPROVAL_OPINIONS = List.of("同意", "不同意");
@Inject
private Dao dao;
/**
* 保存当前用户的自定义审批意见。
*
* @param opinions 前端提交的意见数组,每项包含 id 和 text;系统内置的“同意”“不同意”不会写入用户数据
* @return Result,成功时不返回额外数据,失败时 msg 说明校验结果
*/
@At
@SaCheckLogin
@Aop(TransAop.READ_COMMITTED)
@ApiOperation("保存审批意见")
public Result update(@Param("opinions")JSONObject[] opinions){
boolean hasBlank = Arrays.stream(opinions).anyMatch(v -> StrUtil.isBlank(v.getStr("text").trim()));
@@ -41,35 +60,68 @@ public class SysUserApprovalOpinionController {
return Result.error("内容不能为空,请删除后再提交!");
}
Set<String> opinionTexts = Arrays.stream(opinions).map(v -> v.getStr("text").trim()).collect(Collectors.toSet());
if(opinionTexts.size() != opinions.length){
// 系统默认意见只参与页面展示,不占用用户自定义意见数量,也不写入用户表。
JSONObject[] customOpinions = Arrays.stream(opinions)
.filter(v -> !DEFAULT_APPROVAL_OPINIONS.contains(v.getStr("text").trim()))
.toArray(JSONObject[]::new);
Set<String> opinionTexts = Arrays.stream(customOpinions).map(v -> v.getStr("text").trim()).collect(Collectors.toSet());
if(opinionTexts.size() != customOpinions.length){
return Result.error("内容重复,请删除后再提交!");
}
boolean text = Arrays.stream(opinions).anyMatch(v -> v.getStr("text").trim().length() > 50);
boolean text = Arrays.stream(customOpinions).anyMatch(v -> v.getStr("text").trim().length() > 50);
if(text){
return Result.error("单条内容不能超过50个字!");
}
if(opinions.length > 5){
if(customOpinions.length > 5){
return Result.error("最多可添加10条审批意见!");
}
for (int i = 0; i < opinions.length; i++) {
opinions[i].set("id",i+1);
for (int i = 0; i < customOpinions.length; i++) {
customOpinions[i].set("id",i+1);
}
dao.update(Sys_user.class, Chain.make("customApprovalOpinions", Arrays.asList(opinions)), Cnd.where(Sys_user::getId,"=", SecurityUtil.getUserId()));
dao.update(Sys_user.class, Chain.make("customApprovalOpinions", Arrays.asList(customOpinions)), Cnd.where(Sys_user::getId,"=", SecurityUtil.getUserId()));
return Result.success();
}
/**
* 获取当前用户可选的审批意见。
*
* @return Resultdata 为意见数组,每项包含 id 和 text;系统默认意见排在用户自定义意见之前
*/
@At
@SaCheckLogin
@ApiOperation("获取审批意见")
public Result list(){
FieldFilter fieldFilter = FieldFilter.create(Sys_user.class, "^customApprovalOpinions");
Sys_user sysUser = Daos.ext(dao, fieldFilter).fetch(Sys_user.class, Cnd.where(Sys_user::getId, "=", SecurityUtil.getUserId()));
return Result.success(sysUser.getCustomApprovalOpinions());
List<JSONObject> opinions = new ArrayList<>();
Set<String> opinionTexts = new HashSet<>();
// 默认意见始终置顶,并通过文本去重,避免与用户历史自定义意见重复。
for (String defaultOpinion : DEFAULT_APPROVAL_OPINIONS) {
JSONObject opinion = new JSONObject();
opinion.set("id", opinions.size() + 1);
opinion.set("text", defaultOpinion);
opinions.add(opinion);
opinionTexts.add(defaultOpinion);
}
List<JSONObject> customOpinions = Optional.ofNullable(sysUser.getCustomApprovalOpinions()).orElseGet(Collections::emptyList);
for (JSONObject customOpinion : customOpinions) {
String text = customOpinion.getStr("text");
if (StrUtil.isBlank(text) || !opinionTexts.add(text.trim())) {
continue;
}
JSONObject opinion = new JSONObject();
opinion.set("id", opinions.size() + 1);
opinion.set("text", text);
opinions.add(opinion);
}
return Result.success(opinions);
}
}
@@ -2,7 +2,6 @@ package com.budwk.app.sys.services.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
@@ -25,7 +24,6 @@ import com.budwk.app.zhgh.staffmanage.member.constant.MemberChangeOrigin;
import com.budwk.app.zhgh.staffmanage.member.constant.MemberChangeType;
import lombok.extern.slf4j.Slf4j;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.ioc.aop.Aop;
@@ -52,7 +50,6 @@ import java.util.stream.Collectors;
@IocBean
public class SysDataUserAllUpdateServiceImpl implements SysDataUserUpdateService {
private static final int BATCH_SIZE = 500;
private static final int ROLE_DELETE_BATCH_SIZE = 50;
@Inject
private Dao dao;
@@ -114,34 +111,6 @@ public class SysDataUserAllUpdateServiceImpl implements SysDataUserUpdateService
return fieldMappings;
}
/**
* 检查用户是否符合会员条件
*
* @param userState 用户状态
* @param preparedBy 编制类别
* @param postDoctoralJoinDate 博士后进站时间
* @return 是否符合会员条件
*/
private boolean checkMembershipEligibility(String userState, String preparedBy, Date postDoctoralJoinDate) {
// 博士后单独判断:只要进站时间在两年内就是会员
if ("博士后".equals(preparedBy)) {
if (postDoctoralJoinDate != null) {
Date twoYearsAgo = DateUtil.offset(DateUtil.date(), DateField.YEAR, -2).toJdkDate();
return postDoctoralJoinDate.after(twoYearsAgo);
}
return false;
}
// 其他人员需要判断在岗状态和聘用方式
if (!"在岗".equals(userState)) {
return false;
}
// 判断聘用方式
Set<String> memberPreparedByTypes = new HashSet<>(Arrays.asList("新人事代理", "校聘合同制", "事业编制"));
return memberPreparedByTypes.contains(preparedBy);
}
/**
* 全量更新用户数据
*
@@ -156,7 +125,6 @@ public class SysDataUserAllUpdateServiceImpl implements SysDataUserUpdateService
// 获取角色信息
Sys_role publicRole = sysRoleService.getByCode(RoleConstant.PUBLIC);
Sys_role memberRole = sysRoleService.getByCode(RoleConstant.MEMBER);
// 获取单位信息,后续判断单位变更
List<Sys_unit> unitList = dao.query(Sys_unit.class, Cnd.where("unitTypeCode", "=", "1"));
@@ -181,23 +149,6 @@ public class SysDataUserAllUpdateServiceImpl implements SysDataUserUpdateService
List<Sys_user> needDoUpdateList = new CopyOnWriteArrayList<>();
List<Sys_user> needInitUserList = new CopyOnWriteArrayList<>();
List<Sys_user_history> histories = new CopyOnWriteArrayList<>();
List<String> addMemberUserIds = Collections.synchronizedList(new ArrayList<>());
List<String> removeMemberUserIds = Collections.synchronizedList(new ArrayList<>());
Set<String> sourceLoginNames = sources.stream()
.map(Sys_user_source::getLoginname)
.filter(StrUtil::isNotBlank)
.collect(Collectors.toSet());
List<String> leaveUserIds = sysUsers.stream()
.filter(user -> StrUtil.isNotBlank(user.getLoginname()))
.filter(user -> !sourceLoginNames.contains(user.getLoginname()))
.map(Sys_user::getId)
.toList();
List<String> leaveMemberUserIds = sysUsers.stream()
.filter(user -> StrUtil.isNotBlank(user.getLoginname()))
.filter(user -> !sourceLoginNames.contains(user.getLoginname()))
.filter(user -> Boolean.TRUE.equals(user.getMember()))
.map(Sys_user::getId)
.toList();
// 处理每条数据
for (Sys_user_source source : sources) {
@@ -214,22 +165,15 @@ public class SysDataUserAllUpdateServiceImpl implements SysDataUserUpdateService
u.setSalt(salt);
u.setPassword(PwdUtil.getPassword(PwdUtil.generate(12), salt));
/* if (u.getMember()) {
addMemberUserIds.add(u.getId());
}*/
needInitUserList.add(u);
} else {
// 修改现有用户
u.setId(user.getId());
// 更新会员状态
boolean currentIsMember = user.getMember() != null && user.getMember();
if (!currentIsMember) {
// addMemberUserIds.add(user.getId());
} else{
// removeMemberUserIds.add(user.getId());
}
/*
* aidFundMember 由基金会员业务维护,数据中心源表默认值为 0。
* 全量更新已有用户时置空,避免 updateIgnoreNull 把已迁移的基金会员标识覆盖为非会员。
*/
u.setAidFundMember(null);
needDoUpdateList.add(u);
}
@@ -312,45 +256,6 @@ public class SysDataUserAllUpdateServiceImpl implements SysDataUserUpdateService
updateTasks.add(updateTask);
}
if (Lang.isNotEmpty(leaveUserIds)) {
CompletableFuture<Void> leaveTask = CompletableFuture.runAsync(() -> {
log.info("数据源缺失用户转为不在岗并取消会员: {} 个", leaveUserIds.size());
List<List<String>> batches = ListUtil.split(leaveUserIds, BATCH_SIZE);
batches.forEach(batch -> {
try {
/*
* 本次拉取批次中没有出现、但系统用户表仍存在的人员,按离岗处理:
* 1. userState 写为“不在岗”,用于后续人员状态筛选和业务判断;
* 2. member 写为 false,避免仍按会员身份参与后续业务判断。
*/
dao.update(Sys_user.class, Chain.make("userState", "不在岗").add("member", false), Cnd.where("id", "in", batch));
} catch (Exception e) {
log.error("批量更新数据源缺失用户状态异常", e);
}
});
}, executorService);
updateTasks.add(leaveTask);
}
if (Lang.isNotEmpty(leaveMemberUserIds)) {
CompletableFuture<Void> leaveMemberRoleTask = CompletableFuture.runAsync(() -> {
log.info("数据源缺失会员移除会员角色: {} 个", leaveMemberUserIds.size());
List<List<String>> batches = ListUtil.split(leaveMemberUserIds, ROLE_DELETE_BATCH_SIZE);
batches.forEach(batch -> {
try {
/*
* 只对原本是会员的缺失人员移除会员角色,并缩小删除批次,
* 降低 sys_user_role 大批量 DELETE 时的锁等待概率。
*/
dao.clear(Sys_user_role.class, Cnd.where("userId", "in", batch).and("roleId", "=", memberRole.getId()));
} catch (Exception e) {
log.error("批量移除数据源缺失会员角色异常", e);
}
});
}, executorService);
updateTasks.add(leaveMemberRoleTask);
}
if (Lang.isNotEmpty(histories)) {
CompletableFuture<Void> historyTask = CompletableFuture.runAsync(() -> {
log.info("添加历史记录: {} 条", histories.size());
@@ -444,8 +349,11 @@ public class SysDataUserAllUpdateServiceImpl implements SysDataUserUpdateService
long endTime = System.currentTimeMillis();
log.info("全量更新用户数据完成,耗时: {} 毫秒", (endTime - startTime));
return "更新完成: 新增用户 " + needInitUserList.size() + " 个, 更新用户 " + needDoUpdateList.size()
+ " 个, 数据源缺失转不在岗 " + leaveUserIds.size() + " 个, 待添加会员 " + addMemberUserIds.size() + " 个, 待移除会员 " + removeMemberUserIds.size() + "";
if (needInitUserList.isEmpty() && histories.isEmpty()) {
return "本次没有可更新的数据。";
}
return "更新完成: 新增用户 " + needInitUserList.size() + " 个, 有效变更 " + histories.size()
+ "";
}
/**
@@ -479,6 +387,18 @@ public class SysDataUserAllUpdateServiceImpl implements SysDataUserUpdateService
Object sourceValue = mapping.field.get(source);
Object userValue = mapping.field.get(user);
/*
* 全量更新使用 updateIgnoreNull,数据源空值不会覆盖系统已有值。
* 因此当新值为空、旧值有值时不生成历史记录,避免每次更新都重复记录“有值→空”。
* 同时将 null、空字符串、纯空格统一视为业务空值,避免页面显示为空但底层值不同导致“空→空”被记录。
*/
if (isBlankChangeValue(sourceValue) && isBlankChangeValue(userValue)) {
continue;
}
if (isBlankChangeValue(sourceValue) && !isBlankChangeValue(userValue)) {
continue;
}
// 如果值不相等,记录变更
if (!ObjectUtil.equals(sourceValue, userValue)) {
NutMap change = NutMap.NEW();
@@ -543,6 +463,20 @@ public class SysDataUserAllUpdateServiceImpl implements SysDataUserUpdateService
return history;
}
/**
* 判断历史变更字段是否为业务空值。
* null、空字符串、纯空格在页面上都会展示为空,统一视为无有效新值,避免生成无意义的空值变更记录。
*/
private boolean isBlankChangeValue(Object value) {
if (value == null) {
return true;
}
if (value instanceof CharSequence) {
return StrUtil.isBlank(value.toString());
}
return ObjectUtil.isEmpty(value);
}
/**
* 获取单位变更记录展示值。
* 入参 unitId 为系统用户旧单位或数据源新单位ID;返回值优先使用单位名称,查不到名称时保留单位ID,避免变更记录为空导致更新中断。
@@ -2,6 +2,7 @@ package com.budwk.app.sys.services.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.thread.AsyncUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
@@ -15,18 +16,18 @@ import com.budwk.app.sys.param.SysDataUserUpdateParam;
import com.budwk.app.sys.services.SysDataUserUpdateService;
import com.budwk.app.sys.services.SysRoleService;
import com.budwk.app.zhgh.democratic.proposal.models.ProposalConfig;
import com.budwk.app.zhgh.staffmanage.member.constant.MemberChangeOrigin;
import com.budwk.app.zhgh.staffmanage.member.constant.MemberChangeType;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.random.R;
import java.util.List;
import java.util.Arrays;
import java.util.Date;
import java.util.Calendar;
import java.util.concurrent.CompletableFuture;
/**
@@ -41,6 +42,7 @@ public class SysDataUserIncrUpdateServiceImpl implements SysDataUserUpdateServic
private SysRoleService sysRoleService;
@Override
@Aop(TransAop.READ_COMMITTED)
public String update(SysDataUserUpdateParam updateParam) {
// 基本SQL查询
Cnd cnd = Cnd.where("pullTime", "=", updateParam.getPullTime())
@@ -67,34 +69,6 @@ public class SysDataUserIncrUpdateServiceImpl implements SysDataUserUpdateServic
String pwd = PwdUtil.generate(12);
sysUser.setPassword(PwdUtil.getPassword(pwd, salt));
sysUser.setLoginCount(0);
// 检查是否符合会员条件
// 1. 用户状态为"在岗"
if ("在岗".equals(sysUser.getUserState())) {
// 2. 检查聘用方式条件
List<String> membershipQualifyingPreparedBy = Arrays.asList("新人事代理", "校聘合同制", "事业编制");
// 第一种情况:聘用方式在指定列表中
boolean isQualifiedByPreparedBy = membershipQualifyingPreparedBy.contains(sysUser.getPreparedBy());
// 第二种情况:聘用方式是博士后,且进站时间不超过两年
boolean isQualifiedPostdoc = false;
if ("博士后".equals(sysUser.getPreparedBy()) && sysUser.getPostDoctoralJoinDate() != null) {
Calendar twoYearsAgo = Calendar.getInstance();
twoYearsAgo.add(Calendar.YEAR, -2);
Date twoYearsAgoDate = twoYearsAgo.getTime();
isQualifiedPostdoc = sysUser.getPostDoctoralJoinDate().after(twoYearsAgoDate);
}
// 如果满足任一条件,设置为会员
if (isQualifiedByPreparedBy || isQualifiedPostdoc) {
sysUser.setMember(true);
} else {
sysUser.setMember(false);
}
} else {
sysUser.setMember(false);
}
}
List<List<Sys_user>> splitSysUsers = ListUtil.split(sysUsers, 500);
@@ -102,6 +76,18 @@ public class SysDataUserIncrUpdateServiceImpl implements SysDataUserUpdateServic
//等待任务全部完成
AsyncUtil.waitAll(CompletableFuture.allOf(splitSysUsersFutures.toArray(new CompletableFuture[0])));
// 增量更新只处理新增人员,需要同步写入用户历史记录;列表的变更类型、变更时间通过 sys_user_history 最新记录展示。
List<Sys_user_history> histories = BeanUtil.copyToList(userSources, Sys_user_history.class);
for (Sys_user_history history : histories) {
history.setId(R.UU32());
history.setChangeTypes(List.of(MemberChangeType.NEW.name()));
history.setChangeTime(DateUtil.date());
history.setChangeOrigin(MemberChangeOrigin.SYSTEM.name());
}
List<List<Sys_user_history>> splitHistories = ListUtil.split(histories, 500);
List<CompletableFuture<List<Sys_user_history>>> splitHistoryFutures = splitHistories.stream().map(v -> CompletableFuture.supplyAsync(() -> dao.fastInsert(v))).toList();
AsyncUtil.waitAll(CompletableFuture.allOf(splitHistoryFutures.toArray(new CompletableFuture[0])));
Sys_role publicRole = sysRoleService.getByCode(RoleConstant.PUBLIC);
//添加公共角色
@@ -143,15 +129,15 @@ public class SysDataUserIncrUpdateServiceImpl implements SysDataUserUpdateServic
dao.insert(insertUnits);
});
// 计算设置为会员的人数
long memberCount = sysUsers.stream().filter(Sys_user::getMember).count();
// 6.1 更新提案的校领导角色,发送订阅
ProposalConfig config = dao.fetch(ProposalConfig.class, Cnd.where("delFlag", "=", false).desc("updatedAt"));
for (String unitId : config.getSchoolLeaderUnitIds()) {
RoleEventPublisher.broadcast(new RoleEventMsg(unitId, RoleConstant.PROPOSAL_BRANCH_SCHOOL_LEADER.name(), RoleEventMsg.RENEW_ROLE));
}
return StrUtil.format("增量更新成功,本次更新新入职老师{}人,新增单位{}个,设置为会员{}人。", sysUsers.size(), insertUnits.size(), memberCount);
if (sysUsers.isEmpty() && insertUnits.isEmpty()) {
return "本次没有新增人员或单位。";
}
return StrUtil.format("增量更新成功,本次新增人员{}人,新增单位{}个。", sysUsers.size(), insertUnits.size());
}
}
@@ -80,8 +80,9 @@ public class ProposalUnderTakeReplyController {
public Result pageData(@Valid ProposalSearchParam pageForm, boolean approval, boolean transfer) {
/*
* 承办单位答复列表需要按“承办单位”维度展示。
* 同一个任务可能挂了多个承办单位负责人,若只按 taskId 分组会把多条待审核合并成一条
* 因此这里优先使用任务参与人的承办单位信息拆行,历史数据缺失时再回退到流程变量。
* 新流程生成的会签任务可能未写入 underTakeName、underTakeId、underTakeIsMaster
* 因此优先读取任务变量,变量缺失时再按“提案ID + 任务参与人单位ID”关联承办单位记录兜底,
* 兼容已经生成的历史待办,同时保持原有任务变量的数据优先级。
*/
Sql sql = Sqls.create("""
SELECT
@@ -107,8 +108,13 @@ public class ProposalUnderTakeReplyController {
IFNULL(GROUP_CONCAT(DISTINCT nt.displayName),'结束') curTaskName,
IFNULL(GROUP_CONCAT(DISTINCT nt.taskName),'结束') curTaskKey,
CASE WHEN t.taskState = 20 AND ( rt.id IS NULL OR rt.taskState = 10 ) THEN 1 ELSE 0 END AS canRevoke,
t.variable->>'$.underTakeName' AS underTakeName,
IF(JSON_EXTRACT(t.variable, '$.underTakeIsMaster') = true, 1, 0) AS underTakeIsMaster,
COALESCE(NULLIF(t.variable->>'$.underTakeName', ''), replyUnit.unitName) AS underTakeName,
COALESCE(NULLIF(t.variable->>'$.underTakeId', ''), replyUnit.unitId) AS underTakeId,
CASE
WHEN JSON_EXTRACT(t.variable, '$.underTakeIsMaster') IS NOT NULL
THEN IF(JSON_EXTRACT(t.variable, '$.underTakeIsMaster') = true, 1, 0)
ELSE IFNULL(replyUnit.isMaster, 0)
END AS underTakeIsMaster,
t.variable->>'$.tf_transferUserId' AS tf_transferUserId,
transferUser.username AS transferUserName,
GROUP_CONCAT(DISTINCT ta.actorName, '(', ta.actorAccount, ')' ) AS auditUser
@@ -119,6 +125,7 @@ public class ProposalUnderTakeReplyController {
LEFT JOIN wf_process_task nt ON nt.processInstanceId = ins.id AND nt.taskState = 10
LEFT JOIN wf_process_task rt ON rt.processInstanceId = ins.id AND rt.taskParentId = t.id
LEFT JOIN proposal_info info ON info.id = ins.businessNo
LEFT JOIN proposal_reply_unit replyUnit ON replyUnit.proposalId = info.id AND replyUnit.unitId = ta.actorUnitId
LEFT JOIN proposal_type type on type.id = info.typeId
LEFT JOIN proposal_merge mer ON mer.proposalId = info.id
LEFT JOIN teacher_congress_session tcs on tcs.id = info.sessionId
@@ -6,6 +6,7 @@ import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.exception.BaseException;
import com.budwk.app.flow.constant.FlowConst;
import com.budwk.app.flow.engine.AssignmentHandler;
import com.budwk.app.flow.engine.core.Execution;
import com.budwk.app.flow.engine.core.ServiceContext;
@@ -36,12 +37,7 @@ public class ProposalUnitAssignmentHandler implements AssignmentHandler {
SysRoleService sysRoleService = ServiceContext.find(SysRoleService.class);
String proposalId = execution.getProcessInstance().getBusinessNo();
// 当前节点需要同时处理主办和协办负责人。
// 这里不能按单位ID去重,必须保留每个承办单位对应的一条分派记录,
// 否则同一用户负责多个单位时,会被错误合并成更少的待办。
List<String> unitIds = new ArrayList<>();
unitIds.addAll(resolveMasterUnitIds(execution, dao, proposalId));
unitIds.addAll(resolveSlaveUnitIds(execution, dao, proposalId));
List<String> unitIds = resolveUnitIds(model, execution, dao, proposalId);
if (unitIds.isEmpty()) {
throw new BaseException("提案没有配置承办单位");
@@ -76,6 +72,25 @@ public class ProposalUnitAssignmentHandler implements AssignmentHandler {
return assignee;
}
/**
* 确定当前答复节点需要分派的单位范围。
* 二次答复页面已明确提交 tf_secondReplyUnitIds 时,该字段就是唯一分派范围;
* 未选择的主办或协办单位不能再从历史承办单位记录中补回。
* 旧流程没有该字段时,继续按主办、协办配置回退,保证历史流程可以正常运行。
*/
private List<String> resolveUnitIds(TaskModel model, Execution execution, Dao dao, String proposalId) {
String secondReplyUnitIdsKey = FlowConst.TASK_FORM_DATA_PREFIX + "secondReplyUnitIds";
if ("two_unit_reply".equals(model.getName()) && execution.getArgs().containsKey(secondReplyUnitIdsKey)) {
return getStringList(execution.getArgs(), secondReplyUnitIdsKey);
}
// 初次答复需要同时处理主办和协办负责人,旧二次答复流程也沿用该兼容逻辑。
List<String> unitIds = new ArrayList<>();
unitIds.addAll(resolveMasterUnitIds(execution, dao, proposalId));
unitIds.addAll(resolveSlaveUnitIds(execution, dao, proposalId));
return unitIds;
}
/**
* 优先从当前流程变量读取主办单位,读不到时回落到承办单位记录表,兼容重新流转场景。
*/
@@ -33,6 +33,11 @@ public class ProposalInfo extends BaseModel {
@ColDefine(type = ColType.VARCHAR, width = 20)
private String code;
@Column
@Comment("立案编号")
@ColDefine(type = ColType.VARCHAR, width = 20)
private String caseFilingCode;
@Column
@Comment("提案名称")
@ColDefine(type = ColType.VARCHAR, width = 100)
@@ -76,6 +76,8 @@ public class ProposalCommitteeFilingUnitServiceImpl extends BaseServiceImpl<Prop
throw new BaseException("没有进行中的流程任务");
}
validateAndNormalizeCaseFilingCode(args);
String proposalId = args.getStr("proposalId");
List<String> proposalIds = proposalCommonService.mergeProposal(proposalId);
if (ObjectUtil.isEmpty(proposalIds)) {
@@ -98,16 +100,44 @@ public class ProposalCommitteeFilingUnitServiceImpl extends BaseServiceImpl<Prop
syncCommitteeFilingUnitData(proposalIds, args);
}
/**
* old-flow 页面提交后,需要把立案结果以及主协办单位同步落业务表。
* 校验并规范化立案编号。确定立案时必须传入不超过 20 个字符的编号;
* 其他立案结果不保存编号,避免切换选项后把历史输入带入业务表和流程变量。
*
* @param args 流程提交参数,其中 tf_caseFilingResult 为立案结果,tf_caseFilingCode 为手工填写的立案编号
*/
private void validateAndNormalizeCaseFilingCode(Dict args) {
String caseFilingResultKey = FlowConst.TASK_FORM_DATA_PREFIX + "caseFilingResult";
String caseFilingCodeKey = FlowConst.TASK_FORM_DATA_PREFIX + "caseFilingCode";
if (!"CONFIRM_FILING".equals(args.getStr(caseFilingResultKey))) {
args.put(caseFilingCodeKey, "");
return;
}
String caseFilingCode = StrUtil.trim(args.getStr(caseFilingCodeKey));
if (StrUtil.isBlank(caseFilingCode)) {
throw new BaseException("立案编号不能为空");
}
if (caseFilingCode.length() > 20) {
throw new BaseException("立案编号不能超过20个字符");
}
args.put(caseFilingCodeKey, caseFilingCode);
}
/**
* old-flow 页面提交后,需要把立案编号、立案结果以及主协办单位同步落业务表。
* 若这次改成“不予立案”等无需承办单位的结果,也要先清掉旧的承办单位记录,避免脏数据残留。
*/
private void syncCommitteeFilingUnitData(List<String> proposalIds, Dict args) {
String caseFilingCode = args.getStr(FlowConst.TASK_FORM_DATA_PREFIX + "caseFilingCode");
String caseFilingResult = args.getStr(FlowConst.TASK_FORM_DATA_PREFIX + "caseFilingResult");
String caseFilingType = args.getStr(FlowConst.TASK_FORM_DATA_PREFIX + "caseFilingType");
dao().update(ProposalInfo.class,
Chain.make("caseFilingResult", caseFilingResult).add("caseFilingType", caseFilingType),
Chain.make("caseFilingCode", caseFilingCode)
.add("caseFilingResult", caseFilingResult)
.add("caseFilingType", caseFilingType),
Cnd.where(ProposalInfo::getId, "in", proposalIds));
dao().clear(ProposalReplyUnit.class, Cnd.where(ProposalReplyUnit::getProposalId, "in", proposalIds));
@@ -83,15 +83,18 @@ public class TeacherCongressInstitutionController {
}
/**
* 表单中的树结构
* 获取新增机构表单使用的固定机构字典树。
*
* @param sessionId
* @return
* @param sessionId 当前教代会届次ID,用于保持接口参数与机构管理页面上下文一致
* @return Resultdata.treeList 为级联组件树结构,data.treeFlat 为名称和代码回填使用的扁平字典列表
*/
@At
@SaCheckPermission("tc.institution")
public Result formTree(@Valid String sessionId) {
Sys_dict institutionFixedDict = sysDictService.fetch(Cnd.where(Sys_dict::getCode, "=", "TEACHER_CONGRESS_INSTITUTION_FIXED"));
if (ObjectUtil.isEmpty(institutionFixedDict)) {
return Result.error("未配置双代会固定机构字典");
}
List<Sys_dict> children = sysDictService.query(Cnd.where(Sys_dict::getPath, "like", institutionFixedDict.getPath() + "%"));
List<TreeNode<String>> treeNodes = children.stream().map(sysDict -> {
TreeNode<String> treeNode = new TreeNode<>(sysDict.getId(), sysDict.getParentId(), sysDict.getName(), sysDict.getLocation());
@@ -134,19 +137,24 @@ public class TeacherCongressInstitutionController {
}
/**
* 添加机构
* 添加当前届次的机构
*
* @param institution
* @return
* @param institution 机构数据,包含 sessionId、name、code、parentId、location 和 introduceparentId 可能是固定字典ID
* @return Result,机构重复或父级不存在时返回错误,否则返回成功
*/
@At
@SaCheckPermission("tc.institution")
@Aop(TransAop.READ_COMMITTED)
public Result insert(Teacher_congress_institution institution) {
if (dao.count(Teacher_congress_institution.class, Cnd.where(Teacher_congress_institution::getCode, "=", institution.getCode()).and(Teacher_congress_institution::getSessionId, "=", institution.getSessionId())) > 0) {
return Result.error("机构已存在");
}
if (StrUtil.isNotBlank(institution.getParentId()) && !institution.getParentId().equals("0") && dao.count(Teacher_congress_institution.class, Cnd.where(Teacher_congress_institution::getId, "=", institution.getParentId()).and(Teacher_congress_institution::getSessionId, "=", institution.getSessionId())) == 0) {
// 级联框提交的是固定字典父级ID,需要按机构代码匹配当前届次的实际父机构。
Sys_dict sysDict = sysDictService.fetch(Cnd.where(Sys_dict::getId, "=", institution.getParentId()));
if (ObjectUtil.isEmpty(sysDict)) {
return Result.error("父级机构不存在");
}
Teacher_congress_institution parentInstitution = dao.fetch(Teacher_congress_institution.class,
Cnd.where(Teacher_congress_institution::getCode, "=", sysDict.getCode())
.and(Teacher_congress_institution::getSessionId, "=", institution.getSessionId())
@@ -162,13 +170,14 @@ public class TeacherCongressInstitutionController {
}
/**
* 删除机构
* 更新机构名称、描述和排序。
*
* @param id
* @return
* @param institution 机构数据,id 标识待更新机构,name、introduce、location 为可更新内容
* @return Result,机构不存在时返回错误,否则返回成功
*/
@At
@SaCheckPermission("tc.institution")
@Aop(TransAop.READ_COMMITTED)
public Result update(Teacher_congress_institution institution) {
Teacher_congress_institution dbInstitution = dao.fetch(Teacher_congress_institution.class, institution.getId());
if (ObjectUtil.isEmpty(dbInstitution)) {
@@ -267,6 +276,7 @@ public class TeacherCongressInstitutionController {
*/
@At
@SaCheckPermission("tc.institution")
@Aop(TransAop.READ_COMMITTED)
public Result userDelete(@Valid String id) {
teacherCongressInstitutionUserService.userDelete(id);
return Result.success();
@@ -61,6 +61,18 @@ public class TeacherCongressSessionController {
return Result.success(pagination);
}
/**
* 查询历史届次已保存的提案类型,不需要请求参数。
*
* @return VO 列表,每项的 proposalType 字段表示一个下拉选项
*/
@At
@SaCheckPermission("tc.prepare.session")
@ApiOperation(value = "查询届次提案类型选项")
public Result listProposalTypes() {
return Result.success(teacherCongressSessionService.listProposalTypes());
}
@At
@Aop(TransAop.READ_COMMITTED)
@SaCheckPermission("tc.prepare.session")
@@ -74,7 +86,7 @@ public class TeacherCongressSessionController {
@Aop(TransAop.READ_COMMITTED)
@SaCheckPermission("tc.prepare.session")
@ApiOperation(value = "修改届次信息")
public Result update(Teacher_congress_session session) {
public Result update(@Valid Teacher_congress_session session) {
int count = dao.count(Teacher_congress_session.class,
Cnd.where(Teacher_congress_session::getJ, "=", session.getJ())
.and(Teacher_congress_session::getC, "=", session.getC())
@@ -43,6 +43,13 @@ public class Teacher_congress_session extends BaseModel {
@ColDefine(type = ColType.VARCHAR, width = 20)
private String fullName;
@Column
@Comment("提案类型")
@ColDefine(type = ColType.VARCHAR, width = 50)
@NotBlank(message = "提案类型不能为空")
@Size(max = 50, message = "提案类型最多50个字")
private String proposalType;
@Column
@Comment("教代会开启时间")
@ColDefine(type = ColType.DATE)
@@ -1,13 +1,23 @@
package com.budwk.app.zhgh.democratic.teachercongress.prepare.service;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.zhgh.democratic.teachercongress.prepare.controller.vo.TeacherCongressSessionProposalTypeVO;
import com.budwk.app.zhgh.democratic.teachercongress.prepare.models.Teacher_congress_session;
import java.util.List;
/**
* 教代会届次
*/
public interface TeacherCongressSessionService extends BaseService<Teacher_congress_session> {
/**
* 查询届次中已经保存过的提案类型,供可输入下拉框复用。
*
* @return 提案类型 VO 列表,每项的 proposalType 字段为一个可选类型
*/
List<TeacherCongressSessionProposalTypeVO> listProposalTypes();
void insertSession(Teacher_congress_session session, boolean isExtend);
void deleteSession(String id);
@@ -24,12 +24,15 @@ import com.budwk.app.zhgh.democratic.teachercongress.institution.models.Teacher_
import com.budwk.app.zhgh.democratic.teachercongress.institution.models.Teacher_congress_institution_user;
import com.budwk.app.zhgh.democratic.teachercongress.meetings.models.Teacher_congress_meeting;
import com.budwk.app.zhgh.democratic.teachercongress.meetings.models.Teacher_congress_meeting_file;
import com.budwk.app.zhgh.democratic.teachercongress.prepare.controller.vo.TeacherCongressSessionProposalTypeVO;
import com.budwk.app.zhgh.democratic.teachercongress.prepare.models.Teacher_congress_prepare_file;
import com.budwk.app.zhgh.democratic.teachercongress.prepare.models.Teacher_congress_session;
import com.budwk.app.zhgh.democratic.teachercongress.prepare.service.TeacherCongressSessionService;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
@@ -52,6 +55,21 @@ public class TeacherCongressSessionServiceImpl extends BaseServiceImpl<Teacher_c
super(dao);
}
/**
* 读取历史届次中非空的提案类型并去重,用户既可复用已有类型,也可在前端输入新类型。
*
* @return 提案类型 VO 列表,每项只包含 proposalType 字段
*/
@Override
public List<TeacherCongressSessionProposalTypeVO> listProposalTypes() {
Sql sql = Sqls.create("SELECT DISTINCT proposalType FROM teacher_congress_session " +
"WHERE proposalType IS NOT NULL AND TRIM(proposalType) <> '' ORDER BY proposalType");
sql.setCallback(Sqls.callback.strList());
dao().execute(sql);
return sql.getList(String.class).stream()
.map(TeacherCongressSessionProposalTypeVO::new)
.toList();
}
@Override
@Aop(TransAop.READ_COMMITTED)
@@ -91,7 +91,13 @@ public class AidFundChangeRecordController {
$condition
""");
Cnd cnd = Cnd.NEW();
cnd.andEX("us.aidFundMemberUserType", "=", pageForm.getAidFundMemberUserType());
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
SqlExpressionGroup seg = new SqlExpressionGroup();
seg.or("us.loginname", "like", "%" + pageForm.getSearchKeyword() + "%");
seg.or("us.username", "like", "%" + pageForm.getSearchKeyword() + "%");
cnd.and(seg);
}
cnd.andEX("IFNULL(info.aidFundMemberUserType, us.aidFundMemberUserType)", "=", pageForm.getAidFundMemberUserType());
cnd.andEX("us.unitid", "=", pageForm.getUnitId());
cnd.andEX("us.unionid", "=", pageForm.getUnionId());
cnd.andEX("info.changeType", "=", pageForm.getChangeType());
@@ -276,11 +276,12 @@ layout("/layouts/platform.html"){
if (resp.code === 0) {
this.$message.success(resp.msg)
this.updateDialog = false
this.pageData()
}
})
})
.finally(() => {
this.updateLoading = false
.finally(() => {
this.updateLoading = false
})
})
},
listUnit() {
@@ -12,6 +12,7 @@ const PROPOSAL_INFO = {
</h3>
<el-descriptions :column="3" border>
<el-descriptions-item label="提案编号">{{ viewData.code }}</el-descriptions-item>
<el-descriptions-item label="立案编号">{{ viewData.caseFilingCode || '暂无' }}</el-descriptions-item>
<el-descriptions-item label="提案人">{{viewData.createUserName }}</el-descriptions-item>
<el-descriptions-item label="提案时间">{{ viewData.createTime }}</el-descriptions-item>
<el-descriptions-item label="教代会届次"> {{ viewData.sessionName || '暂无' }}</el-descriptions-item>
@@ -87,7 +88,8 @@ const PROPOSAL_INFO = {
<div style="display: flex;justify-content: center">
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_RESULT"
:value="row.caseFilingResult"></dict-tag>
<template v-if="row.caseFilingType">
<!-- 普通提案/重点提案暂不展示,历史数据仍保留。 -->
<template v-if="false">
(
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_TYPE"
:value="row.caseFilingType"></dict-tag>
@@ -107,9 +109,22 @@ const PROPOSAL_INFO = {
</div>
</el-dialog>
<template v-for="task in doneTasks">
<div class="mt10">
<div class="process-title">{{ task.displayName }}</div>
<!--审核信息采用手风琴展示,同一时间最多展开一条记录,避免流程较长时页面内容一次性全部铺开。-->
<template v-if="doneTasks.length">
<div class="process-title">审核信息</div>
<el-collapse v-model="activeTaskId" accordion>
<el-collapse-item v-for="task in doneTasks" :key="task.id" :name="task.id">
<template slot="title">
<!--折叠标题使用独立的单行布局,避免复用 process-title 后产生外边距和高度冲突。-->
<div style="display: flex;align-items: center;justify-content: space-between;width: 100%;min-width: 0;padding-left: 10px">
<span style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;font-size: 15px;font-weight: 600">
{{ task.displayName }}
</span>
<span style="flex-shrink: 0;margin-right: 8px;color: var(--color-primary);font-weight: 400">
{{ activeTaskId === task.id ? '收起' : '展开' }}
</span>
</div>
</template>
<el-descriptions border class="flow-task-form" :column="3" :key="task.id"
v-if="task.ext.isFirstTaskNode">
<el-descriptions-item label="申请用户">{{ task.ext.initiatorName
@@ -154,7 +169,8 @@ const PROPOSAL_INFO = {
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_RESULT"
:value="task.ext.tf_caseFilingResult"></dict-tag>
<template v-if="task.ext.tf_caseFilingType">
<!-- 普通提案/重点提案暂不展示,历史流程变量仍保留。 -->
<template v-if="false">
(
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_TYPE"
:value="task.ext.tf_caseFilingType"></dict-tag>
@@ -200,7 +216,8 @@ const PROPOSAL_INFO = {
<div v-html="task.taskFormData.tf_opinion"></div>
</el-descriptions-item>
</el-descriptions>
</div>
</el-collapse-item>
</el-collapse>
</template>
<slot></slot>
@@ -215,6 +232,7 @@ const PROPOSAL_INFO = {
return {
viewData: {},
doneTasks: [],
activeTaskId: null,
row: null,
viewDialogVisible: false
}
@@ -224,6 +242,9 @@ const PROPOSAL_INFO = {
onOpen(row) {
this.row = row
this.visible = true
// 切换提案时先清空上一条提案的审核记录和展开状态,避免异步加载期间展示旧数据。
this.doneTasks = []
this.activeTaskId = null
this.getInfo()
this.getDoneTasks()
},
@@ -249,9 +270,12 @@ const PROPOSAL_INFO = {
getDoneTasks() {
this.$axios.post("/flow/common/doneTasks", {bizId: this.row.id}).then((res) => {
if (res.code === 0) {
this.doneTasks = res.data
const tasks = res.data || []
this.doneTasks = tasks
// 审核记录加载完成后默认全部折叠,由用户按需展开查看。
this.activeTaskId = null
// 通知外层页面已办节点数据已加载完成,便于当前环节做表单回显。
this.$emit("done-tasks", res.data)
this.$emit("done-tasks", tasks)
}
})
},
@@ -99,14 +99,14 @@ layout("/layouts/platform.html"){
</el-radio>
</el-radio-group>
<span class="text-primary ml10" v-if="formData.tf_caseCheckNeedSecondReply">
(请选择需要进入二次答复的办单位,可多选)
(请选择需要进入二次答复的办单位,可多选)
</span>
</el-form-item>
<el-form-item
label="答复单位"
prop="tf_secondReplyUnitIds"
v-if="formData.tf_caseCheckNeedSecondReply"
:rules="[{required:formData.tf_caseCheckNeedSecondReply === 1,message:'请选择需要二次答复的办单位',trigger:['change','blur']}]"
:rules="[{required:formData.tf_caseCheckNeedSecondReply === 1,message:'请选择需要二次答复的办单位',trigger:['change','blur']}]"
>
<el-select v-model="formData.tf_secondReplyUnitIds" clearable filterable multiple style="width: 100%">
<el-option
@@ -123,7 +123,7 @@ layout("/layouts/platform.html"){
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
<el-button @click="$refs.guava.index()" size="small">返回</el-button>
<!-- <el-button @click="handleTaskAction(6)" size="small" type="info">退回到提案人</el-button>-->
<!-- <el-button @click="handleTaskAction(2)" size="small" type="danger">不同意</el-button>-->
<el-button @click="handleTaskAction(1)" size="small" type="primary">同意</el-button>
@@ -242,7 +242,7 @@ layout("/layouts/platform.html"){
})
},
// 二次答复只能选择当前提案已配置的办单位,避免误选到别的单位。
// 二次答复只能选择当前提案已配置的办单位,避免误选到别的单位。
loadReplyUnits(proposalId) {
this.$axios.post("/platform/proposal/case/check/listReplyUnits", { proposalId: proposalId }).then((res) => {
if (res.code === 0) {
@@ -100,7 +100,7 @@ layout("/layouts/platform.html"){
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
<el-button @click="$refs.guava.index()" size="small">返回</el-button>
<el-button @click="doSubmit" size="small" type="primary">提交</el-button>
</el-row>
</div>
@@ -120,7 +120,8 @@ layout("/layouts/platform.html"){
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="['CONFIRM_FILING'].includes(formData.tf_caseFilingResult)" label="立案类型"
<!-- 普通提案/重点提案暂不展示,保留原字段和处理逻辑,便于兼容历史流程数据。 -->
<el-form-item v-if="false" label="立案类型"
prop="tf_caseFilingType"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-radio-group v-model="formData.tf_caseFilingType" size="small">
@@ -130,9 +131,9 @@ layout("/layouts/platform.html"){
</el-radio-group>
</el-form-item>
<el-form-item
:label="formData.tf_caseFilingResult === 'SUGGESTION' ? '办单位' : '主办单位'"
:label="formData.tf_caseFilingResult === 'SUGGESTION' ? '办单位' : '主办单位'"
v-if="['CONFIRM_FILING','SUGGESTION'].includes(formData.tf_caseFilingResult)"
:rules="[{required:['CONFIRM_FILING','SUGGESTION'].includes(formData.tf_caseFilingResult),message:formData.tf_caseFilingResult === 'SUGGESTION' ? '请选择办单位' : '请选择主办单位',trigger:['change','blur']}]"
:rules="[{required:['CONFIRM_FILING','SUGGESTION'].includes(formData.tf_caseFilingResult),message:formData.tf_caseFilingResult === 'SUGGESTION' ? '请选择办单位' : '请选择主办单位',trigger:['change','blur']}]"
prop="tf_masterUnitIds"
>
<el-select v-model="formData.tf_masterUnitIds" filterable clearable multiple
@@ -167,7 +168,7 @@ layout("/layouts/platform.html"){
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
<el-button @click="$refs.guava.index()" size="small">返回</el-button>
<el-button @click="handleTaskAction(6)" size="small" type="info">退回到提案人</el-button>
<el-button @click="handleTaskAction(1)" size="small" type="primary">提交</el-button>
</el-row>
@@ -228,7 +229,7 @@ layout("/layouts/platform.html"){
},
methods: {
/**
* “作为建议”不再区分主办/协办,只保留办单位;
* “作为建议”不再区分主办/协办,只保留办单位;
* 切到“不予立案”等结果时,同时清空已选单位,避免旧值被误提交。
*/
handleCaseFilingResultChange(caseFilingResult) {
@@ -271,7 +272,7 @@ layout("/layouts/platform.html"){
cancelButtonText: "取消",
type: "warning"
}).then(() => {
// “作为建议”统一按办单位处理,提交时不再携带协办单位数据。
// “作为建议”统一按办单位处理,提交时不再携带协办单位数据。
const masterUnitIds = this.formData.tf_masterUnitIds || []
const slaveUnitIds = this.formData.tf_caseFilingResult === "CONFIRM_FILING" ? (this.formData.tf_slaveUnitIds || []) : []
// 是否有协办单位
@@ -411,7 +412,7 @@ layout("/layouts/platform.html"){
})
},
// 查询办单位
// 查询办单位
listUnderTake() {
this.$axios.post("/platform/proposal/common/listUnderTake").then((res) => {
if (res.code === 0) {
@@ -31,7 +31,8 @@ const merge = {
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="['CONFIRM_FILING'].includes(formData.tf_caseFilingResult)" label="立案类型"
<!-- 普通提案/重点提案暂不展示,保留原字段和处理逻辑,便于兼容历史流程数据。 -->
<el-form-item v-if="false" label="立案类型"
prop="tf_caseFilingType"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-radio-group v-model="formData.tf_caseFilingType" size="small">
@@ -41,9 +42,9 @@ const merge = {
</el-radio-group>
</el-form-item>
<el-form-item
:label="formData.tf_caseFilingResult === 'SUGGESTION' ? '办单位' : '主办单位'"
:label="formData.tf_caseFilingResult === 'SUGGESTION' ? '办单位' : '主办单位'"
v-if="['CONFIRM_FILING','SUGGESTION'].includes(formData.tf_caseFilingResult)"
:rules="[{required:['CONFIRM_FILING','SUGGESTION'].includes(formData.tf_caseFilingResult),message:formData.tf_caseFilingResult === 'SUGGESTION' ? '请选择办单位' : '请选择主办单位',trigger:['change','blur']}]"
:rules="[{required:['CONFIRM_FILING','SUGGESTION'].includes(formData.tf_caseFilingResult),message:formData.tf_caseFilingResult === 'SUGGESTION' ? '请选择办单位' : '请选择主办单位',trigger:['change','blur']}]"
prop="tf_masterUnitIds"
>
<el-select v-model="formData.tf_masterUnitIds" filterable clearable multiple style="width: 100%">
@@ -77,7 +78,7 @@ const merge = {
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="$emit('close')" size="small">取消</el-button>
<el-button @click="$emit('close')" size="small">返回</el-button>
<el-button @click="handleTaskAction(6)" size="small" type="info">退回到提案人</el-button>
<el-button @click="handleTaskAction(1)" size="small" type="primary">提交</el-button>
</el-row>
@@ -104,7 +105,7 @@ const merge = {
methods: {
/**
* 并案审核与单案审核保持同一口径:
* “作为建议”只录入办单位,不再区分协办单位。
* “作为建议”只录入办单位,不再区分协办单位。
*/
handleCaseFilingResultChange(caseFilingResult) {
if (caseFilingResult !== "CONFIRM_FILING") {
@@ -132,7 +133,7 @@ const merge = {
}
this.selection.splice(index, 1)
},
// 查询办单位
// 查询办单位
listUnderTake() {
this.$axios.post("/platform/proposal/common/listUnderTake").then((res) => {
if (res.code === 0) {
@@ -121,7 +121,15 @@ layout("/layouts/platform.html"){
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="['CONFIRM_FILING'].includes(formData.tf_caseFilingResult)" label="立案类型"
<!-- 立案编号由审核人手工填写,仅确定立案时参与校验和保存。 -->
<el-form-item v-if="formData.tf_caseFilingResult === 'CONFIRM_FILING'"
label="立案编号"
prop="tf_caseFilingCode"
:rules="[{required:true,message:'请填写立案编号',trigger:['change','blur']}]">
<el-input v-model="formData.tf_caseFilingCode" clearable maxlength="20"
show-word-limit placeholder="请输入立案编号"></el-input>
</el-form-item>
<!-- <el-form-item v-if="['CONFIRM_FILING'].includes(formData.tf_caseFilingResult)" label="立案类型"
prop="tf_caseFilingType"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-radio-group v-model="formData.tf_caseFilingType" size="small">
@@ -129,11 +137,11 @@ layout("/layouts/platform.html"){
{{item.label}}
</el-radio>
</el-radio-group>
</el-form-item>
</el-form-item>-->
<el-form-item
:label="formData.tf_caseFilingResult === 'SUGGESTION' ? '办单位' : '主办单位'"
:label="formData.tf_caseFilingResult === 'SUGGESTION' ? '办单位' : '主办单位'"
v-if="['CONFIRM_FILING','SUGGESTION'].includes(formData.tf_caseFilingResult)"
:rules="[{required:['CONFIRM_FILING','SUGGESTION'].includes(formData.tf_caseFilingResult),message:formData.tf_caseFilingResult === 'SUGGESTION' ? '请选择办单位' : '请选择主办单位',trigger:['change','blur']}]"
:rules="[{required:['CONFIRM_FILING','SUGGESTION'].includes(formData.tf_caseFilingResult),message:formData.tf_caseFilingResult === 'SUGGESTION' ? '请选择办单位' : '请选择主办单位',trigger:['change','blur']}]"
prop="tf_masterUnitIds"
>
<el-select v-model="formData.tf_masterUnitIds" filterable clearable multiple
@@ -168,7 +176,7 @@ layout("/layouts/platform.html"){
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
<el-button @click="$refs.guava.index()" size="small">返回</el-button>
<el-button @click="handleTaskAction(6)" size="small" type="info">退回到提案人</el-button>
<el-button @click="handleTaskAction(1)" size="small" type="primary">提交</el-button>
</el-row>
@@ -223,11 +231,12 @@ layout("/layouts/platform.html"){
},
methods: {
/**
* “作为建议”场景下只保留办单位,协办单位和立案类型都要及时清空,
* “作为建议”场景下只保留办单位,协办单位和立案类型都要及时清空,
* 避免旧表单值跟着一起提交到流程里。
*/
handleCaseFilingResultChange(caseFilingResult) {
if (caseFilingResult !== "CONFIRM_FILING") {
this.$set(this.formData, "tf_caseFilingCode", "")
this.$set(this.formData, "tf_caseFilingType", "")
}
if (caseFilingResult === "SUGGESTION") {
@@ -281,9 +290,10 @@ layout("/layouts/platform.html"){
if (!val || !val.length) {
return
}
// 当前页面需要回显上一环节“提案委员会立案”保存的主办/协办单位或办单位。
// 当前页面需要回显上一环节“提案委员会立案”保存的主办/协办单位或办单位。
var data = val[val.length - 1]
this.$set(this.formData, "tf_caseFilingResult", data.ext.tf_caseFilingResult)
this.$set(this.formData, "tf_caseFilingCode", data.ext.tf_caseFilingCode || "")
this.$set(this.formData, "tf_caseFilingType", data.ext.tf_caseFilingType)
this.$set(this.formData, "tf_masterUnitIds", this.normalizeUnitIds(data.ext.tf_masterUnitIds))
this.$set(this.formData, "tf_slaveUnitIds", this.normalizeUnitIds(data.ext.tf_slaveUnitIds))
@@ -296,6 +306,7 @@ layout("/layouts/platform.html"){
proposalId: row.id,
processTaskId: row.taskId,
taskName: row.curTaskName,
tf_caseFilingCode: "",
tf_masterUnitIds: [],
tf_slaveUnitIds: []
}
@@ -311,7 +322,7 @@ layout("/layouts/platform.html"){
cancelButtonText: "取消",
type: "warning"
}).then(() => {
// “作为建议”统一按办单位处理,提交时不再携带协办单位数据。
// “作为建议”统一按办单位处理,提交时不再携带协办单位数据。
const masterUnitIds = this.formData.tf_masterUnitIds || []
const slaveUnitIds = this.formData.tf_caseFilingResult === "CONFIRM_FILING" ? (this.formData.tf_slaveUnitIds || []) : []
// 是否有协办单位
@@ -436,7 +447,7 @@ layout("/layouts/platform.html"){
})
},
// 查询办单位
// 查询办单位
listUnderTake() {
this.$axios.post("/platform/proposal/common/listUnderTake").then((res) => {
if (res.code === 0) {
@@ -64,7 +64,7 @@ layout("/layouts/platform.html"){
</el-form-item>
</el-form>
<span slot="footer">
<el-button size="small" @click="jumpDialogVisible = false">取消</el-button>
<el-button size="small" @click="jumpDialogVisible = false">返回</el-button>
<el-button size="small" type="primary" @click="doJump">确定</el-button>
</span>
</el-dialog>
@@ -81,7 +81,7 @@ layout("/layouts/platform.html"){
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
<el-button @click="$refs.guava.index()" size="small">返回</el-button>
<el-button @click="handleTaskAction(6)" size="small" type="info">退回到提案人</el-button>
<el-button @click="handleTaskAction(2)" size="small" type="danger">不同意</el-button>
<el-button @click="handleTaskAction(1)" size="small" type="primary">同意</el-button>
@@ -94,7 +94,7 @@ layout("/layouts/platform.html"){
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
<el-button @click="$refs.guava.index()" size="small">返回</el-button>
<el-button @click="handleTaskAction(1)" size="small" type="primary">提交</el-button>
</el-row>
</div>
@@ -85,7 +85,7 @@ layout("/layouts/platform.html"){
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
<el-button @click="$refs.guava.index()" size="small">返回</el-button>
<el-button @click="handleTaskAction(4)" size="small" type="info">退回到提案人(不审核)</el-button>
<el-button @click="handleTaskAction(6)" size="small" type="info">退回到提案人(审核)</el-button>
<el-button @click="handleTaskAction(2)" size="small" type="danger">不同意</el-button>
@@ -119,7 +119,7 @@ layout("/layouts/platform.html"){
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
<el-button @click="$refs.guava.index()" size="small">返回</el-button>
<el-button @click="handleTaskAction('back')" size="small" type="danger">退回提委会立案</el-button>
<el-button @click="handleTaskAction('agree')" size="small" type="primary">同意</el-button>
</el-row>
@@ -146,7 +146,7 @@ layout("/layouts/platform.html"){
{label: "提案编号", prop: "code"},
{label: "提案名称", prop: "name", width: "200px"},
{label: "提案类别", prop: "typeName"},
{label: "办单位", prop: "undertakeUnits", width: "260px"},
{label: "办单位", prop: "undertakeUnits", width: "260px"},
{label: "是否并案", prop: "merge"},
{label: "当前节点", prop: "curTaskName"},
{label: "审核人", prop: "auditUser"},
@@ -164,8 +164,8 @@ layout("/layouts/platform.html"){
},
methods: {
/**
* 校领导审批列表需要按立案结果切换办单位展示口径:
* 确定立案显示主办/协办,作为建议只显示办单位。
* 校领导审批列表需要按立案结果切换办单位展示口径:
* 确定立案显示主办/协办,作为建议只显示办单位。
*/
getUndertakeDisplay(row) {
var masterUnitNames = this.formatUnitNames(row.masterUnitName)
@@ -81,12 +81,12 @@ layout("/layouts/platform.html"){
</el-form-item>
</el-form>
<el-row type="flex" justify="end" v-if="row.curTaskCode ==='second'">
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
<el-button @click="$refs.guava.index()" size="small">返回返回</el-button>
<el-button @click="handleTaskAction(20)" size="small" type="danger">不同意</el-button>
<el-button @click="handleTaskAction(1)" size="small" type="primary">同意</el-button>
</el-row>
<el-row type="flex" justify="end" v-else>
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
<el-button @click="$refs.guava.index()" size="small">返回</el-button>
<el-button @click="updateSecond(2)" size="small" type="danger">不同意</el-button>
<el-button @click="updateSecond(1)" size="small" type="primary">同意</el-button>
</el-row>
@@ -143,7 +143,7 @@ layout("/layouts/platform.html"){
<proposal-info ref="proposalInfoRef">
<div v-if="showApprovalForm">
<div class="process-title">
办单位意见
单位意见
</div>
<el-form :model="formData" ref="formRef" label-width="80px" :rules="formRules" label-suffix="">
<el-form-item label="承办意向" prop="result"
@@ -160,7 +160,7 @@ layout("/layouts/platform.html"){
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
<el-button @click="$refs.guava.index()" size="small">返回</el-button>
<el-button @click="onAudit()" size="small" type="primary">提交</el-button>
</el-row>
</div>
@@ -208,7 +208,7 @@ layout("/layouts/platform.html"){
{label: "提案类别", prop: "typeName"},
{label: "届次", prop: "sessionName"},
{label: "代表团", prop: "delegationName"},
{label: "建议办单位", prop: "suggestUnits"},
{label: "建议办单位", prop: "suggestUnits"},
{label: "意见数", prop: "count"},
{label: "当前节点", prop: "curTaskName"},
{label: "流程状态", prop: "instanceState"}
@@ -83,7 +83,7 @@ layout("/layouts/platform.html"){
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
<el-button @click="$refs.guava.index()" size="small">返回</el-button>
<el-button @click="handleTaskAction(6)" size="small" type="info">退回到提案人</el-button>
<el-button @click="handleTaskAction(2)" size="small" type="danger">不同意</el-button>
<el-button @click="handleTaskAction(1)" size="small" type="primary">同意</el-button>
@@ -75,7 +75,7 @@ layout("/layouts/platform.html"){
<el-tag v-else size="mini" type="info"></el-tag>
</template>
</el-table-column>
<el-table-column label="办单位" prop="underTakeName" show-overflow-tooltip></el-table-column>
<el-table-column label="办单位" prop="underTakeName" show-overflow-tooltip></el-table-column>
<el-table-column label="当前节点" prop="processInstanceNodeName" show-overflow-tooltip></el-table-column>
<el-table-column label="操作" fixed="right" width="100px">
<template scope="{row}">
@@ -105,7 +105,7 @@ layout("/layouts/platform.html"){
<el-divider></el-divider>
<el-form :model="formData" ref="approvalFormRef" label-position="left" label-width="80px">
<el-form-item label="办单位">
<el-form-item label="办单位">
<el-input :value="formData.underTakeName" disabled></el-input>
</el-form-item>
<el-form-item label="能否承办" prop="canTake" :rules="[{required:true,message:'必填',trigger:['change','blur']}]">
@@ -128,7 +128,7 @@ layout("/layouts/platform.html"){
<!-- </el-form-item>-->
</el-form>
<el-row type="flex" justify="end">
<el-button plain @click="$refs.guava.index()">取消</el-button>
<el-button plain @click="$refs.guava.index()">返回</el-button>
<el-button type="primary" @click="doApproval('DYNAMIC')">提交</el-button>
</el-row>
</div>
@@ -148,7 +148,7 @@ layout("/layouts/platform.html"){
</el-button>
<el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">撤回
</el-button>
<!--办单位领导、超级管理员才能转办-->
<!--单位领导、超级管理员才能转办-->
<el-button v-if="!pageForm.approval && $auth.hasRoleOr('SYSADMIN,PROPOSAL_UNIT_LEADER')"
@click="openTransfer(row)" size="mini" type="primary">转交
</el-button>
@@ -165,7 +165,7 @@ layout("/layouts/platform.html"){
{{formData.taskName}}
</div>
<el-form :model="formData" ref="formRef" label-width="80px" :rules="formRules" label-suffix="">
<el-form-item label="办单位">
<el-form-item label="办单位">
<el-input :value="formData.underTakeName" disabled></el-input>
</el-form-item>
<el-form-item label="落实情况" prop="tf_implementState"
@@ -200,7 +200,7 @@ layout("/layouts/platform.html"){
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
<el-button @click="$refs.guava.index()" size="small">返回</el-button>
<!-- <el-button @click="handleTaskAction(6)" size="small" type="info">退回到发起人</el-button>-->
<el-button @click="handleTaskAction(1)" size="small" type="primary">提交</el-button>
</el-row>
@@ -246,7 +246,7 @@ layout("/layouts/platform.html"){
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="showTransferDialog = false" size="small">取消</el-button>
<el-button @click="showTransferDialog = false" size="small">返回</el-button>
<el-button @click="handleTransfer" size="small" type="primary">提交</el-button>
</el-row>
</el-dialog>
@@ -265,7 +265,7 @@ layout("/layouts/platform.html"){
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="showReplyEditDialog = false" size="small">取消</el-button>
<el-button @click="showReplyEditDialog = false" size="small">返回</el-button>
<el-button @click="handleReplyEdit" size="small" type="primary">保存</el-button>
</el-row>
</el-dialog>
@@ -291,7 +291,7 @@ layout("/layouts/platform.html"){
{label: "提案类别", prop: "typeName"},
{label: "立案结果", prop: "caseFilingResult"},
{label: "是否并案", prop: "merge"},
{label: "办单位", prop: "underTakeName"},
{label: "办单位", prop: "underTakeName"},
{label: "承办类型", prop: "underTakeIsMaster"},
{label: "当前节点", prop: "curTaskName"},
{label: "审核人", prop: "auditUser"},
@@ -134,9 +134,9 @@ layout("/layouts/platform.html"){
<!-- ></el-input>-->
<!-- </el-form-item>-->
<el-form-item label="建议办单位" prop="suggestUnits" v-if="false">
<el-form-item label="建议办单位" prop="suggestUnits" v-if="false">
<el-select v-model="formData.suggestUnits" multiple filterable style="width: 100%"
placeholder="请选择建议办单位">
placeholder="请选择建议办单位">
<el-option :key="item.id" :label="item.name" :value="item.name"
v-for="item in suggestUnitOptions"></el-option>
</el-select>
@@ -270,7 +270,7 @@ layout("/layouts/platform.html"){
sessionId: [{required: true, message: "请选择所属教代会", trigger: ["blur", "change"]}],
committeeId: [{required: true, message: "请选择所属委员会", trigger: ["blur", "change"]}],
typeId: [{required: true, message: "请选择提案类别", trigger: ["blur", "change"]}],
suggestUnits: [{required: true, message: "请选择建议办单位", trigger: ["blur", "change"]}],
suggestUnits: [{required: true, message: "请选择建议办单位", trigger: ["blur", "change"]}],
sign: [{required: true, message: "请扫描二维码进行签字", trigger: ["blur", "change"]}],
excerpt: [{required: true, message: "请填写", trigger: ["blur", "change"]}],
researchFindings: [{required: true, message: "请填写", trigger: ["blur", "change"]}],
@@ -285,7 +285,7 @@ layout("/layouts/platform.html"){
isWriteTime: true,
// 建议办单位
// 建议办单位
suggestUnitOptions: []
}
},
@@ -474,7 +474,7 @@ layout("/layouts/platform.html"){
},
// 建议办单位
// 建议办单位
listSuggestUnit() {
this.$axios.post("/platform/proposal/common/listUnderTake").then((res) => {
if (res.code === 0) {
@@ -34,15 +34,32 @@ const BASIC_TABLE_COMPONENT = {
<el-dialog :visible.sync="dialogFormVisible" :title="isEdit ? '编辑' : '新增'" width="40%">
<el-form :model="formData" ref="formRef" :rules="rules" label-width="100px">
<el-form-item label="上级机构名称">
<el-input :value="parentName || '-'" disabled></el-input>
</el-form-item>
<el-form-item label="机构名称" prop="name">
<el-input placeholder="请输入机构名称" v-model="formData.name"></el-input>
</el-form-item>
<el-form-item label="机构代码" prop="code">
<el-input placeholder="请输入机构代码" v-model="formData.code" :disabled="isEdit"></el-input>
</el-form-item>
<template v-if="!isEdit">
<el-form-item label="机构名称" prop="institutionPath">
<el-cascader
v-model="formData.institutionPath"
:options="treeList"
:props="cascaderProps"
@change="institutionChange"
placeholder="请选择机构"
style="width: 100%"
></el-cascader>
</el-form-item>
<el-form-item label="机构代码">
<el-input :value="formData.code" disabled placeholder="选择机构后自动带出"></el-input>
</el-form-item>
</template>
<template v-else>
<el-form-item label="上级机构名称">
<el-input :value="parentName || '-'" disabled></el-input>
</el-form-item>
<el-form-item label="机构名称" prop="name">
<el-input placeholder="请输入机构名称" v-model="formData.name"></el-input>
</el-form-item>
<el-form-item label="机构代码" prop="code">
<el-input placeholder="请输入机构代码" v-model="formData.code" disabled></el-input>
</el-form-item>
</template>
<el-form-item label="排序编码" prop="location">
<el-input-number v-model="formData.location" :min="0" :step="1" style="width: 100%"></el-input-number>
</el-form-item>
@@ -75,6 +92,7 @@ const BASIC_TABLE_COMPONENT = {
data() {
return {
rules: {
institutionPath: [{ type: "array", required: true, message: "请选择机构", trigger: "change" }],
name: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
code: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
parentId: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
@@ -82,6 +100,14 @@ const BASIC_TABLE_COMPONENT = {
},
parentData: {},
parentIds: [],
treeList: [],
treeFlat: [],
cascaderProps: {
checkStrictly: true,
multiple: false,
label: "name",
value: "id"
},
dialogFormVisible: false,
isEdit: false
}
@@ -105,9 +131,11 @@ const BASIC_TABLE_COMPONENT = {
this.isEdit = false
this.dialogFormVisible = true
this.formData = {
institutionPath: [],
parentId: this.parentId,
location: 0
}
this.listFormTree()
},
openEdit(row) {
this.isEdit = true
@@ -117,6 +145,29 @@ const BASIC_TABLE_COMPONENT = {
location: row.location || 0
}
},
/**
* 加载“双代会固定机构”字典树,新增机构只能从该树中选择。
* 接口返回 treeList 用于级联展示,treeFlat 用于按所选字典ID回填名称和代码。
*/
listFormTree() {
this.$axios.post("/platform/teacherCongress/institution/formTree", {
sessionId: this.sessionId
}).then((res) => {
if (res.code === 0) {
this.treeList = res.data.treeList || []
this.treeFlat = res.data.treeFlat || []
}
})
},
/**
* 固定机构选择变化后回填业务名称和机构代码;清空选择时同步清空旧值。
*/
institutionChange(institutionPath) {
const institutionId = institutionPath.length ? institutionPath[institutionPath.length - 1] : null
const institution = this.treeFlat.find(item => item.id === institutionId)
this.$set(this.formData, "name", institution ? institution.name : "")
this.$set(this.formData, "code", institution ? institution.code : "")
},
isBasicInstitution(index) {
const pageNumber = this.pageForm.pageNumber || 1
const pageSize = this.pageForm.pageSize || 10
@@ -127,12 +178,18 @@ const BASIC_TABLE_COMPONENT = {
if (!valid) {
return
}
this.formData.sessionId = this.sessionId
const params = {
...this.formData,
sessionId: this.sessionId
}
if (!this.isEdit) {
this.formData.parentId = this.parentId
const institutionPath = this.formData.institutionPath || []
// 下级机构先提交固定字典中的父级ID,由后端转换为当前届次的实际父机构ID。
params.parentId = institutionPath.length > 1 ? institutionPath[institutionPath.length - 2] : this.parentId
delete params.institutionPath
}
const url = this.isEdit ? loc() + "/update" : loc() + "/insert"
this.$axios.post(url, this.formData).then((res) => {
this.$axios.post(url, params).then((res) => {
if (res.code === 0) {
this.dialogFormVisible = false
this.$message.success(res.msg)
@@ -49,8 +49,9 @@ layout("/layouts/platform.html"){
"basic-table": BASIC_TABLE_COMPONENT
},
computed: {
// 根节点即使尚无子机构也要展示机构列表,确保空届次可以创建第一条机构。
hasChildInstitution() {
return this.currentTreeData && this.currentTreeData.children && this.currentTreeData.children.length > 0
return this.currentTreeData && (this.currentTreeData.id === "0" || (this.currentTreeData.children && this.currentTreeData.children.length > 0))
}
},
data() {
@@ -35,6 +35,7 @@ layout("/layouts/platform.html"){
<el-table-column prop="year" label="年份" sortable></el-table-column>
<el-table-column prop="j" label="届数" sortable></el-table-column>
<el-table-column prop="c" label="次数" sortable></el-table-column>
<el-table-column prop="proposalType" label="提案类型" show-overflow-tooltip></el-table-column>
<el-table-column prop="description" label="描述"></el-table-column>
<el-table-column prop="startDate" label="开启时间"></el-table-column>
<el-table-column prop="enable" label="开启状态">
@@ -78,6 +79,15 @@ layout("/layouts/platform.html"){
<dict-select v-model="formData.c" code="TEACHER_CONGRESS_C"></dict-select>
</el-form-item>
<!-- 支持复用历史类型,也允许直接输入并创建新的届次提案类型。 -->
<el-form-item prop="proposalType" label="提案类型">
<el-select v-model="formData.proposalType" clearable filterable allow-create default-first-option
placeholder="请选择或输入提案类型" style="width: 100%">
<el-option v-for="item in proposalTypeOptions" :key="item.proposalType"
:label="item.proposalType" :value="item.proposalType"></el-option>
</el-select>
</el-form-item>
<el-form-item prop="description" label="描述">
<el-input type="textarea" :rows="2" style="width: 100%" placeholder="请输入教代会描述"
v-model="formData.description"></el-input>
@@ -139,12 +149,17 @@ layout("/layouts/platform.html"){
year: [{required: true, message: "必填", trigger: ["change", "blur"]}],
j: [{required: true, message: "必填", trigger: ["change", "blur"]}],
c: [{required: true, message: "必填", trigger: ["change", "blur"]}],
proposalType: [
{required: true, message: "请选择或输入提案类型", trigger: ["change", "blur"]},
{max: 50, message: "提案类型最多50个字", trigger: ["change", "blur"]}
],
enable: [{required: true, message: "必填", trigger: ["change", "blur"]}],
description: [{required: true, message: "必填", trigger: ["change", "blur"]}],
isExtend: [{required: true, message: "必填", trigger: ["change", "blur"]}],
collectStartTime: [{required: true, message: "必填", trigger: ["change", "blur"]}],
collectEndTime: [{required: true, message: "必填", trigger: ["change", "blur"]}]
}
},
proposalTypeOptions: []
}
},
methods: {
@@ -152,6 +167,7 @@ layout("/layouts/platform.html"){
this.dialogFormVisible = true
this.$nextTick(() => {
this.formData = {}
this.$set(this.formData, "proposalType", "")
})
},
openEdit(id) {
@@ -173,6 +189,7 @@ layout("/layouts/platform.html"){
this.dialogFormVisible = false
this.$message.success(res.msg)
this.doSearch()
this.listProposalTypes()
}
}).finally(() => {
loading.close()
@@ -194,10 +211,20 @@ layout("/layouts/platform.html"){
}
})
})
},
// 查询历史届次已保存的提案类型,作为可输入下拉框的候选项。
listProposalTypes() {
this.$axios.post(loc() + "/listProposalTypes").then((res) => {
if (res.code === 0) {
this.proposalTypeOptions = res.data || []
}
})
}
},
created() {
this.pageData()
this.listProposalTypes()
}
})
</script>
@@ -65,6 +65,7 @@ layout("/layouts/platform.html"){
</table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder"
ref="table" row-key="id" style="width: 100%"
v-loading="tableLoading"
:summary-method="getSummaries" :show-summary="showSummary">
<el-table-column type="index" width="50px" label="序号" :index="indexMethod"
fixed="left"></el-table-column>
@@ -10,6 +10,7 @@ const PROPOSAL_INFO = {
</div>
</van-cell>
<van-cell title="提案编号">{{ viewData.code }}</van-cell>
<van-cell title="立案编号">{{ viewData.caseFilingCode || '暂无' }}</van-cell>
<van-cell title="提案人">{{ viewData.createUserName }}</van-cell>
<van-cell title="提案时间">{{ viewData.createTime }}</van-cell>
<van-cell title="教代会届次">{{ viewData.fullName }}</van-cell>
+2 -2
View File
@@ -83,8 +83,8 @@ public class JugTest {
@Test
public void userPwd(){
List<Sys_user> users = dao.query(Sys_user.class, Cnd.where("loginname","in",List.of("safeadmin","safemember")));
String pwd = "@Gonghui_jshvc1024";
List<Sys_user> users = dao.query(Sys_user.class, Cnd.NEW());
String pwd = "@Dd3s#2016!26";
for (Sys_user user : users) {
user.setSalt(R.UU32());
user.setPassword(PwdUtil.getPassword(pwd, user.getSalt()));