commit
This commit is contained in:
@@ -7,6 +7,8 @@ import cn.hutool.core.lang.tree.Tree;
|
||||
import cn.hutool.core.lang.tree.TreeNode;
|
||||
import cn.hutool.core.lang.tree.TreeUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.exception.BaseException;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
@@ -263,7 +265,7 @@ public class SysUnionController {
|
||||
if (Lang.isEmpty(branchUnionRoles)) {
|
||||
return Result.success();
|
||||
}
|
||||
List<String> branchUnionRoleCodes = branchUnionRoles.stream().map(Sys_dict::getCode).toList();
|
||||
List<String> branchUnionRoleCodes = getBranchUnionRoleCodes(branchUnionRoles);
|
||||
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
@@ -338,7 +340,7 @@ public class SysUnionController {
|
||||
if (Lang.isEmpty(branchUnionRoles)) {
|
||||
return Result.success(List.of());
|
||||
}
|
||||
List<String> branchUnionRoleCodes = branchUnionRoles.stream().map(Sys_dict::getCode).toList();
|
||||
List<String> branchUnionRoleCodes = getBranchUnionRoleCodes(branchUnionRoles);
|
||||
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT DISTINCT
|
||||
@@ -371,6 +373,41 @@ public class SysUnionController {
|
||||
return Result.success(usedJCodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询分工会干部角色选项,并补充按单位授权的二级党委书记角色。
|
||||
*
|
||||
* @return 角色编码和名称
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("sys.manager.union.branchOfficer")
|
||||
public Result branchUnionRoleOptions() {
|
||||
List<NutMap> roleOptions = sysDictService.getSubListByCode("BRANCH_UNION_ROLES").stream()
|
||||
.map(item -> NutMap.NEW().addv("code", item.getCode()).addv("name", item.getName()))
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
if (sysRoleService.getByCode(RoleConstant.UNIT_PARTY_SECRETARY) != null
|
||||
&& roleOptions.stream().noneMatch(item -> RoleConstant.UNIT_PARTY_SECRETARY.name().equals(item.getString("code")))) {
|
||||
roleOptions.add(NutMap.NEW().addv("code", RoleConstant.UNIT_PARTY_SECRETARY.name()).addv("name", "二级党委书记"));
|
||||
}
|
||||
return Result.success(roleOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询当前分工会可配置二级党委书记的组成单位。
|
||||
*
|
||||
* @param unionId 分工会ID
|
||||
* @return 当前分工会的二级单位
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("sys.manager.union.branchOfficer")
|
||||
public Result branchUnionPartySecretaryUnitOptions(String unionId) {
|
||||
if (StrUtil.isBlank(unionId)) {
|
||||
return Result.error("分工会参数不能为空");
|
||||
}
|
||||
List<Sys_unit> units = dao.query(Sys_unit.class, Cnd.where("unionId", "=", unionId)
|
||||
.and("unitLevel", "=", 2).asc("unitcode"));
|
||||
return Result.success(units);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("sys.manager.union.branchOfficer")
|
||||
@ApiOperation("添加分工会人员角色")
|
||||
@@ -444,6 +481,76 @@ public class SysUnionController {
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发起二级党委书记授权审批。一个审批申请可关联当前分工会下的多个单位。
|
||||
* 审核通过后由流程拦截器按单位写入角色,避免影响普通分工会角色的授权方式。
|
||||
*
|
||||
* @param userId 人员ID
|
||||
* @param unionId 分工会ID
|
||||
* @param unitIds 组成单位ID集合
|
||||
* @param j 届次
|
||||
* @return 处理结果
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("sys.manager.union.branchOfficer")
|
||||
@ApiOperation("添加二级党委书记角色")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Result insertBranchUnionPartySecretaryRole(String userId, String unionId, @Param("unitIds") String[] unitIds, String j) {
|
||||
if (StrUtil.isBlank(userId) || StrUtil.isBlank(unionId) || Lang.isEmpty(unitIds)) {
|
||||
return Result.error("人员、分工会和所属单位不能为空");
|
||||
}
|
||||
Sys_role role = sysRoleService.getByCode(RoleConstant.UNIT_PARTY_SECRETARY);
|
||||
if (role == null) {
|
||||
return Result.error("未配置二级党委书记角色");
|
||||
}
|
||||
View_user user = dao.fetch(View_user.class, Cnd.where("id", "=", userId));
|
||||
if (user == null || !unionId.equals(user.getUnionId())) {
|
||||
return Result.error("所选人员不属于当前分工会");
|
||||
}
|
||||
List<String> distinctUnitIds = java.util.Arrays.stream(unitIds)
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.distinct()
|
||||
.toList();
|
||||
List<Sys_unit> units = dao.query(Sys_unit.class, Cnd.where("id", "in", distinctUnitIds)
|
||||
.and("unionId", "=", unionId).and("unitLevel", "=", 2));
|
||||
if (units.size() != distinctUnitIds.size()) {
|
||||
return Result.error("所属单位包含非当前分工会的单位");
|
||||
}
|
||||
int roleCount = dao.count(Sys_user_role.class, Cnd.where("roleId", "=", role.getId())
|
||||
.and("userId", "=", userId).and("unionId", "=", unionId));
|
||||
if (roleCount > 0) {
|
||||
return Result.error("该人员已设置二级党委书记,请先删除后再重新设置");
|
||||
}
|
||||
|
||||
Sys_union_cadre unionCadre = new Sys_union_cadre();
|
||||
unionCadre.setUserId(userId);
|
||||
unionCadre.setUnionId(unionId);
|
||||
unionCadre.setMobile(user.getMobile());
|
||||
unionCadre.setUnionName(user.getUnionName());
|
||||
unionCadre.setLoginName(user.getLoginname());
|
||||
unionCadre.setUserName(user.getUsername());
|
||||
unionCadre.setRoleCode(RoleConstant.UNIT_PARTY_SECRETARY.name());
|
||||
unionCadre.setJ(j);
|
||||
unionCadre.setApplyDate(new Date());
|
||||
unionCadre.setIsServing(true);
|
||||
unionCadre.setIsJoin(true);
|
||||
dao.insert(unionCadre);
|
||||
|
||||
JSONObject formData = JSONUtil.parseObj(unionCadre);
|
||||
formData.set("unitIds", distinctUnitIds);
|
||||
Dict args = Dict.create();
|
||||
boolean isAdmin = AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name());
|
||||
args.set("submit", isAdmin ? "admin" : "branch");
|
||||
args.set(FlowConst.SUBMIT_TYPE, ProcessSubmitTypeEnum.APPLY.getCode());
|
||||
args.set(FlowConst.FORM_DATA, formData.toString());
|
||||
ProcessInstance instance = flowEngine.startProcessInstanceByKey("JCGHWY", unionCadre.getId(), SecurityUtil.getUserId(), args);
|
||||
List<ProcessTask> doingTaskList = flowEngine.processTaskService().getDoingTaskList(instance.getId(), null);
|
||||
for (ProcessTask task : doingTaskList) {
|
||||
flowEngine.executeProcessTask(task.getId(), SecurityUtil.getUserId(), args);
|
||||
}
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("分工会干部离任")
|
||||
@SaCheckPermission("sys.manager.union.branchOfficer")
|
||||
@@ -504,6 +611,18 @@ public class SysUnionController {
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字典维护的分工会角色与单位级二级党委书记角色合并为列表查询范围。
|
||||
*/
|
||||
private List<String> getBranchUnionRoleCodes(List<Sys_dict> branchUnionRoles) {
|
||||
List<String> roleCodes = new ArrayList<>(branchUnionRoles.stream().map(Sys_dict::getCode).toList());
|
||||
if (sysRoleService.getByCode(RoleConstant.UNIT_PARTY_SECRETARY) != null
|
||||
&& !roleCodes.contains(RoleConstant.UNIT_PARTY_SECRETARY.name())) {
|
||||
roleCodes.add(RoleConstant.UNIT_PARTY_SECRETARY.name());
|
||||
}
|
||||
return roleCodes;
|
||||
}
|
||||
|
||||
|
||||
@At
|
||||
@ApiOperation("分工会组成单位分页")
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package com.budwk.app.sys.interceptor;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONArray;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.flow.constant.FlowConst;
|
||||
import com.budwk.app.flow.engine.FlowInterceptor;
|
||||
import com.budwk.app.flow.engine.core.Execution;
|
||||
@@ -13,6 +17,9 @@ import com.budwk.app.sys.services.SysUserService;
|
||||
import org.nutz.dao.Chain;
|
||||
import org.nutz.dao.Cnd;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author FKY
|
||||
@@ -35,14 +42,37 @@ public class SysUnionSchoolAuditInterceptor implements FlowInterceptor {
|
||||
SysUserService sysUserService = ServiceContext.find(SysUserService.class);
|
||||
|
||||
// 表单数据
|
||||
Sys_union_cadre unionBean = JSONUtil.toBean(formDataStr, Sys_union_cadre.class);
|
||||
JSONObject formData = JSONUtil.parseObj(formDataStr);
|
||||
Sys_union_cadre unionBean = JSONUtil.toBean(formData, Sys_union_cadre.class);
|
||||
|
||||
// 清除对应角色然后再新增
|
||||
Sys_role role = sysRoleService.getByCode(unionBean.getRoleCode());
|
||||
sysRoleService.clear("sys_user_role", Cnd.where("roleId", "=", role.getId())
|
||||
.and("userId", "=", unionBean.getUserId()).and("unionId", "=", unionBean.getUnionId()));
|
||||
sysRoleService.insert("sys_user_role", Chain.make("roleId", role.getId())
|
||||
.add("userId", unionBean.getUserId()).add("unionId", unionBean.getUnionId()));
|
||||
if (RoleConstant.UNIT_PARTY_SECRETARY.name().equals(unionBean.getRoleCode())) {
|
||||
// 二级党委书记按申请中选定的单位分别授权,保障流程可按申请人所属单位找到办理人。
|
||||
JSONArray unitIdArray = formData.getJSONArray("unitIds");
|
||||
List<String> unitIds = new ArrayList<>();
|
||||
if (unitIdArray != null) {
|
||||
for (Object unitId : unitIdArray) {
|
||||
String value = StrUtil.toString(unitId);
|
||||
if (StrUtil.isNotBlank(value) && !unitIds.contains(value)) {
|
||||
unitIds.add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (unitIds.isEmpty()) {
|
||||
throw new IllegalArgumentException("二级党委书记未选择所属单位");
|
||||
}
|
||||
for (String unitId : unitIds) {
|
||||
sysRoleService.insert("sys_user_role", Chain.make("roleId", role.getId())
|
||||
.add("userId", unionBean.getUserId()).add("unionId", unionBean.getUnionId()).add("unitId", unitId));
|
||||
}
|
||||
} else {
|
||||
// 其他分工会角色保持原有按分工会单条授权的逻辑。
|
||||
sysRoleService.insert("sys_user_role", Chain.make("roleId", role.getId())
|
||||
.add("userId", unionBean.getUserId()).add("unionId", unionBean.getUnionId()));
|
||||
}
|
||||
|
||||
// 清除缓存
|
||||
sysRoleService.clearCache();
|
||||
|
||||
@@ -148,6 +148,11 @@ public class SysRoleServiceImpl extends BaseServiceImpl<Sys_role> implements Sys
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void saveMenu(String[] menuIds, String roleId, String platform) {
|
||||
// 保存前确认权限均属于当前平台,防止PC端与H5端权限混写。
|
||||
List<Sys_menu> menus = sysMenuService.query(Cnd.where("id", "in", menuIds).and("platform", "=", platform));
|
||||
if (menus.size() != menuIds.length) {
|
||||
throw new BaseException("存在不属于当前平台的权限,无法保存");
|
||||
}
|
||||
//只清除对应平台的即可
|
||||
Sql sql = Sqls.queryString("""
|
||||
SELECT
|
||||
|
||||
+13
-24
@@ -17,7 +17,7 @@ import com.budwk.app.zhgh.activity.sports.service.ActivitySportsApplyUserService
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||
import org.nutz.dao.util.cri.Static;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.random.R;
|
||||
@@ -26,8 +26,6 @@ import org.nutz.mvc.annotation.Ok;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
import org.nutz.trans.Trans;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @author zhf
|
||||
* @date 2021/5/19 14:58
|
||||
@@ -57,7 +55,8 @@ public class ActivitySportsResultsController {
|
||||
PageForm page,
|
||||
String activityId,
|
||||
String eventId,
|
||||
String[] isMenWomen) {
|
||||
Integer isMenWomen,
|
||||
Integer projectType) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
@@ -79,22 +78,10 @@ public class ActivitySportsResultsController {
|
||||
cnd.and("ase.activityId", "=", activityId);
|
||||
cnd.andEX("abs.`name`", "=", groupName);
|
||||
cnd.andEX("ae.`id`", "=", eventId);
|
||||
SqlExpressionGroup sqlExpressionGroup = new SqlExpressionGroup();
|
||||
if (Arrays.stream(isMenWomen).anyMatch(a -> a.equals("2"))) {
|
||||
sqlExpressionGroup.and("ae.isMenWomen", "=", 1);
|
||||
}
|
||||
if (Arrays.stream(isMenWomen).anyMatch(a -> a.equals("3"))) {
|
||||
sqlExpressionGroup.or("ae.isMenWomen", "=", 2);
|
||||
}
|
||||
if (Arrays.stream(isMenWomen).anyMatch(a -> a.equals("4"))) {
|
||||
sqlExpressionGroup.and("ae.projectType", "=", 1);
|
||||
}
|
||||
if (Arrays.stream(isMenWomen).anyMatch(a -> a.equals("5"))) {
|
||||
sqlExpressionGroup.or("ae.projectType", "=", 2);
|
||||
}
|
||||
if (sqlExpressionGroup.getExps().size() > 0) {
|
||||
cnd.and(sqlExpressionGroup);
|
||||
}
|
||||
// 页面男子/女子选项值与活动项目性别字段保持一致:1 为男子,2 为女子。
|
||||
cnd.andEX("ae.isMenWomen", "=", isMenWomen);
|
||||
// 页面项目类型选项值与活动项目类型字段保持一致:1 为单项,2 为团体。
|
||||
cnd.andEX("ae.projectType", "=", projectType);
|
||||
cnd.desc("allName");
|
||||
sql.setCondition(cnd);
|
||||
return Result.success(baseService.listPageMap(page.getPageNumber(), page.getPageSize(), sql));
|
||||
@@ -192,8 +179,9 @@ public class ActivitySportsResultsController {
|
||||
cnd.and("asa.activityId", "=", activityId);
|
||||
cnd.and("asa.eventId", "=", eventId);
|
||||
cnd.and("asa.awardsMode", "=", 1);
|
||||
if (isMenWomen != null && isMenWomen == 1) cnd.and("u.sex", "=", "男性");
|
||||
if (isMenWomen != null && isMenWomen == 2) cnd.and("u.sex", "=", "女性");
|
||||
// 兼容历史人员“男性/女性”和临时添加人员“男/女”的性别值。
|
||||
if (isMenWomen != null && isMenWomen == 1) cnd.and(new Static("u.sex IN ('男', '男性')"));
|
||||
if (isMenWomen != null && isMenWomen == 2) cnd.and(new Static("u.sex IN ('女', '女性')"));
|
||||
sql.setCondition(cnd);
|
||||
return Result.success(activitySchoolApplyViService.listMap(sql));
|
||||
}
|
||||
@@ -268,8 +256,9 @@ public class ActivitySportsResultsController {
|
||||
""");
|
||||
cnd.and("ar.activityId", "=", activityId);
|
||||
cnd.and("ar.eventId", "=", eventId);
|
||||
if (isMenWomen != null && isMenWomen == 1) cnd.and("u.sex", "=", "男性");
|
||||
if (isMenWomen != null && isMenWomen == 2) cnd.and("u.sex", "=", "女性");
|
||||
// 兼容历史人员“男性/女性”和临时添加人员“男/女”的性别值。
|
||||
if (isMenWomen != null && isMenWomen == 1) cnd.and(new Static("u.sex IN ('男', '男性')"));
|
||||
if (isMenWomen != null && isMenWomen == 2) cnd.and(new Static("u.sex IN ('女', '女性')"));
|
||||
cnd.asc("ar.ranking");
|
||||
sql.setCondition(cnd);
|
||||
return Result.success(baseService.listMap(sql));
|
||||
|
||||
+7
@@ -22,6 +22,7 @@ import com.budwk.app.zhgh.activity.workscollection.models.Activity_works_collect
|
||||
import com.budwk.app.zhgh.activity.workscollection.models.Activity_works_collection_upload;
|
||||
import com.budwk.app.zhgh.activity.workscollection.models.Activity_works_subjectType;
|
||||
import com.budwk.app.zhgh.activity.workscollection.models.Activity_works_worksType;
|
||||
import com.budwk.app.zhgh.activity.workscollection.service.ActivityWorksCollectionService;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Chain;
|
||||
import org.nutz.dao.Cnd;
|
||||
@@ -50,6 +51,8 @@ public class ActivityWorksCollectionManageController {
|
||||
@Inject
|
||||
private Dao dao;
|
||||
@Inject
|
||||
private ActivityWorksCollectionService activityWorksCollectionService;
|
||||
@Inject
|
||||
private BaseService baseService;
|
||||
@Inject
|
||||
private SysMsgService sysMsgService;
|
||||
@@ -202,6 +205,10 @@ public class ActivityWorksCollectionManageController {
|
||||
@SaCheckPermission(value = {"activity.workscollection.manage", "activity.workscollection.new"}, mode = SaMode.OR)
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Result update(@Param("data") @Valid Activity_works_collection worksCollection) {
|
||||
String validateMessage = activityWorksCollectionService.validateReferencedTypesBeforeUpdate(worksCollection);
|
||||
if (StrUtil.isNotBlank(validateMessage)) {
|
||||
return Result.error(validateMessage);
|
||||
}
|
||||
dao.update(worksCollection);
|
||||
dao.updateLinks(worksCollection, "subjectTypes");
|
||||
dao.insertLinks(worksCollection, "subjectTypes");
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.budwk.app.zhgh.activity.workscollection.service;
|
||||
|
||||
import com.budwk.app.zhgh.activity.workscollection.models.Activity_works_collection;
|
||||
|
||||
/**
|
||||
* 作品征集活动配置服务。
|
||||
*/
|
||||
public interface ActivityWorksCollectionService {
|
||||
|
||||
/**
|
||||
* 校验编辑活动时删除的主题类型、作品类型是否已被投稿引用。
|
||||
*
|
||||
* @param worksCollection 前端提交的活动及其主题、作品类型配置
|
||||
* @return 校验通过返回 {@code null};校验不通过返回提示信息
|
||||
*/
|
||||
String validateReferencedTypesBeforeUpdate(Activity_works_collection worksCollection);
|
||||
}
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
package com.budwk.app.zhgh.activity.workscollection.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.zhgh.activity.workscollection.models.Activity_works_collection;
|
||||
import com.budwk.app.zhgh.activity.workscollection.models.Activity_works_collection_upload;
|
||||
import com.budwk.app.zhgh.activity.workscollection.models.Activity_works_subjectType;
|
||||
import com.budwk.app.zhgh.activity.workscollection.models.Activity_works_worksType;
|
||||
import com.budwk.app.zhgh.activity.workscollection.service.ActivityWorksCollectionService;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 作品征集活动配置服务实现。
|
||||
*/
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class ActivityWorksCollectionServiceImpl implements ActivityWorksCollectionService {
|
||||
|
||||
private final Dao dao;
|
||||
|
||||
public ActivityWorksCollectionServiceImpl(Dao dao) {
|
||||
this.dao = dao;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String validateReferencedTypesBeforeUpdate(Activity_works_collection worksCollection) {
|
||||
if (worksCollection == null || StrUtil.isBlank(worksCollection.getId())) {
|
||||
return null;
|
||||
}
|
||||
List<Activity_works_subjectType> persistedSubjectTypes = dao.query(Activity_works_subjectType.class,
|
||||
Cnd.where(Activity_works_subjectType::getActivityId, "=", worksCollection.getId()));
|
||||
List<Activity_works_subjectType> submittedSubjectTypes = CollUtil.defaultIfEmpty(worksCollection.getSubjectTypes(), Collections.emptyList());
|
||||
Set<String> submittedSubjectIds = submittedSubjectTypes.stream()
|
||||
.map(Activity_works_subjectType::getId)
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
List<Activity_works_subjectType> deletedSubjectTypes = persistedSubjectTypes.stream()
|
||||
.filter(subjectType -> !submittedSubjectIds.contains(subjectType.getId()))
|
||||
.toList();
|
||||
String subjectError = getReferencedSubjectTypeError(worksCollection.getId(), deletedSubjectTypes);
|
||||
if (subjectError != null) {
|
||||
return subjectError;
|
||||
}
|
||||
|
||||
for (Activity_works_subjectType submittedSubjectType : submittedSubjectTypes) {
|
||||
if (submittedSubjectType == null || StrUtil.isBlank(submittedSubjectType.getId())) {
|
||||
continue;
|
||||
}
|
||||
List<Activity_works_worksType> persistedWorksTypes = dao.query(Activity_works_worksType.class,
|
||||
Cnd.where(Activity_works_worksType::getSubjectId, "=", submittedSubjectType.getId()));
|
||||
List<Activity_works_worksType> submittedWorksTypes = CollUtil.defaultIfEmpty(submittedSubjectType.getWorksTypes(), Collections.emptyList());
|
||||
Set<String> submittedWorksIds = submittedWorksTypes.stream()
|
||||
.map(Activity_works_worksType::getId)
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.collect(Collectors.toSet());
|
||||
List<Activity_works_worksType> deletedWorksTypes = persistedWorksTypes.stream()
|
||||
.filter(worksType -> !submittedWorksIds.contains(worksType.getId()))
|
||||
.toList();
|
||||
String worksError = getReferencedWorksTypeError(worksCollection.getId(), deletedWorksTypes);
|
||||
if (worksError != null) {
|
||||
return worksError;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验待删除主题类型是否已有投稿,防止投稿的主题类型关联被清空。
|
||||
*/
|
||||
private String getReferencedSubjectTypeError(String activityId, List<Activity_works_subjectType> deletedSubjectTypes) {
|
||||
if (CollUtil.isEmpty(deletedSubjectTypes)) {
|
||||
return null;
|
||||
}
|
||||
List<String> deletedSubjectIds = deletedSubjectTypes.stream()
|
||||
.map(Activity_works_subjectType::getId)
|
||||
.collect(Collectors.toList());
|
||||
List<Activity_works_collection_upload> uploads = dao.query(Activity_works_collection_upload.class,
|
||||
Cnd.where(Activity_works_collection_upload::getActivityId, "=", activityId)
|
||||
.and(Activity_works_collection_upload::getSubjectId, "in", deletedSubjectIds));
|
||||
if (CollUtil.isEmpty(uploads)) {
|
||||
return null;
|
||||
}
|
||||
Set<String> referencedSubjectIds = uploads.stream()
|
||||
.map(Activity_works_collection_upload::getSubjectId)
|
||||
.collect(Collectors.toSet());
|
||||
String typeNames = deletedSubjectTypes.stream()
|
||||
.filter(subjectType -> referencedSubjectIds.contains(subjectType.getId()))
|
||||
.map(Activity_works_subjectType::getTypeName)
|
||||
.collect(Collectors.joining("、"));
|
||||
return "主题类型“" + typeNames + "”下已有投稿,不能删除";
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验待删除作品类型是否已有投稿,防止投稿的作品类型关联被清空。
|
||||
*/
|
||||
private String getReferencedWorksTypeError(String activityId, List<Activity_works_worksType> deletedWorksTypes) {
|
||||
if (CollUtil.isEmpty(deletedWorksTypes)) {
|
||||
return null;
|
||||
}
|
||||
List<String> deletedWorksIds = deletedWorksTypes.stream()
|
||||
.map(Activity_works_worksType::getId)
|
||||
.collect(Collectors.toList());
|
||||
List<Activity_works_collection_upload> uploads = dao.query(Activity_works_collection_upload.class,
|
||||
Cnd.where(Activity_works_collection_upload::getActivityId, "=", activityId)
|
||||
.and(Activity_works_collection_upload::getWorksId, "in", deletedWorksIds));
|
||||
if (CollUtil.isEmpty(uploads)) {
|
||||
return null;
|
||||
}
|
||||
Set<String> referencedWorksIds = uploads.stream()
|
||||
.map(Activity_works_collection_upload::getWorksId)
|
||||
.collect(Collectors.toSet());
|
||||
String typeNames = deletedWorksTypes.stream()
|
||||
.filter(worksType -> referencedWorksIds.contains(worksType.getId()))
|
||||
.map(Activity_works_worksType::getWorksTypeName)
|
||||
.collect(Collectors.joining("、"));
|
||||
return "作品类型“" + typeNames + "”下已有投稿,不能删除";
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -200,6 +200,7 @@ public class ClubInfoManageController {
|
||||
@SLog(tag = "社团管理系统-信息管理", msg = "修改身份")
|
||||
public Result updateRoleCode(@Param("id") String id, @Valid String[] roleCodes, @Valid String clubId) {
|
||||
List<String> roleCodeList = Arrays.asList(roleCodes);
|
||||
ClubUser clubUser = clubInfoManageService.dao().fetch(ClubUser.class, id);
|
||||
//查询社团是否存在会长或者秘书长
|
||||
if(Arrays.asList(roleCodes).contains(RoleConstant.CLUB_PRESIDENT.name())) {
|
||||
int count = dao.count(ClubUser.class, Cnd.where("clubId", "=", clubId)
|
||||
@@ -210,14 +211,14 @@ public class ClubInfoManageController {
|
||||
}
|
||||
if(Arrays.asList(roleCodes).contains(RoleConstant.CLUB_SECRETARY.name())) {
|
||||
int count = dao.count(ClubUser.class, Cnd.where("clubId", "=", clubId)
|
||||
.and("id", "!=", id)
|
||||
.and(new Static("JSON_CONTAINS(roleCode, '\"%s\"')".formatted(RoleConstant.CLUB_SECRETARY.name()))));
|
||||
if (count > 0) {
|
||||
// return Result.error("秘书长只能有一位");
|
||||
return Result.error("秘书长只能有一位");
|
||||
}
|
||||
}
|
||||
|
||||
ClubUser clubUser = clubInfoManageService.dao().fetch(ClubUser.class, id);
|
||||
|
||||
// 先清除所有的角色
|
||||
dao.clear(Sys_user_role.class, Cnd.where("userId", "=", clubUser.getUserId()).and("clubId", "=", clubUser.getClubId()));
|
||||
// 再根据传过来的赋值
|
||||
|
||||
@@ -291,7 +291,7 @@ public class SysClubExamineServiceImpl extends BaseServiceImpl<SysClubExamineReg
|
||||
|
||||
@Override
|
||||
public List<NutMap> getJgUser(String clubId) {
|
||||
// 构建社团管理人员查询SQL(排除普通成员,按职务排序)
|
||||
// 构建社团成员查询SQL,理事机构成员优先展示,普通成员随后展示。
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
cl.*,
|
||||
@@ -304,7 +304,6 @@ public class SysClubExamineServiceImpl extends BaseServiceImpl<SysClubExamineReg
|
||||
LEFT JOIN `vw_user` u ON cl.userId = u.id
|
||||
WHERE
|
||||
cl.clubId = @clubId
|
||||
AND NOT JSON_CONTAINS(cl.roleCode, '"CLUB_MEMBER"')
|
||||
ORDER BY
|
||||
CASE
|
||||
WHEN JSON_CONTAINS(cl.roleCode, '"CLUB_PRESIDENT"') THEN 1
|
||||
@@ -480,6 +479,35 @@ public class SysClubExamineServiceImpl extends BaseServiceImpl<SysClubExamineReg
|
||||
List<SysClubExamineRegisterDetailed> detailedList = dao().query(SysClubExamineRegisterDetailed.class,
|
||||
Cnd.where("registerId", "=", id).asc("location"));
|
||||
clubExamineVo.setDetailedList(detailedList);
|
||||
// V3年审审核记录已迁入audit表,作为V4工作流历史为空时的详情回显数据。
|
||||
Sql legacyAuditSql = Sqls.create("""
|
||||
SELECT
|
||||
a.id,
|
||||
a.username AS userName,
|
||||
a.loginname AS loginName,
|
||||
a.auditTime,
|
||||
a.auditPass,
|
||||
a.auditOpinion,
|
||||
a.auditSign,
|
||||
CASE
|
||||
WHEN a.id = scer.clubAuditId THEN '社团审核'
|
||||
WHEN a.id = scer.clubLeaderAuditId THEN '会长审核'
|
||||
WHEN a.id = scer.schoolAuditId THEN '校工会审核'
|
||||
END AS auditName
|
||||
FROM
|
||||
sys_club_examine_register scer
|
||||
INNER JOIN audit a ON a.id IN (scer.clubAuditId, scer.clubLeaderAuditId, scer.schoolAuditId)
|
||||
WHERE
|
||||
scer.id = @id
|
||||
ORDER BY
|
||||
CASE
|
||||
WHEN a.id = scer.clubAuditId THEN 1
|
||||
WHEN a.id = scer.clubLeaderAuditId THEN 2
|
||||
WHEN a.id = scer.schoolAuditId THEN 3
|
||||
ELSE 99
|
||||
END
|
||||
""").setParam("id", id);
|
||||
clubExamineVo.setLegacyAuditRecords(listMap(legacyAuditSql));
|
||||
}
|
||||
return clubExamineVo;
|
||||
}
|
||||
|
||||
+110
-77
@@ -86,7 +86,7 @@ public class SysClubInfoManageServiceImpl extends BaseServiceImpl<ClubCommonPage
|
||||
scu.clubId = c.id
|
||||
) currentNum,
|
||||
GROUP_CONCAT(DISTINCT presidentUser.username) AS clubLeader,
|
||||
GROUP_CONCAT(secretaryUser.username) AS clubSecretary
|
||||
GROUP_CONCAT(DISTINCT secretaryUser.username) AS clubSecretary
|
||||
FROM
|
||||
sys_club c
|
||||
LEFT JOIN club_user presidentCu on presidentCu.clubId = c.id AND JSON_CONTAINS(presidentCu.roleCode, '"CLUB_PRESIDENT"')
|
||||
@@ -229,23 +229,19 @@ public class SysClubInfoManageServiceImpl extends BaseServiceImpl<ClubCommonPage
|
||||
public Pagination<ClubUserCommonPageVo> exitManagePageData(ClubUserPageForm pageForm) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
COALESCE(info.id, scu.id) AS id,
|
||||
scu.clubId,
|
||||
scu.userId,
|
||||
COALESCE(info.roleCode, scu.roleCode) AS applyRoleCode,
|
||||
COALESCE(info.clubPosition, scu.position) AS clubPosition,
|
||||
COALESCE(info.email, scu.email, u.email) AS email,
|
||||
COALESCE(info.mobile, u.mobile) AS mobile,
|
||||
COALESCE(info.birthday, u.birthday) AS birthday,
|
||||
COALESCE(info.avatar, scu.avatar, u.avatar) AS avatar,
|
||||
COALESCE(info.sameTimeJoinOtherClubSituation, scu.sameTimeJoinOtherClubSituation) AS sameTimeJoinOtherClubSituation,
|
||||
COALESCE(info.awardsExperience, scu.awardsExperience) AS awardsExperience,
|
||||
info.signature,
|
||||
COALESCE(
|
||||
info.applyDate,
|
||||
STR_TO_DATE(scu.changeTime, '%Y-%m-%d %H:%i:%s'),
|
||||
STR_TO_DATE(JSON_UNQUOTE(JSON_EXTRACT(scu.exitAuditList, '$[0].auditTime')), '%Y-%m-%d %H:%i:%s')
|
||||
) AS applyDate,
|
||||
exitInfo.id,
|
||||
exitInfo.clubId,
|
||||
exitInfo.userId,
|
||||
exitInfo.applyRoleCode,
|
||||
exitInfo.clubPosition,
|
||||
COALESCE(exitInfo.email, u.email) AS email,
|
||||
COALESCE(exitInfo.mobile, u.mobile) AS mobile,
|
||||
COALESCE(exitInfo.birthday, u.birthday) AS birthday,
|
||||
COALESCE(exitInfo.avatar, u.avatar) AS avatar,
|
||||
exitInfo.sameTimeJoinOtherClubSituation,
|
||||
exitInfo.awardsExperience,
|
||||
exitInfo.signature,
|
||||
exitInfo.applyDate,
|
||||
u.username AS userName,
|
||||
u.loginname AS loginName,
|
||||
u.sex,
|
||||
@@ -253,32 +249,14 @@ public class SysClubInfoManageServiceImpl extends BaseServiceImpl<ClubCommonPage
|
||||
u.userState,
|
||||
club.clubName,
|
||||
u.unitname AS unitName,
|
||||
COALESCE(scu.joinTime, DATE_FORMAT(club.foundTime, '%Y-%m-%d %H:%i:%s')) AS joinTime,
|
||||
COALESCE(
|
||||
DATE_FORMAT(info.exitTime, '%Y-%m-%d %H:%i:%s'),
|
||||
JSON_UNQUOTE(JSON_EXTRACT(scu.exitAuditList, '$[0].auditTime')),
|
||||
scu.changeTime
|
||||
) AS exitTime,
|
||||
IF(info.id IS NULL, 'DIRECT_REMOVE', 'AUDIT_EXIT') AS exitType,
|
||||
ins.id AS instanceId,
|
||||
ins.businessNo,
|
||||
ins.state instanceState,
|
||||
ins.variable instanceVariable,
|
||||
ins.processDefineId instanceProcessDefineId
|
||||
FROM
|
||||
sys_club_user scu
|
||||
LEFT JOIN club_user_apply info ON info.clubId = scu.clubId
|
||||
AND info.userId = scu.userId
|
||||
AND info.mode = false
|
||||
LEFT JOIN sys_club club ON club.id = scu.clubId
|
||||
INNER JOIN vw_user u ON u.id = scu.userId
|
||||
LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id
|
||||
AND ins.state = 20
|
||||
DATE_FORMAT(COALESCE(exitInfo.joinTime, STR_TO_DATE(club.foundTime, '%Y-%m-%d')), '%Y-%m-%d %H:%i:%s') AS joinTime,
|
||||
DATE_FORMAT(exitInfo.exitTime, '%Y-%m-%d %H:%i:%s') AS exitTime,
|
||||
exitInfo.exitType
|
||||
""" + getExitManageBaseSql() + """
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("scu.isNormal", "=", false);
|
||||
cnd.andEX("scu.clubId", "=", pageForm.getClubId());
|
||||
cnd.andEX("exitInfo.clubId", "=", pageForm.getClubId());
|
||||
cnd.andEX("u.personType", "=", pageForm.getPersonType());
|
||||
cnd.andEX("u.userState", "=", pageForm.getUserState());
|
||||
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
||||
@@ -287,9 +265,9 @@ public class SysClubInfoManageServiceImpl extends BaseServiceImpl<ClubCommonPage
|
||||
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name(), RoleConstant.SCHOOL_UNION_CLUB_ADMIN.name())) {
|
||||
List<String> clubIdList = commonService.findUserRoleByRoleCode(List.of(RoleConstant.CLUB_PRESIDENT.name(), RoleConstant.CLUB_VICE_PRESIDENT.name(), RoleConstant.CLUB_SECRETARY.name(), RoleConstant.CLUB_VICE_SECRETARY.name(), RoleConstant.CLUB_OPERATOR.name()));
|
||||
List<Sys_user_role> clubList = dao().query(Sys_user_role.class, Cnd.where("roleId", "in", clubIdList).and("userId", "=", SecurityUtil.getUserId()).and("clubId", "is not", null));
|
||||
cnd.and("scu.clubId", "in", clubList.stream().map(Sys_user_role::getClubId).toList());
|
||||
cnd.and("exitInfo.clubId", "in", clubList.stream().map(Sys_user_role::getClubId).toList());
|
||||
}
|
||||
cnd.groupBy("scu.id");
|
||||
cnd.groupBy("exitInfo.id");
|
||||
cnd.desc("exitTime");
|
||||
sql.setCondition(cnd);
|
||||
Pagination<ClubUserCommonPageVo> pagination = listPageVO(pageForm, sql, ClubUserCommonPageVo.class);
|
||||
@@ -307,55 +285,110 @@ public class SysClubInfoManageServiceImpl extends BaseServiceImpl<ClubCommonPage
|
||||
public ClubUserJoinVo exitManageInfo(String id) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
COALESCE(cua.id, scu.id) AS id,
|
||||
scu.clubId,
|
||||
scu.userId,
|
||||
COALESCE(cua.roleCode, scu.roleCode) AS roleCode,
|
||||
COALESCE(cua.clubPosition, scu.position) AS clubPosition,
|
||||
COALESCE(cua.email, scu.email, u.email) AS email,
|
||||
COALESCE(cua.mobile, u.mobile) AS mobile,
|
||||
COALESCE(cua.birthday, u.birthday) AS birthday,
|
||||
COALESCE(cua.avatar, scu.avatar, u.avatar) AS avatar,
|
||||
COALESCE(cua.sameTimeJoinOtherClubSituation, scu.sameTimeJoinOtherClubSituation) AS sameTimeJoinOtherClubSituation,
|
||||
COALESCE(cua.awardsExperience, scu.awardsExperience) AS awardsExperience,
|
||||
cua.signature,
|
||||
COALESCE(
|
||||
cua.applyDate,
|
||||
STR_TO_DATE(scu.changeTime, '%Y-%m-%d %H:%i:%s'),
|
||||
STR_TO_DATE(JSON_UNQUOTE(JSON_EXTRACT(scu.exitAuditList, '$[0].auditTime')), '%Y-%m-%d %H:%i:%s')
|
||||
) AS applyDate,
|
||||
STR_TO_DATE(scu.joinTime, '%Y-%m-%d %H:%i:%s') AS joinTime,
|
||||
COALESCE(
|
||||
cua.exitTime,
|
||||
STR_TO_DATE(JSON_UNQUOTE(JSON_EXTRACT(scu.exitAuditList, '$[0].auditTime')), '%Y-%m-%d %H:%i:%s'),
|
||||
STR_TO_DATE(scu.changeTime, '%Y-%m-%d %H:%i:%s')
|
||||
) AS exitTime,
|
||||
IF(cua.id IS NULL, 'DIRECT_REMOVE', 'AUDIT_EXIT') AS exitType,
|
||||
exitInfo.id,
|
||||
exitInfo.clubId,
|
||||
exitInfo.userId,
|
||||
exitInfo.applyRoleCode AS roleCode,
|
||||
exitInfo.clubPosition,
|
||||
COALESCE(exitInfo.email, u.email) AS email,
|
||||
COALESCE(exitInfo.mobile, u.mobile) AS mobile,
|
||||
COALESCE(exitInfo.birthday, u.birthday) AS birthday,
|
||||
COALESCE(exitInfo.avatar, u.avatar) AS avatar,
|
||||
exitInfo.sameTimeJoinOtherClubSituation,
|
||||
exitInfo.awardsExperience,
|
||||
exitInfo.signature,
|
||||
exitInfo.applyDate,
|
||||
COALESCE(exitInfo.joinTime, STR_TO_DATE(club.foundTime, '%Y-%m-%d')) AS joinTime,
|
||||
exitInfo.exitTime,
|
||||
exitInfo.exitType,
|
||||
club.clubName,
|
||||
u.loginname AS loginName,
|
||||
u.username AS userName,
|
||||
u.sex,
|
||||
u.mobile,
|
||||
u.unitName,
|
||||
u.unionName,
|
||||
u.technicalTitle,
|
||||
u.education,
|
||||
u.academicDegree,
|
||||
u.position
|
||||
FROM
|
||||
sys_club_user scu
|
||||
LEFT JOIN club_user_apply cua ON cua.clubId = scu.clubId
|
||||
AND cua.userId = scu.userId
|
||||
AND cua.mode = false
|
||||
LEFT JOIN vw_user u ON u.id = scu.userId
|
||||
LEFT JOIN sys_club club ON club.id = scu.clubId
|
||||
WHERE scu.isNormal = false
|
||||
AND COALESCE(cua.id, scu.id) = @id
|
||||
""" + getExitManageBaseSql() + """
|
||||
WHERE exitInfo.id = @id
|
||||
""");
|
||||
sql.setParam("id", id);
|
||||
return fetchVO(sql, ClubUserJoinVo.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 退会申请审批完成后会删除club_user成员关系,因此退会管理以退会申请记录为主数据源。
|
||||
* 同时保留旧sys_club_user表中已退会的数据,避免历史直接移出记录无法查询。
|
||||
*
|
||||
* @return 退会管理列表和详情共用的数据来源SQL
|
||||
*/
|
||||
private String getExitManageBaseSql() {
|
||||
return """
|
||||
FROM (
|
||||
SELECT
|
||||
cua.id,
|
||||
cua.clubId,
|
||||
cua.userId,
|
||||
cua.roleCode AS applyRoleCode,
|
||||
cua.clubPosition,
|
||||
cua.email,
|
||||
cua.mobile,
|
||||
cua.birthday,
|
||||
cua.avatar,
|
||||
cua.sameTimeJoinOtherClubSituation,
|
||||
cua.awardsExperience,
|
||||
cua.signature,
|
||||
cua.applyDate,
|
||||
cua.joinTime,
|
||||
cua.exitTime,
|
||||
'AUDIT_EXIT' AS exitType
|
||||
FROM
|
||||
club_user_apply cua
|
||||
INNER JOIN wf_process_instance ins ON ins.businessNo = cua.id AND ins.state = 20
|
||||
WHERE cua.mode = false
|
||||
UNION ALL
|
||||
SELECT
|
||||
scu.id,
|
||||
scu.clubId,
|
||||
scu.userId,
|
||||
scu.roleCode AS applyRoleCode,
|
||||
scu.position AS clubPosition,
|
||||
scu.email,
|
||||
NULL AS mobile,
|
||||
NULL AS birthday,
|
||||
scu.avatar,
|
||||
scu.sameTimeJoinOtherClubSituation,
|
||||
scu.awardsExperience,
|
||||
NULL AS signature,
|
||||
COALESCE(
|
||||
STR_TO_DATE(scu.changeTime, '%Y-%m-%d %H:%i:%s'),
|
||||
STR_TO_DATE(JSON_UNQUOTE(JSON_EXTRACT(scu.exitAuditList, '$[0].auditTime')), '%Y-%m-%d %H:%i:%s')
|
||||
) AS applyDate,
|
||||
STR_TO_DATE(scu.joinTime, '%Y-%m-%d %H:%i:%s') AS joinTime,
|
||||
COALESCE(
|
||||
STR_TO_DATE(JSON_UNQUOTE(JSON_EXTRACT(scu.exitAuditList, '$[0].auditTime')), '%Y-%m-%d %H:%i:%s'),
|
||||
STR_TO_DATE(scu.changeTime, '%Y-%m-%d %H:%i:%s')
|
||||
) AS exitTime,
|
||||
'DIRECT_REMOVE' AS exitType
|
||||
FROM
|
||||
sys_club_user scu
|
||||
WHERE scu.isNormal = false
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM club_user_apply cua
|
||||
INNER JOIN wf_process_instance ins ON ins.businessNo = cua.id AND ins.state = 20
|
||||
WHERE cua.mode = false
|
||||
AND cua.clubId = scu.clubId
|
||||
AND cua.userId = scu.userId
|
||||
)
|
||||
) exitInfo
|
||||
LEFT JOIN sys_club club ON club.id = exitInfo.clubId
|
||||
INNER JOIN vw_user u ON u.id = exitInfo.userId
|
||||
""";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pagination<ClubUserCommonPageVo> clubManagePersonAuditPageData(ClubUserPageForm pageForm) {
|
||||
Sql sql = Sqls.create("""
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.budwk.app.zhgh.club.model.SysClubExamineRegisterDetailed;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -18,4 +19,9 @@ public class ClubExamineVo extends SysClubExamineRegister {
|
||||
private String typeName;
|
||||
@ApiModelProperty("节点审批记录")
|
||||
private List<BpmTaskApprovalRecordVo> nodeTasks;
|
||||
|
||||
/**
|
||||
* V3年审已迁入但未转换为V4工作流任务的历史审核记录。
|
||||
*/
|
||||
private List<NutMap> legacyAuditRecords;
|
||||
}
|
||||
|
||||
+2
@@ -84,6 +84,8 @@ public class EnrollmentRegistrationApplyListController {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.andEX("YEAR(info.applyTime)", "=", year);
|
||||
cnd.and("info.userId", "=", SecurityUtil.getUserId());
|
||||
// 同一登记可能关联多个流程任务参与人,按业务主表ID分组后仅展示一条申请记录。
|
||||
cnd.groupBy("info.id");
|
||||
sql.setCondition(cnd);
|
||||
Pagination pagination = baseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
return Result.success(pagination);
|
||||
|
||||
+1
@@ -74,6 +74,7 @@ public class EvaluateActivityController {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.andEX("year", "=", year);
|
||||
cnd.and(Cnd.likeEX("eva.name", searchKeyword));
|
||||
cnd.groupBy("eva.id");
|
||||
sql.setCondition(cnd);
|
||||
return Result.success(baseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql));
|
||||
}
|
||||
|
||||
+13
@@ -83,6 +83,7 @@ public class EvaluateApplyController {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("enable", "=", 1);
|
||||
cnd.andEX("year", "=", year);
|
||||
cnd.groupBy("eva.id");
|
||||
sql.setCondition(cnd);
|
||||
Pagination pagination = evaluateActivityService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
return Result.success(pagination);
|
||||
@@ -108,6 +109,10 @@ public class EvaluateApplyController {
|
||||
@ApiOperation("保存")
|
||||
@SLog(tag = "评优评先申请", msg = "保存申请")
|
||||
public Result save(@Param("data") EvaluateApply evaluateApply) {
|
||||
String validateMessage = evaluateService.validateCollectiveHonorApply(evaluateApply);
|
||||
if (validateMessage != null) {
|
||||
return Result.error(validateMessage);
|
||||
}
|
||||
evaluateApply.setApplyDateTime(new Date());
|
||||
evaluateService.insertOrUpdate(evaluateApply);
|
||||
return Result.success();
|
||||
@@ -119,6 +124,10 @@ public class EvaluateApplyController {
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SLog( tag = "评优评先申请", msg = "重新提交申请")
|
||||
public Result submitAgain(@Param("data") EvaluateApply evaluateApply, @Param("taskId") Long taskId) {
|
||||
String validateMessage = evaluateService.validateCollectiveHonorApply(evaluateApply);
|
||||
if (validateMessage != null) {
|
||||
return Result.error(validateMessage);
|
||||
}
|
||||
evaluateService.insertOrUpdate(evaluateApply);
|
||||
|
||||
Dict dict = Dict.create();
|
||||
@@ -134,6 +143,10 @@ public class EvaluateApplyController {
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SLog(tag = "评优评先申请", msg = "提交申请")
|
||||
public Result submit(@Param("data") EvaluateApply evaluateApply) {
|
||||
String validateMessage = evaluateService.validateCollectiveHonorApply(evaluateApply);
|
||||
if (validateMessage != null) {
|
||||
return Result.error(validateMessage);
|
||||
}
|
||||
evaluateApply.setApplyDateTime(new Date());
|
||||
evaluateService.insertOrUpdate(evaluateApply);
|
||||
|
||||
|
||||
+1
@@ -80,6 +80,7 @@ public class EvaluateMineController {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.andEX("YEAR(info.year)", "=", year);
|
||||
cnd.and("info.loginName", "=", SecurityUtil.getUserLoginname());
|
||||
cnd.groupBy("info.id");
|
||||
cnd.desc("info.createdAt");
|
||||
sql.setCondition(cnd);
|
||||
Pagination pagination = evaluateService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
|
||||
@@ -10,4 +10,12 @@ public interface EvaluateService extends BaseService<EvaluateApply> {
|
||||
|
||||
|
||||
Sql getSummarySql(EvaluatePageForm pageForm);
|
||||
|
||||
/**
|
||||
* 校验集体荣誉是否已由当前分工会申请。
|
||||
*
|
||||
* @param evaluateApply 待保存或提交的申请
|
||||
* @return 校验通过返回 {@code null};重复申请时返回提示信息
|
||||
*/
|
||||
String validateCollectiveHonorApply(EvaluateApply evaluateApply);
|
||||
}
|
||||
|
||||
+30
@@ -4,9 +4,12 @@ import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.base.utils.PageUtil;
|
||||
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.dayofficework.evaluation.models.EvaluateActivity;
|
||||
import com.budwk.app.zhgh.dayofficework.evaluation.models.EvaluateApply;
|
||||
import com.budwk.app.zhgh.dayofficework.evaluation.service.EvaluateService;
|
||||
import com.budwk.app.zhgh.dayofficework.evaluation.vo.EvaluatePageForm;
|
||||
import com.budwk.app.zhgh.dayofficework.honor.models.HonorBasicSettings;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.Sqls;
|
||||
@@ -67,6 +70,7 @@ public class EvaluateServiceImpl extends BaseServiceImpl<EvaluateApply> implemen
|
||||
seg.orLike("info.loginName", pageForm.getSearchKeyword());
|
||||
cnd.and(seg);
|
||||
}
|
||||
cnd.groupBy("info.id");
|
||||
if (StrUtil.isAllBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) {
|
||||
cnd.desc("t.createdAt").desc("info.applyDateTime");
|
||||
} else {
|
||||
@@ -76,4 +80,30 @@ public class EvaluateServiceImpl extends BaseServiceImpl<EvaluateApply> implemen
|
||||
sql.setCondition(cnd);
|
||||
return sql;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String validateCollectiveHonorApply(EvaluateApply evaluateApply) {
|
||||
if (evaluateApply == null || StrUtil.isBlank(evaluateApply.getEvaluateId())) {
|
||||
return "评优评先活动不能为空";
|
||||
}
|
||||
EvaluateActivity activity = dao().fetch(EvaluateActivity.class, evaluateApply.getEvaluateId());
|
||||
if (activity == null) {
|
||||
return "评优评先活动不存在";
|
||||
}
|
||||
HonorBasicSettings honorType = dao().fetch(HonorBasicSettings.class, activity.getHonorTypeId());
|
||||
if (honorType == null || !StrUtil.equals("集体荣誉", honorType.getName())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Cnd cnd = Cnd.where(EvaluateApply::getUnionId, "=", SecurityUtil.getUnionId())
|
||||
.and(EvaluateApply::getHonorId, "=", activity.getHonorId())
|
||||
.and("YEAR(applyDateTime)", "=", activity.getYear());
|
||||
if (StrUtil.isNotBlank(evaluateApply.getId())) {
|
||||
cnd.and(EvaluateApply::getId, "!=", evaluateApply.getId());
|
||||
}
|
||||
if (dao().count(EvaluateApply.class, cnd) > 0) {
|
||||
return "本分工会已申请该集体荣誉,同一类型只能申请一次";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+21
-1
@@ -420,12 +420,32 @@ public class TourSignupController {
|
||||
a.agencyName AS travelAgencyName,
|
||||
IFNULL(lot.allowOverReimbursement, 0) AS allowOverReimbursement,
|
||||
s.allowFamily,
|
||||
IFNULL(s.fillBedInfo, 1) AS fillBedInfo
|
||||
IFNULL(s.fillBedInfo, 1) AS fillBedInfo,
|
||||
IFNULL(sc.signupCount, 0) AS signupCount,
|
||||
IFNULL(sc.familyCount, 0) AS familyCount
|
||||
FROM tour_matter m
|
||||
INNER JOIN tour_line l ON l.id = m.lineId
|
||||
LEFT JOIN tour_travel_agency a ON a.id = l.travelAgencyId
|
||||
LEFT JOIN tour_setting_lot lot ON lot.id = l.lotId
|
||||
LEFT JOIN tour_setting s ON s.id = m.settingId
|
||||
LEFT JOIN (
|
||||
/* 与PC报名列表保持一致:已报人数包含教职工本人和有效家属。 */
|
||||
SELECT
|
||||
t.matterId,
|
||||
COUNT(1) + SUM(IFNULL(f.familyCount, 0)) AS signupCount,
|
||||
SUM(IFNULL(f.familyCount, 0)) AS familyCount
|
||||
FROM tour_ledger t
|
||||
LEFT JOIN (
|
||||
SELECT ledgerId, COUNT(1) AS familyCount
|
||||
FROM tour_ledger_family
|
||||
WHERE delFlag = 0
|
||||
GROUP BY ledgerId
|
||||
) f ON f.ledgerId = t.id
|
||||
WHERE t.delFlag = 0
|
||||
AND t.matterId IS NOT NULL
|
||||
AND t.matterId <> ''
|
||||
GROUP BY t.matterId
|
||||
) sc ON sc.matterId = m.id
|
||||
WHERE m.delFlag = 0
|
||||
AND m.enabled = 1
|
||||
AND m.id = @matterId
|
||||
|
||||
+4
-18
@@ -128,27 +128,13 @@ public class ProposalDashboardController {
|
||||
nodes.addAll(taskNodes);
|
||||
nodes.addAll(feedbackNodes);
|
||||
|
||||
// 查询待办任务
|
||||
Sql todoSql = Sqls.create("""
|
||||
SELECT
|
||||
t.taskName,
|
||||
t.taskState
|
||||
FROM
|
||||
wf_process_task t
|
||||
INNER JOIN wf_process_instance ins ON ins.id = t.processInstanceId
|
||||
INNER JOIN proposal_info info ON info.id = ins.businessNo
|
||||
WHERE
|
||||
info.sessionId = @sessionId
|
||||
""");
|
||||
todoSql.setParam("sessionId", sessionId);
|
||||
List<NutMap> todoTasks = processDefineService.listMap(todoSql);
|
||||
Map<String, NutMap> taskProposalCounts = proposalCommonService.countDashboardTaskProposals(sessionId);
|
||||
|
||||
for (NutMap node : nodes) {
|
||||
if (node.getString("type").equals("task")) {
|
||||
long todoCount = todoTasks.stream().filter(task -> task.getInt("taskState") == ProcessTaskStateEnum.DOING.getCode() && task.getString("taskName").equals(node.getString("id"))).count();
|
||||
node.put("todoCount", todoCount);
|
||||
long doneCount = todoTasks.stream().filter(task -> task.getInt("taskState") == ProcessTaskStateEnum.FINISHED.getCode() && task.getString("taskName").equals(node.getString("id"))).count();
|
||||
node.put("doneCount", doneCount);
|
||||
NutMap taskCount = taskProposalCounts.get(node.getString("id"));
|
||||
node.put("todoCount", taskCount == null ? 0 : taskCount.getLong("todoCount", 0L));
|
||||
node.put("doneCount", taskCount == null ? 0 : taskCount.getLong("doneCount", 0L));
|
||||
} else if (node.getString("type").equals("total")) {
|
||||
int count = dao.count(ProposalInfo.class, Cnd.where(ProposalInfo::getSessionId, "=", sessionId));
|
||||
node.put("count", count);
|
||||
|
||||
+1
-88
@@ -1,22 +1,13 @@
|
||||
package com.budwk.app.zhgh.democratic.proposal.controller.query;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.flow.entity.ProcessTask;
|
||||
import com.budwk.app.flow.enums.ProcessInstanceStateEnum;
|
||||
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
|
||||
import com.budwk.app.zhgh.democratic.proposal.param.ProposalQueryComprehensiveParam;
|
||||
import com.budwk.app.zhgh.democratic.proposal.service.common.ProposalCommonService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
@@ -27,7 +18,6 @@ import org.nutz.mvc.annotation.Param;
|
||||
import javax.validation.Valid;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
@IocBean
|
||||
@@ -37,20 +27,6 @@ import java.util.Map;
|
||||
@Api(tags = "征集进度查询")
|
||||
public class ProposalQueryCollectProgressController {
|
||||
|
||||
/**
|
||||
* 征集进度表格允许排序的字段映射,值为查询中的真实字段或安全别名。
|
||||
*/
|
||||
private static final Map<String, String> COLLECT_PROGRESS_ORDER_COLUMNS = Map.ofEntries(
|
||||
Map.entry("code", "info.code"),
|
||||
Map.entry("name", "info.name"),
|
||||
Map.entry("createUserName", "info.createUserName"),
|
||||
Map.entry("delegationName", "delegationName"),
|
||||
Map.entry("inviteCount", "inviteCount"),
|
||||
Map.entry("finishCount", "finishCount"),
|
||||
Map.entry("curTaskName", "curTaskName"),
|
||||
Map.entry("instanceState", "instanceState")
|
||||
);
|
||||
|
||||
static List<NutMap> states = new ArrayList<>() {{
|
||||
add(NutMap.NEW().addv("code", 10).addv("id", 10).addv("name", "撰写提案"));
|
||||
add(NutMap.NEW().addv("code", 20).addv("id", 20).addv("name", "附议提案"));
|
||||
@@ -60,9 +36,6 @@ public class ProposalQueryCollectProgressController {
|
||||
|
||||
@Inject
|
||||
private ProposalCommonService proposalCommonService;
|
||||
@Inject
|
||||
private Dao dao;
|
||||
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/democratic/proposal/query/collectProgress/index.html")
|
||||
@@ -74,67 +47,7 @@ public class ProposalQueryCollectProgressController {
|
||||
@SaCheckPermission("proposal.query.collectProgress")
|
||||
@ApiOperation(value = "分页列表")
|
||||
public Result pageData(@Valid @Param("pageForm") ProposalQueryComprehensiveParam pageForm) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
info.id,
|
||||
info.name,
|
||||
info.code,
|
||||
info.createUserName,
|
||||
type.NAME AS typeName,
|
||||
tcs.fullName AS sessionName,
|
||||
tcd.`name` AS delegationName,
|
||||
(SELECT count(1) FROM proposal_second WHERE proposalId = info.id) AS inviteCount,
|
||||
(SELECT count(1) FROM wf_process_task WHERE processInstanceId = ins.id AND taskName = 'second' AND taskState = 20) finishCount,
|
||||
ins.id AS instanceId,
|
||||
ins.state instanceState,
|
||||
t.displayName curTaskName
|
||||
FROM
|
||||
proposal_info info
|
||||
LEFT JOIN proposal_type type ON type.id = info.typeId
|
||||
LEFT JOIN teacher_congress_session tcs ON tcs.id = info.sessionId
|
||||
LEFT JOIN teacher_congress_delegation tcd ON tcd.id = info.delegationId
|
||||
LEFT JOIN teacher_congress_delegate tcde on tcde.loginName = info.createUserLoginName
|
||||
LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id
|
||||
LEFT JOIN wf_process_task t ON t.processInstanceId = ins.id AND t.taskState = 10
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
// 征集进度必须按页面选中的教代会过滤,避免共享参数未处理sessionId导致跨届次查询。
|
||||
cnd.andEX("info.sessionId", "=", pageForm.getSessionId());
|
||||
ProposalQueryComprehensiveParam.buildSearch(cnd, pageForm);
|
||||
|
||||
SqlExpressionGroup seg = new SqlExpressionGroup();
|
||||
if (ArrayUtil.contains(pageForm.getCollectIds(), 10)) {
|
||||
seg.or("t.taskName", "=", "startTask");
|
||||
}
|
||||
if (ArrayUtil.contains(pageForm.getCollectIds(), 20)) {
|
||||
seg.or("t.taskName", "=", "second");
|
||||
}
|
||||
if (ArrayUtil.contains(pageForm.getCollectIds(), 30)) {
|
||||
seg.or("t.taskName", "=", "delegation");
|
||||
}
|
||||
if (ArrayUtil.contains(pageForm.getCollectIds(), 40)) {
|
||||
seg.or("t.taskName", "not in", List.of("startTask", "second", "delegation"));
|
||||
seg.and("t.taskName", "is not", null);
|
||||
seg.or("ins.state","=", ProcessInstanceStateEnum.FINISHED.getCode());
|
||||
}
|
||||
if (!seg.isEmpty()) {
|
||||
cnd.and(seg);
|
||||
}
|
||||
cnd.groupBy("info.id");
|
||||
// 征集进度包含关联字段和人数统计别名,只允许白名单字段进入排序条件。
|
||||
proposalCommonService.applySafePageOrder(cnd, pageForm, COLLECT_PROGRESS_ORDER_COLUMNS);
|
||||
sql.setCondition(cnd);
|
||||
Pagination pagination = proposalCommonService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
List<NutMap> list = (List<NutMap>) pagination.getList();
|
||||
// for (NutMap row : list) {
|
||||
// int count = dao.count(ProcessTask.class, Cnd.where(ProcessTask::getProcessInstanceId, "=", row.getString("instanceId"))
|
||||
// .and(ProcessTask::getTaskName, "=", "second")
|
||||
// .and(ProcessTask::getTaskState, "=", ProcessTaskStateEnum.FINISHED.getCode())
|
||||
// );
|
||||
//
|
||||
//
|
||||
// }
|
||||
Pagination pagination = proposalCommonService.queryCollectProgress(pageForm);
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
|
||||
+8
-6
@@ -77,6 +77,10 @@ public class ProposalQueryDelegationController {
|
||||
@ApiOperation("代表团提案统计")
|
||||
@SaCheckPermission("proposal.query.delegation")
|
||||
public Result pageData(PageForm pageForm, String sessionId) {
|
||||
// 统计必须明确限定届次,空参数不能退化为跨届次汇总,避免页面异步初始化时展示错误数据。
|
||||
if (StrUtil.isBlank(sessionId)) {
|
||||
return Result.success(List.of());
|
||||
}
|
||||
List<Sys_dict> dictList = sysDictService.getSubListByCode("PROPOSAL_CASE_FILING_RESULT");
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
@@ -90,19 +94,17 @@ public class ProposalQueryDelegationController {
|
||||
FROM
|
||||
teacher_congress_delegation dbt
|
||||
$condition
|
||||
""");
|
||||
""");
|
||||
Map<String, String> summaryOrderColumns = new HashMap<>(DELEGATION_SUMMARY_ORDER_COLUMNS);
|
||||
List<String> resultSqlParts = new ArrayList<>();
|
||||
int resultIndex = 0;
|
||||
for (Sys_dict dict : dictList) {
|
||||
String resultCode = dict.getCode();
|
||||
// 动态别名仅允许字母、数字和下划线,查询值使用参数绑定,避免字典内容进入SQL结构。
|
||||
// 动态别名和立案结果编码仅允许字母、数字和下划线;变量替换后新增的 @ 参数不会被 Nutz 再次解析,
|
||||
// 因此这里使用已校验的字典编码字面量,确保统计条件能正确传递给数据库。
|
||||
if (StrUtil.isBlank(resultCode) || !resultCode.matches("[A-Za-z0-9_]+")) {
|
||||
continue;
|
||||
}
|
||||
String paramName = "caseFilingResult" + resultIndex++;
|
||||
resultSqlParts.add(", (select count(1) from proposal_info info where info.delegationId = dbt.id and info.sessionId = dbt.sessionId and info.caseFilingResult = @" + paramName + ") AS `" + resultCode + "`");
|
||||
sql.setParam(paramName, resultCode);
|
||||
resultSqlParts.add(", (select count(1) from proposal_info info where info.delegationId = dbt.id and info.sessionId = dbt.sessionId and info.caseFilingResult = '" + resultCode + "') AS `" + resultCode + "`");
|
||||
summaryOrderColumns.put(resultCode, "`" + resultCode + "`");
|
||||
}
|
||||
sql.setVar("resultSql", String.join("", resultSqlParts));
|
||||
|
||||
+1
-1
@@ -97,7 +97,7 @@ public class ProposalSeniorBasicController {
|
||||
return Result.error("提案编号已存在");
|
||||
}
|
||||
|
||||
dao.update(proposalInfo,"^code|name|typeId|brief|measures|excerpt|suggestUnits|files$");
|
||||
dao.update(proposalInfo,"^code|caseFilingCode|name|typeId|brief|measures|excerpt|suggestUnits|files$");
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
|
||||
+27
-1
@@ -103,7 +103,7 @@ public class ProposalMineController {
|
||||
|
||||
@At("/h5")
|
||||
@Ok("beetl:/platform/zhghh5/democratic/proposal/transact/mine/index.html")
|
||||
@SaCheckPermission("proposal.mine")
|
||||
@SaCheckPermission("h5.proposal.mine")
|
||||
public void h5Index() {
|
||||
}
|
||||
|
||||
@@ -111,6 +111,18 @@ public class ProposalMineController {
|
||||
@SaCheckPermission("proposal.mine")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Result pageData(@Valid ProposalSearchParam pageForm, String sessionId) {
|
||||
return queryPageData(pageForm, sessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询当前登录人的提案分页数据。
|
||||
* PC 与 H5 入口共享同一数据范围和排序规则,避免两个端的列表结果不一致。
|
||||
*
|
||||
* @param pageForm 页面筛选及分页参数
|
||||
* @param sessionId 教代会届次ID
|
||||
* @return 当前登录人的提案分页结果
|
||||
*/
|
||||
private Result queryPageData(ProposalSearchParam pageForm, String sessionId) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
info.*,
|
||||
@@ -158,6 +170,20 @@ public class ProposalMineController {
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
/**
|
||||
* 我的提案 H5 分页列表。
|
||||
* H5 使用独立权限标识,但查询口径与 PC 端保持一致。
|
||||
*
|
||||
* @param pageForm 页面筛选及分页参数
|
||||
* @param sessionId 教代会届次ID
|
||||
* @return 当前登录人的提案分页结果
|
||||
*/
|
||||
@At("/h5/pageData")
|
||||
@SaCheckPermission("h5.proposal.mine")
|
||||
public Result h5PageData(@Valid ProposalSearchParam pageForm, String sessionId) {
|
||||
return queryPageData(pageForm, sessionId);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("proposal.mine")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
|
||||
+27
-1
@@ -84,13 +84,25 @@ public class ProposalSecondedController {
|
||||
|
||||
@At("/h5")
|
||||
@Ok("beetl:/platform/zhghh5/democratic/proposal/transact/seconded/index.html")
|
||||
@SaCheckPermission("proposal.seconded")
|
||||
@SaCheckPermission("h5.proposal.seconded")
|
||||
public void h5Index() {
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("proposal.seconded")
|
||||
public Result pageData(@Valid ProposalSearchParam pageForm, boolean approval) {
|
||||
return queryPageData(pageForm, approval);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询当前登录附议人的提案分页数据。
|
||||
* PC 与 H5 入口共享同一待附议、已附议筛选口径。
|
||||
*
|
||||
* @param pageForm 页面筛选及分页参数
|
||||
* @param approval 是否查询已附议记录
|
||||
* @return 附议提案分页结果
|
||||
*/
|
||||
private Result queryPageData(ProposalSearchParam pageForm, boolean approval) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
info.*,
|
||||
@@ -165,6 +177,20 @@ public class ProposalSecondedController {
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
/**
|
||||
* 提案附议 H5 分页列表。
|
||||
* H5 使用独立权限标识,但查询口径与 PC 端保持一致。
|
||||
*
|
||||
* @param pageForm 页面筛选及分页参数
|
||||
* @param approval 是否查询已附议记录
|
||||
* @return 附议提案分页结果
|
||||
*/
|
||||
@At("/h5/pageData")
|
||||
@SaCheckPermission("h5.proposal.seconded")
|
||||
public Result h5PageData(@Valid ProposalSearchParam pageForm, boolean approval) {
|
||||
return queryPageData(pageForm, approval);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("proposal.seconded")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
|
||||
+19
@@ -5,7 +5,9 @@ import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.param.ExportTableColumns;
|
||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalInfo;
|
||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalUndertake;
|
||||
import com.budwk.app.zhgh.democratic.proposal.param.ProposalQueryComprehensiveParam;
|
||||
import com.budwk.app.zhgh.democratic.proposal.param.ProposalSearchParam;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
|
||||
@@ -171,4 +173,21 @@ public interface ProposalCommonService extends BaseService<ProposalInfo> {
|
||||
* 修改提案状态码
|
||||
*/
|
||||
void updateStateCode(String id, Integer stateCode);
|
||||
|
||||
/**
|
||||
* 查询提案征集进度列表。
|
||||
* 查询结果与页面既有筛选、排序语义保持一致,内部使用聚合关联避免逐行执行统计子查询。
|
||||
*
|
||||
* @param pageForm 征集进度页面的筛选、排序和分页参数
|
||||
* @return 包含征集进度统计字段的分页结果
|
||||
*/
|
||||
Pagination queryCollectProgress(ProposalQueryComprehensiveParam pageForm);
|
||||
|
||||
/**
|
||||
* 按提案去重统计指定届次各流程节点的待办和已办数量。
|
||||
*
|
||||
* @param sessionId 教代会届次ID
|
||||
* @return 键为流程节点编码、值为待办和已办数量的统计结果
|
||||
*/
|
||||
Map<String, NutMap> countDashboardTaskProposals(String sessionId);
|
||||
}
|
||||
|
||||
+172
-29
@@ -3,6 +3,7 @@ package com.budwk.app.zhgh.democratic.proposal.service.common;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.lang.Dict;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
@@ -15,6 +16,7 @@ import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.exception.BaseException;
|
||||
import com.budwk.app.base.param.ExportTableColumns;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.base.utils.CommonDownloadUtil;
|
||||
import com.budwk.app.base.utils.PageUtil;
|
||||
@@ -56,6 +58,7 @@ import org.nutz.dao.FieldFilter;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.dao.util.Daos;
|
||||
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||
import org.nutz.dao.util.cri.Static;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
@@ -85,6 +88,18 @@ public class ProposalCommonServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
/** 办理页面允许导出的列表字段,避免请求参数携带非页面字段。 */
|
||||
private static final Map<String, Set<String>> WORKFLOW_EXPORT_COLUMNS = createWorkflowExportColumns();
|
||||
|
||||
/** 征集进度页面允许排序的字段,避免排序参数直接拼接到SQL。 */
|
||||
private static final Map<String, String> COLLECT_PROGRESS_ORDER_COLUMNS = Map.ofEntries(
|
||||
Map.entry("code", "info.code"),
|
||||
Map.entry("name", "info.name"),
|
||||
Map.entry("createUserName", "info.createUserName"),
|
||||
Map.entry("delegationName", "delegationName"),
|
||||
Map.entry("inviteCount", "inviteCount"),
|
||||
Map.entry("finishCount", "finishCount"),
|
||||
Map.entry("curTaskName", "curTaskName"),
|
||||
Map.entry("instanceState", "instanceState")
|
||||
);
|
||||
|
||||
//找出富文本里面上传的图片
|
||||
static String IMG_SRC_REGEX = "<img\\s+[^>]*src\\s*=\\s*([\"'])(/platform/sys/file/download\\?id=.*?)\\1[^>]*>";
|
||||
|
||||
@@ -107,6 +122,128 @@ public class ProposalCommonServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
super(dao);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询提案征集进度。
|
||||
* 附议人数和已附议人数使用分组结果关联,避免原查询对每一条提案重复执行统计子查询;
|
||||
* 总数查询只保留筛选所需关联,避免分页统计重复执行列表中的统计计算。
|
||||
*
|
||||
* @param pageForm 页面筛选、排序和分页参数
|
||||
* @return 征集进度分页数据
|
||||
*/
|
||||
@Override
|
||||
public Pagination queryCollectProgress(ProposalQueryComprehensiveParam pageForm) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
info.id,
|
||||
info.name,
|
||||
info.code,
|
||||
info.createUserName,
|
||||
type.NAME AS typeName,
|
||||
tcs.fullName AS sessionName,
|
||||
tcd.`name` AS delegationName,
|
||||
COALESCE(secondStat.inviteCount, 0) AS inviteCount,
|
||||
COALESCE(taskStat.finishCount, 0) AS finishCount,
|
||||
ins.id AS instanceId,
|
||||
ins.state AS instanceState,
|
||||
t.displayName AS curTaskName
|
||||
FROM proposal_info info
|
||||
LEFT JOIN proposal_type type ON type.id = info.typeId
|
||||
LEFT JOIN teacher_congress_session tcs ON tcs.id = info.sessionId
|
||||
LEFT JOIN teacher_congress_delegation tcd ON tcd.id = info.delegationId
|
||||
LEFT JOIN teacher_congress_delegate tcde ON tcde.loginName = info.createUserLoginName
|
||||
LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id
|
||||
LEFT JOIN wf_process_task t ON t.processInstanceId = ins.id AND t.taskState = 10
|
||||
LEFT JOIN (
|
||||
SELECT proposalId, COUNT(1) AS inviteCount
|
||||
FROM proposal_second
|
||||
GROUP BY proposalId
|
||||
) secondStat ON secondStat.proposalId = info.id
|
||||
LEFT JOIN (
|
||||
SELECT processInstanceId, COUNT(1) AS finishCount
|
||||
FROM wf_process_task
|
||||
WHERE taskName = 'second' AND taskState = 20
|
||||
GROUP BY processInstanceId
|
||||
) taskStat ON taskStat.processInstanceId = ins.id
|
||||
$condition
|
||||
""");
|
||||
Cnd dataCnd = buildCollectProgressCondition(pageForm);
|
||||
dataCnd.groupBy("info.id");
|
||||
applySafePageOrder(dataCnd, pageForm, COLLECT_PROGRESS_ORDER_COLUMNS);
|
||||
sql.setCondition(dataCnd);
|
||||
|
||||
Sql countSql = Sqls.create("""
|
||||
SELECT COUNT(DISTINCT info.id)
|
||||
FROM proposal_info info
|
||||
LEFT JOIN teacher_congress_delegate tcde ON tcde.loginName = info.createUserLoginName
|
||||
LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id
|
||||
LEFT JOIN wf_process_task t ON t.processInstanceId = ins.id AND t.taskState = 10
|
||||
$condition
|
||||
""");
|
||||
countSql.setCondition(buildCollectProgressCondition(pageForm));
|
||||
return listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql, countSql);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按提案ID去重统计数据看板的流程节点数量。
|
||||
* 同一提案因撤回、退回等再次经过同一节点时,任务表会保留多条已办记录;
|
||||
* 此处按提案统计,使看板数量与下方按提案展示的列表保持一致。
|
||||
*
|
||||
* @param sessionId 教代会届次ID
|
||||
* @return 以流程节点编码为键的待办、已办统计结果
|
||||
*/
|
||||
@Override
|
||||
public Map<String, NutMap> countDashboardTaskProposals(String sessionId) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
t.taskName,
|
||||
COUNT(DISTINCT CASE WHEN t.taskState = @doingState THEN info.id END) AS todoCount,
|
||||
COUNT(DISTINCT CASE WHEN t.taskState = @finishedState THEN info.id END) AS doneCount
|
||||
FROM wf_process_task t
|
||||
INNER JOIN wf_process_instance ins ON ins.id = t.processInstanceId
|
||||
INNER JOIN proposal_info info ON info.id = ins.businessNo
|
||||
WHERE info.sessionId = @sessionId
|
||||
GROUP BY t.taskName
|
||||
""");
|
||||
sql.setParam("sessionId", sessionId);
|
||||
sql.setParam("doingState", ProcessTaskStateEnum.DOING.getCode());
|
||||
sql.setParam("finishedState", ProcessTaskStateEnum.FINISHED.getCode());
|
||||
List<NutMap> taskCounts = listMap(sql);
|
||||
return taskCounts.stream().collect(Collectors.toMap(task -> task.getString("taskName"), task -> task));
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建征集进度列表和总数查询共用的筛选条件,确保两次查询返回同一数据范围。
|
||||
* 征集阶段条件保持页面原有的布尔组合方式,避免优化时改变既有查询结果。
|
||||
*
|
||||
* @param pageForm 页面筛选参数
|
||||
* @return 不含分组和排序的查询条件
|
||||
*/
|
||||
private Cnd buildCollectProgressCondition(ProposalQueryComprehensiveParam pageForm) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.andEX("info.sessionId", "=", pageForm.getSessionId());
|
||||
ProposalQueryComprehensiveParam.buildSearch(cnd, pageForm);
|
||||
|
||||
SqlExpressionGroup collectStageCondition = new SqlExpressionGroup();
|
||||
if (ArrayUtil.contains(pageForm.getCollectIds(), 10)) {
|
||||
collectStageCondition.or("t.taskName", "=", "startTask");
|
||||
}
|
||||
if (ArrayUtil.contains(pageForm.getCollectIds(), 20)) {
|
||||
collectStageCondition.or("t.taskName", "=", "second");
|
||||
}
|
||||
if (ArrayUtil.contains(pageForm.getCollectIds(), 30)) {
|
||||
collectStageCondition.or("t.taskName", "=", "delegation");
|
||||
}
|
||||
if (ArrayUtil.contains(pageForm.getCollectIds(), 40)) {
|
||||
collectStageCondition.or("t.taskName", "not in", List.of("startTask", "second", "delegation"));
|
||||
collectStageCondition.and("t.taskName", "is not", null);
|
||||
collectStageCondition.or("ins.state", "=", ProcessInstanceStateEnum.FINISHED.getCode());
|
||||
}
|
||||
if (!collectStageCondition.isEmpty()) {
|
||||
cnd.and(collectStageCondition);
|
||||
}
|
||||
return cnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用业务页面提供的字段白名单构建排序条件,非法字段或非法排序方向将被忽略。
|
||||
*
|
||||
@@ -121,8 +258,14 @@ public class ProposalCommonServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
return false;
|
||||
}
|
||||
|
||||
// H5 列表首次加载时可能不传排序字段;不可变 Map 不接受 null 键,直接保留页面默认排序。
|
||||
String pageOrderName = pageForm.getPageOrderName();
|
||||
if (StrUtil.isBlank(pageOrderName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 仅允许白名单中的字段参与排序,防止构造任意SQL排序字段。
|
||||
String orderColumn = allowedOrderColumns.get(pageForm.getPageOrderName());
|
||||
String orderColumn = allowedOrderColumns.get(pageOrderName);
|
||||
String orderBy = PageUtil.getOrder(pageForm.getPageOrderBy());
|
||||
if (StrUtil.isBlank(orderColumn) || StrUtil.isBlank(orderBy)) {
|
||||
return false;
|
||||
@@ -814,35 +957,35 @@ public class ProposalCommonServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
|
||||
// 获取流程实例
|
||||
ProcessInstance processInstance = dao().fetch(ProcessInstance.class, Cnd.where(ProcessInstance::getBusinessNo, "=", id));
|
||||
if (processInstance != null) {
|
||||
// 主办办理情况
|
||||
ProcessTask masterUnitReplyTask = dao().fetch(ProcessTask.class, Cnd.where(ProcessTask::getProcessInstanceId, "=", processInstance.getId())
|
||||
.and(ProcessTask::getTaskName, "in", List.of("master_reply", "opinion_master_reply"))
|
||||
.and(ProcessTask::getTaskState, "=", ProcessTaskStateEnum.FINISHED.getCode())
|
||||
.desc(ProcessTask::getFinishTime)
|
||||
);
|
||||
if (masterUnitReplyTask != null) {
|
||||
// 办理解决情况
|
||||
String implementState = FlowUtil.variableToDict(masterUnitReplyTask.getVariable()).getStr("tf_implementState");
|
||||
info.put(implementState, "√");
|
||||
// 承办单位名称
|
||||
info.put("underTakeName", FlowUtil.variableToDict(masterUnitReplyTask.getVariable()).getStr("underTakeName"));
|
||||
}
|
||||
|
||||
// 主办办理情况
|
||||
ProcessTask masterUnitReplyTask = dao().fetch(ProcessTask.class, Cnd.where(ProcessTask::getProcessInstanceId, "=", processInstance.getId())
|
||||
.and(ProcessTask::getTaskName, "in", List.of("master_reply", "opinion_master_reply"))
|
||||
.and(ProcessTask::getTaskState, "=", ProcessTaskStateEnum.FINISHED.getCode())
|
||||
.desc(ProcessTask::getFinishTime)
|
||||
);
|
||||
if (masterUnitReplyTask != null) {
|
||||
// 办理解决情况
|
||||
String implementState = FlowUtil.variableToDict(masterUnitReplyTask.getVariable()).getStr("tf_implementState");
|
||||
info.put(implementState, "√");
|
||||
// 承办单位名称
|
||||
info.put("underTakeName", FlowUtil.variableToDict(masterUnitReplyTask.getVariable()).getStr("underTakeName"));
|
||||
}
|
||||
|
||||
|
||||
// 反馈评价
|
||||
ProcessTask feedbackTask = dao().fetch(ProcessTask.class, Cnd.where(ProcessTask::getProcessInstanceId, "=", processInstance.getId())
|
||||
.and(ProcessTask::getTaskName, "=", "feedback")
|
||||
.and(ProcessTask::getTaskState, "=", ProcessTaskStateEnum.FINISHED.getCode())
|
||||
.desc(ProcessTask::getFinishTime)
|
||||
);
|
||||
if (feedbackTask != null) {
|
||||
info.put(FlowUtil.variableToDict(feedbackTask.getVariable()).getStr("tf_feedback"), "√");
|
||||
info.put("tf_feedback", FlowUtil.variableToDict(feedbackTask.getVariable()).getStr("tf_feedback"));
|
||||
info.put("tf_opinion", FlowUtil.variableToDict(feedbackTask.getVariable()).getStr("tf_opinion"));
|
||||
info.put("tf_phone", FlowUtil.variableToDict(feedbackTask.getVariable()).getStr("tf_phone"));
|
||||
info.put("tf_address", FlowUtil.variableToDict(feedbackTask.getVariable()).getStr("tf_address"));
|
||||
info.put("tf_postcode", FlowUtil.variableToDict(feedbackTask.getVariable()).getStr("tf_postcode"));
|
||||
// 反馈评价
|
||||
ProcessTask feedbackTask = dao().fetch(ProcessTask.class, Cnd.where(ProcessTask::getProcessInstanceId, "=", processInstance.getId())
|
||||
.and(ProcessTask::getTaskName, "=", "feedback")
|
||||
.and(ProcessTask::getTaskState, "=", ProcessTaskStateEnum.FINISHED.getCode())
|
||||
.desc(ProcessTask::getFinishTime)
|
||||
);
|
||||
if (feedbackTask != null) {
|
||||
info.put(FlowUtil.variableToDict(feedbackTask.getVariable()).getStr("tf_feedback"), "√");
|
||||
info.put("tf_feedback", FlowUtil.variableToDict(feedbackTask.getVariable()).getStr("tf_feedback"));
|
||||
info.put("tf_opinion", FlowUtil.variableToDict(feedbackTask.getVariable()).getStr("tf_opinion"));
|
||||
info.put("tf_phone", FlowUtil.variableToDict(feedbackTask.getVariable()).getStr("tf_phone"));
|
||||
info.put("tf_address", FlowUtil.variableToDict(feedbackTask.getVariable()).getStr("tf_address"));
|
||||
info.put("tf_postcode", FlowUtil.variableToDict(feedbackTask.getVariable()).getStr("tf_postcode"));
|
||||
}
|
||||
}
|
||||
|
||||
HtmlRenderPolicy htmlRenderPolicy = new HtmlRenderPolicy();
|
||||
|
||||
+12
-3
@@ -82,12 +82,12 @@ public class ProposalCommitteeFilingUnitServiceImpl extends BaseServiceImpl<Prop
|
||||
throw new BaseException("提案信息不存在");
|
||||
}
|
||||
args.put("proposalId", proposalId);
|
||||
validateAndNormalizeCaseFilingCode(args);
|
||||
|
||||
List<String> proposalIds = proposalCommonService.mergeProposal(proposalId);
|
||||
if (ObjectUtil.isEmpty(proposalIds)) {
|
||||
proposalIds = List.of(proposalId);
|
||||
}
|
||||
validateAndNormalizeCaseFilingCode(args, proposalIds);
|
||||
|
||||
/*
|
||||
* 先同步 proposal_info 和承办单位,再执行 WF 流转,使查看页面及下一节点读取到的都是本次最新数据。
|
||||
@@ -111,12 +111,14 @@ public class ProposalCommitteeFilingUnitServiceImpl extends BaseServiceImpl<Prop
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验并规范化立案编号。确定立案时必须传入不超过 20 个字符的编号;
|
||||
* 校验并规范化立案编号。确定立案时必须传入不超过 20 个字符且不与历史立案编号重复的编号;
|
||||
* 当前提案及并案提案不参与重复校验,保证流程回退后可按原编号重新提交。
|
||||
* 其他立案结果不保存编号,避免切换选项后把历史输入带入业务表和流程变量。
|
||||
*
|
||||
* @param args 流程提交参数,其中 tf_caseFilingResult 为立案结果,tf_caseFilingCode 为手工填写的立案编号
|
||||
* @param excludedProposalIds 当前办理的提案及并案提案主键,不参与历史重复判断
|
||||
*/
|
||||
private void validateAndNormalizeCaseFilingCode(Dict args) {
|
||||
private void validateAndNormalizeCaseFilingCode(Dict args, List<String> excludedProposalIds) {
|
||||
String caseFilingResultKey = FlowConst.TASK_FORM_DATA_PREFIX + "caseFilingResult";
|
||||
String caseFilingCodeKey = FlowConst.TASK_FORM_DATA_PREFIX + "caseFilingCode";
|
||||
String caseFilingTypeKey = FlowConst.TASK_FORM_DATA_PREFIX + "caseFilingType";
|
||||
@@ -133,6 +135,13 @@ public class ProposalCommitteeFilingUnitServiceImpl extends BaseServiceImpl<Prop
|
||||
if (caseFilingCode.length() > 20) {
|
||||
throw new BaseException("立案编号不能超过20个字符");
|
||||
}
|
||||
Cnd duplicateCondition = Cnd.where("caseFilingCode", "=", caseFilingCode);
|
||||
if (!ObjectUtil.isEmpty(excludedProposalIds)) {
|
||||
duplicateCondition.and("id", "not in", excludedProposalIds);
|
||||
}
|
||||
if (dao().count(ProposalInfo.class, duplicateCondition) > 0) {
|
||||
throw new BaseException("立案编号已存在,请重新填写");
|
||||
}
|
||||
args.put(caseFilingCodeKey, caseFilingCode);
|
||||
}
|
||||
|
||||
|
||||
+41
-53
@@ -654,9 +654,12 @@ public class ProposalExportServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
LEFT JOIN teacher_congress_session tcs on tcs.id = info.sessionId
|
||||
LEFT JOIN teacher_congress_delegation tcd on tcd.id = info.delegationId
|
||||
LEFT JOIN teacher_congress_delegate tcde on tcde.loginName = info.createUserLoginName
|
||||
LEFT JOIN proposal_reply_unit pru ON pru.proposalId = info.id
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
// 综合导出页面按当前选择的届次导出,避免公共查询参数的跨届次场景影响导出范围。
|
||||
cnd.andEX("info.sessionId", "=", pageForm.getSessionId());
|
||||
ProposalQueryComprehensiveParam.buildSearch(cnd, pageForm);
|
||||
cnd.groupBy("info.id");
|
||||
cnd.asc("info.code");
|
||||
@@ -687,46 +690,45 @@ public class ProposalExportServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
return StrUtil.blankToDefault(name, "unnamed").replaceAll("[\\\\/:*?\"<>|\\r\\n]+", "_");
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 ZIP 内唯一且合法的 Word 文件名,避免提案名称中的非法字符或重名条目导致整个压缩包缺文件。
|
||||
*
|
||||
* @param prefix 文档类型前缀
|
||||
* @param proposalRow 提案基础信息
|
||||
* @param entryNameCounts 已生成的基础文件名及其出现次数
|
||||
* @return 可以直接用于 ZipEntry 的文件名
|
||||
*/
|
||||
private String createUniqueZipDocxEntryName(String prefix, NutMap proposalRow, Map<String, Integer> entryNameCounts) {
|
||||
String baseName = sanitizeZipFileName(prefix + "-" + proposalRow.getString("code", "未编号") + "-" + proposalRow.getString("name", "未命名提案"));
|
||||
int sameNameCount = entryNameCounts.merge(baseName, 1, Integer::sum);
|
||||
return baseName + (sameNameCount > 1 ? "-" + sameNameCount : "") + ".docx";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exportFeedBackAsZip(ProposalQueryComprehensiveParam pageForm, HttpServletResponse response) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
info.id,
|
||||
info.code,
|
||||
info.name
|
||||
FROM
|
||||
proposal_info info
|
||||
LEFT JOIN proposal_type type on type.id = info.typeId
|
||||
LEFT JOIN teacher_congress_session tcs on tcs.id = info.sessionId
|
||||
LEFT JOIN teacher_congress_delegation tcd on tcd.id = info.delegationId
|
||||
LEFT JOIN teacher_congress_delegate tcde on tcde.loginName = info.createUserLoginName
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.groupBy("info.id");
|
||||
ProposalQueryComprehensiveParam.buildSearch(cnd, pageForm);
|
||||
sql.setCondition(cnd);
|
||||
List<NutMap> list = listMap(sql);
|
||||
|
||||
try {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
ZipOutputStream zipOutputStream = new ZipOutputStream(bos);
|
||||
List<NutMap> list = queryProposalBaseList(pageForm);
|
||||
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
ZipOutputStream zipOutputStream = new ZipOutputStream(bos)) {
|
||||
Map<String, Integer> entryNameCounts = new HashMap<>();
|
||||
for (NutMap proposalRow : list) {
|
||||
try (ByteArrayOutputStream docxByteArrayOutputStream = new ByteArrayOutputStream()) {
|
||||
proposalCommonService.exportProposalFeedBackAsDocx(proposalRow.getString("id"), docxByteArrayOutputStream);
|
||||
ZipEntry zipEntry = new ZipEntry("反馈表-" + proposalRow.getString("code") + "-" + proposalRow.getString("name") + ".docx");
|
||||
if (docxByteArrayOutputStream.size() == 0) {
|
||||
throw new BaseException("提案【{}】反馈表生成失败", proposalRow.getString("code"));
|
||||
}
|
||||
ZipEntry zipEntry = new ZipEntry(createUniqueZipDocxEntryName("反馈表", proposalRow, entryNameCounts));
|
||||
zipOutputStream.putNextEntry(zipEntry);
|
||||
docxByteArrayOutputStream.writeTo(zipOutputStream);
|
||||
zipOutputStream.closeEntry();
|
||||
} catch (IOException e) {
|
||||
// 处理单个文件生成失败的情况
|
||||
e.printStackTrace();
|
||||
throw new BaseException("提案【{}】反馈表写入压缩包失败", proposalRow.getString("code"));
|
||||
}
|
||||
}
|
||||
zipOutputStream.close();
|
||||
zipOutputStream.finish();
|
||||
CommonDownloadUtil.download("提案反馈表压缩包.zip", bos.toByteArray(), response);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.error("导出提案反馈表压缩包失败", e);
|
||||
throw new BaseException("导出提案反馈表压缩包失败:{}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -834,43 +836,29 @@ public class ProposalExportServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
|
||||
@Override
|
||||
public void exportCollectZip(ProposalQueryComprehensiveParam pageForm, HttpServletResponse response) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
info.id,
|
||||
info.code,
|
||||
info.name
|
||||
FROM
|
||||
proposal_info info
|
||||
LEFT JOIN teacher_congress_session tcs on tcs.id = info.sessionId
|
||||
LEFT JOIN teacher_congress_delegation tcd on tcd.id = info.delegationId
|
||||
LEFT JOIN teacher_congress_delegate tcde on tcde.loginName = info.createUserLoginName
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.groupBy("info.id");
|
||||
ProposalQueryComprehensiveParam.buildSearch(cnd, pageForm);
|
||||
sql.setCondition(cnd);
|
||||
List<NutMap> list = listMap(sql);
|
||||
|
||||
try {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
ZipOutputStream zipOutputStream = new ZipOutputStream(bos);
|
||||
List<NutMap> list = queryProposalBaseList(pageForm);
|
||||
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
ZipOutputStream zipOutputStream = new ZipOutputStream(bos)) {
|
||||
Map<String, Integer> entryNameCounts = new HashMap<>();
|
||||
for (NutMap proposalRow : list) {
|
||||
try (ByteArrayOutputStream docxByteArrayOutputStream = new ByteArrayOutputStream()) {
|
||||
exportCollectDocx(proposalRow.getString("id"), docxByteArrayOutputStream);
|
||||
ZipEntry zipEntry = new ZipEntry("征集表-" + proposalRow.getString("code") + "-" + proposalRow.getString("name") + ".docx");
|
||||
if (docxByteArrayOutputStream.size() == 0) {
|
||||
throw new BaseException("提案【{}】征集表生成失败", proposalRow.getString("code"));
|
||||
}
|
||||
ZipEntry zipEntry = new ZipEntry(createUniqueZipDocxEntryName("征集表", proposalRow, entryNameCounts));
|
||||
zipOutputStream.putNextEntry(zipEntry);
|
||||
docxByteArrayOutputStream.writeTo(zipOutputStream);
|
||||
zipOutputStream.closeEntry();
|
||||
} catch (IOException e) {
|
||||
// 处理单个文件生成失败的情况
|
||||
e.printStackTrace();
|
||||
throw new BaseException("提案【{}】征集表写入压缩包失败", proposalRow.getString("code"));
|
||||
}
|
||||
}
|
||||
zipOutputStream.close();
|
||||
zipOutputStream.finish();
|
||||
CommonDownloadUtil.download("提案征集表压缩包.zip", bos.toByteArray(), response);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.error("导出提案征集表压缩包失败", e);
|
||||
throw new BaseException("导出提案征集表压缩包失败:{}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+80
-24
@@ -17,6 +17,8 @@ import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class TeacherCongressInstitutionUserServiceImpl extends BaseServiceImpl<Teacher_congress_institution_user> implements TeacherCongressInstitutionUserService {
|
||||
@Inject
|
||||
@@ -49,21 +51,9 @@ public class TeacherCongressInstitutionUserServiceImpl extends BaseServiceImpl<T
|
||||
dao().insert(institutionUser);
|
||||
|
||||
Teacher_congress_institution institution = dao().fetch(Teacher_congress_institution.class, institutionId);
|
||||
if (institution.getCode().contains("TEACHER_CONGRESS_INSTITUTION_PROPOSAL_COMMITTEE") && identity.equals("主任")) {
|
||||
Sys_role sysRole = sysRoleService.getByCode(RoleConstant.PROPOSAL_COMMITTEE_DIRECTOR);
|
||||
int existsRole = dao().count(Sys_user_role.class, Cnd.where(Sys_user_role::getUserId, "=", userId)
|
||||
.and(Sys_user_role::getTcSessionId, "=", sessionId)
|
||||
.and(Sys_user_role::getRoleId, "=", sysRole.getId())
|
||||
);
|
||||
if (existsRole == 0) {
|
||||
Sys_user_role insertSysUserRole = new Sys_user_role();
|
||||
insertSysUserRole.setRoleId(sysRole.getId());
|
||||
insertSysUserRole.setUserId(userId);
|
||||
insertSysUserRole.setTcSessionId(sessionId);
|
||||
dao().insert(insertSysUserRole);
|
||||
sysRoleService.clearCache();
|
||||
sysUserService.clearCache();
|
||||
}
|
||||
// 提案审查委员会主任按届次同步提案委员会主任角色,兼容历史届次的旧机构编码。
|
||||
if (isProposalReviewCommittee(institution) && identity.equals("主任")) {
|
||||
grantProposalCommitteeDirectorRole(userId, sessionId);
|
||||
}
|
||||
if (institution.getCode().contains("TEACHER_CONGRESS_INSTITUTION_PROPOSAL_COMMITTEE") && identity.equals("副主任")) {
|
||||
Sys_role sysRole = sysRoleService.getByCode(RoleConstant.PROPOSAL_COMMITTEE_DEPUTY_DIRECTOR);
|
||||
@@ -135,15 +125,8 @@ public class TeacherCongressInstitutionUserServiceImpl extends BaseServiceImpl<T
|
||||
Teacher_congress_institution_user institutionUser = fetch(id);
|
||||
String institutionId = institutionUser.getInstitutionId();
|
||||
Teacher_congress_institution institution = dao().fetch(Teacher_congress_institution.class, institutionId);
|
||||
if (institution.getName().contains("提案工作委员会") && institutionUser.getIdentity().equals("主任")) {
|
||||
Sys_role sysRole = sysRoleService.getByCode(RoleConstant.PROPOSAL_COMMITTEE_DIRECTOR);
|
||||
dao().clear(Sys_user_role.class, Cnd.where(Sys_user_role::getUserId, "=", institutionUser.getUserId())
|
||||
.and(Sys_user_role::getTcSessionId, "=", institutionUser.getSessionId())
|
||||
.and(Sys_user_role::getRoleId, "=", sysRole.getId())
|
||||
);
|
||||
sysRoleService.clearCache();
|
||||
sysUserService.clearCache();
|
||||
}
|
||||
boolean proposalReviewCommitteeDirector = isProposalReviewCommittee(institution)
|
||||
&& institutionUser.getIdentity().equals("主任");
|
||||
if (institution.getName().contains("提案工作委员会") && institutionUser.getIdentity().equals("副主任")) {
|
||||
Sys_role sysRole = sysRoleService.getByCode(RoleConstant.PROPOSAL_COMMITTEE_DEPUTY_DIRECTOR);
|
||||
dao().clear(Sys_user_role.class, Cnd.where(Sys_user_role::getUserId, "=", institutionUser.getUserId())
|
||||
@@ -173,5 +156,78 @@ public class TeacherCongressInstitutionUserServiceImpl extends BaseServiceImpl<T
|
||||
sysUserService.clearCache();
|
||||
}
|
||||
dao().delete(institutionUser);
|
||||
// 删除主任后,仅在同届次不存在其他提案审查委员会主任时撤销系统角色。
|
||||
if (proposalReviewCommitteeDirector) {
|
||||
revokeProposalCommitteeDirectorRoleIfUnused(institutionUser.getUserId(), institutionUser.getSessionId());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断机构是否为提案审查委员会。ZXT001 为当前机构配置编码,旧编码用于兼容历史届次。
|
||||
*
|
||||
* @param institution 教代会机构
|
||||
* @return 是否属于提案审查委员会
|
||||
*/
|
||||
private boolean isProposalReviewCommittee(Teacher_congress_institution institution) {
|
||||
if (institution == null) {
|
||||
return false;
|
||||
}
|
||||
return "ZXT001".equals(institution.getCode())
|
||||
|| "TEACHER_CONGRESS_INSTITUTION_PROPOSAL_COMMITTEE".equals(institution.getCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* 为提案审查委员会主任授予当前届次的提案委员会主任角色,已有角色不重复写入。
|
||||
*
|
||||
* @param userId 用户主键
|
||||
* @param sessionId 教代会届次主键
|
||||
*/
|
||||
private void grantProposalCommitteeDirectorRole(String userId, String sessionId) {
|
||||
Sys_role sysRole = sysRoleService.getByCode(RoleConstant.PROPOSAL_COMMITTEE_DIRECTOR);
|
||||
if (sysRole == null) {
|
||||
throw new BaseException("提案委员会主任角色不存在");
|
||||
}
|
||||
int existsRole = dao().count(Sys_user_role.class, Cnd.where(Sys_user_role::getUserId, "=", userId)
|
||||
.and(Sys_user_role::getTcSessionId, "=", sessionId)
|
||||
.and(Sys_user_role::getRoleId, "=", sysRole.getId())
|
||||
);
|
||||
if (existsRole > 0) {
|
||||
return;
|
||||
}
|
||||
Sys_user_role insertSysUserRole = new Sys_user_role();
|
||||
insertSysUserRole.setRoleId(sysRole.getId());
|
||||
insertSysUserRole.setUserId(userId);
|
||||
insertSysUserRole.setTcSessionId(sessionId);
|
||||
dao().insert(insertSysUserRole);
|
||||
sysRoleService.clearCache();
|
||||
sysUserService.clearCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* 当用户在当前届次不再担任任何提案审查委员会主任时,撤销对应系统角色。
|
||||
*
|
||||
* @param userId 用户主键
|
||||
* @param sessionId 教代会届次主键
|
||||
*/
|
||||
private void revokeProposalCommitteeDirectorRoleIfUnused(String userId, String sessionId) {
|
||||
List<Teacher_congress_institution_user> institutionUsers = dao().query(Teacher_congress_institution_user.class,
|
||||
Cnd.where(Teacher_congress_institution_user::getUserId, "=", userId)
|
||||
.and(Teacher_congress_institution_user::getSessionId, "=", sessionId)
|
||||
.and(Teacher_congress_institution_user::getIdentity, "=", "主任"));
|
||||
boolean stillDirector = institutionUsers.stream()
|
||||
.map(institutionUser -> dao().fetch(Teacher_congress_institution.class, institutionUser.getInstitutionId()))
|
||||
.anyMatch(this::isProposalReviewCommittee);
|
||||
if (stillDirector) {
|
||||
return;
|
||||
}
|
||||
Sys_role sysRole = sysRoleService.getByCode(RoleConstant.PROPOSAL_COMMITTEE_DIRECTOR);
|
||||
if (sysRole == null) {
|
||||
return;
|
||||
}
|
||||
dao().clear(Sys_user_role.class, Cnd.where(Sys_user_role::getUserId, "=", userId)
|
||||
.and(Sys_user_role::getTcSessionId, "=", sessionId)
|
||||
.and(Sys_user_role::getRoleId, "=", sysRole.getId()));
|
||||
sysRoleService.clearCache();
|
||||
sysUserService.clearCache();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,6 +92,55 @@ public class WelfareListController {
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计当前搜索条件下的福利名单人数,用于批量删除前二次确认。
|
||||
*
|
||||
* @param pageForm 福利名单搜索条件
|
||||
* @return 命中人数
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("welfare.list.mange")
|
||||
public Result countByPageForm(@Valid @Param("pageForm") WelfareListPageForm pageForm) {
|
||||
if (StrUtil.isBlank(pageForm.getProjectId())) {
|
||||
return Result.error("请选择福利项目");
|
||||
}
|
||||
return Result.success(welfareListService.countByPageForm(pageForm));
|
||||
}
|
||||
|
||||
/**
|
||||
* 按当前搜索条件删除福利名单及对应的用户已选福利记录。
|
||||
*
|
||||
* @param pageForm 福利名单搜索条件
|
||||
* @return 删除结果
|
||||
*/
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@ApiOperation("按搜索条件删除福利名单人员")
|
||||
@SaCheckPermission("welfare.list.mange")
|
||||
@SLog(tag = "福利名单管理", msg = "按搜索条件批量删除福利名单人员")
|
||||
public Result deleteByPageForm(@Valid @Param("pageForm") WelfareListPageForm pageForm) {
|
||||
if (StrUtil.isBlank(pageForm.getProjectId())) {
|
||||
return Result.error("请选择福利项目");
|
||||
}
|
||||
int deletedCount = welfareListService.deleteByPageForm(pageForm);
|
||||
return Result.success("成功删除" + deletedCount + "人");
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据人员当前所属单位同步指定福利项目名单的单位和工会快照。
|
||||
*
|
||||
* @param projectId 福利项目 ID
|
||||
* @return 同步结果
|
||||
*/
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@ApiOperation("同步福利名单工会")
|
||||
@SaCheckPermission("welfare.list.mange")
|
||||
@SLog(tag = "福利名单管理", msg = "同步了福利名单单位和工会")
|
||||
public Result syncWelfareListUnitAndUnion(String projectId) {
|
||||
return welfareListService.syncWelfareListUnitAndUnion(projectId);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("welfare.list.mange")
|
||||
@ApiOperation("分页查询非福利会员")
|
||||
|
||||
+29
@@ -97,6 +97,17 @@ public class WelfareProjectMangeController {
|
||||
return Result.success(projectService.projectInfo(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询可沿用的往期福利项目。
|
||||
*
|
||||
* @return 往期福利项目列表
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("welfare.project.mange")
|
||||
public Result historyProjectList() {
|
||||
return Result.success(projectService.listHistoryProject());
|
||||
}
|
||||
|
||||
|
||||
@At
|
||||
@SaCheckPermission("welfare.project.mange")
|
||||
@@ -117,6 +128,24 @@ public class WelfareProjectMangeController {
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空指定福利项目的名单及用户已选福利记录。
|
||||
*
|
||||
* @param id 福利项目 ID
|
||||
* @return 清空结果
|
||||
*/
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SLog(tag = "福利", msg = "清空了福利名单")
|
||||
@SaCheckPermission("welfare.project.mange")
|
||||
public Result clearWelfareList(String id) {
|
||||
if (StrUtil.isBlank(id) || projectService.fetch(id) == null) {
|
||||
return Result.error("福利项目不存在");
|
||||
}
|
||||
projectService.clearWelfareList(id);
|
||||
return Result.success("福利名单已清空");
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("welfare.mine")
|
||||
public Result getWelfareList(Integer year) {
|
||||
|
||||
@@ -43,6 +43,9 @@ public class WelfareListPageForm extends PageForm {
|
||||
@ApiModelProperty("单位id")
|
||||
private String[] unitIds;
|
||||
|
||||
@ApiModelProperty("三级单位id")
|
||||
private String[] threeUnitIds;
|
||||
|
||||
@ApiModelProperty("单位名称")
|
||||
private String unitName;
|
||||
|
||||
@@ -59,6 +62,6 @@ public class WelfareListPageForm extends PageForm {
|
||||
private String aidFundMemberUserType;
|
||||
|
||||
@ApiModelProperty("人员属性")
|
||||
private String userAttribute;
|
||||
private String[] userAttributes;
|
||||
|
||||
}
|
||||
|
||||
@@ -33,6 +33,30 @@ public interface WelfareListService extends BaseService<WelfareList> {
|
||||
*/
|
||||
Pagination pageData(WelfareListPageForm pageForm);
|
||||
|
||||
/**
|
||||
* 统计当前搜索条件命中的福利名单人数。
|
||||
*
|
||||
* @param pageForm 福利名单搜索条件
|
||||
* @return 命中人数
|
||||
*/
|
||||
int countByPageForm(WelfareListPageForm pageForm);
|
||||
|
||||
/**
|
||||
* 按当前搜索条件删除福利名单及对应的用户已选福利记录。
|
||||
*
|
||||
* @param pageForm 福利名单搜索条件
|
||||
* @return 删除的名单人数
|
||||
*/
|
||||
int deleteByPageForm(WelfareListPageForm pageForm);
|
||||
|
||||
/**
|
||||
* 根据人员当前所属单位同步福利名单的单位和工会快照。
|
||||
*
|
||||
* @param projectId 福利项目 ID
|
||||
* @return 同步结果及变更人数
|
||||
*/
|
||||
Result syncWelfareListUnitAndUnion(String projectId);
|
||||
|
||||
/**
|
||||
* 查询非福利会员用户
|
||||
* @param pageForm
|
||||
|
||||
@@ -17,6 +17,13 @@ public interface WelfareProjectService extends BaseService<WelfareProject> {
|
||||
*/
|
||||
WelfareProject projectInfo(String projectId);
|
||||
|
||||
/**
|
||||
* 查询可用于沿用配置的历史福利项目。
|
||||
*
|
||||
* @return 历史福利项目列表
|
||||
*/
|
||||
List<WelfareProject> listHistoryProject();
|
||||
|
||||
/**
|
||||
* 校验福利选择是否保留系统默认福利。
|
||||
*
|
||||
@@ -44,6 +51,13 @@ public interface WelfareProjectService extends BaseService<WelfareProject> {
|
||||
*/
|
||||
void deleteWelfare(String id);
|
||||
|
||||
/**
|
||||
* 清空指定福利项目的名单及用户已选福利记录,保留项目配置。
|
||||
*
|
||||
* @param projectId 福利项目 ID
|
||||
*/
|
||||
void clearWelfareList(String projectId);
|
||||
|
||||
/**
|
||||
* 创建福利名单
|
||||
* @param projectId
|
||||
|
||||
+131
-12
@@ -28,11 +28,13 @@ import com.budwk.app.zhgh.welfare.service.WelfareListService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
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.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.json.Json;
|
||||
import org.nutz.lang.Lang;
|
||||
@@ -390,12 +392,130 @@ public class WelfareListServiceImpl extends BaseServiceImpl<WelfareList> impleme
|
||||
t2.loginname,
|
||||
t2.username,
|
||||
t2.sex,
|
||||
t2.birthday
|
||||
t2.birthday,
|
||||
threeUnit.name AS threeUnitName
|
||||
FROM
|
||||
`welfare_list` t1
|
||||
LEFT JOIN `vw_user` t2 ON t2.id = t1.userId
|
||||
LEFT JOIN sys_unit threeUnit ON threeUnit.id = t2.threeUnitId
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = buildPageDataCnd(pageForm);
|
||||
if (StrUtil.isAllBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) {
|
||||
cnd.asc("t1.welfareUnionName");
|
||||
cnd.asc("t1.welfareUnitName");
|
||||
} else {
|
||||
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||
}
|
||||
sql.setCondition(cnd);
|
||||
Pagination pagination = listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
return pagination;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int countByPageForm(WelfareListPageForm pageForm) {
|
||||
Sql sql = Sqls.create("SELECT COUNT(1) FROM welfare_list t1 LEFT JOIN vw_user t2 ON t2.id = t1.userId $condition");
|
||||
sql.setCondition(buildPageDataCnd(pageForm));
|
||||
sql.setCallback(Sqls.callback.integer());
|
||||
dao().execute(sql);
|
||||
return sql.getInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public int deleteByPageForm(WelfareListPageForm pageForm) {
|
||||
Sql sql = Sqls.create("SELECT t1.id, t1.userId FROM welfare_list t1 LEFT JOIN vw_user t2 ON t2.id = t1.userId $condition");
|
||||
sql.setCondition(buildPageDataCnd(pageForm));
|
||||
List<NutMap> welfareLists = listMap(sql);
|
||||
if (welfareLists.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
List<String> welfareListIds = welfareLists.stream().map(item -> item.getString("id")).collect(Collectors.toList());
|
||||
List<String> userIds = welfareLists.stream().map(item -> item.getString("userId")).filter(StrUtil::isNotBlank).distinct().collect(Collectors.toList());
|
||||
// 先清理当前项目中这些人员的已选福利记录,确保名单与选择数据保持一致。
|
||||
if (!userIds.isEmpty()) {
|
||||
dao().clear(WelfareUserSelection.class, Cnd.where("welfareId", "=", pageForm.getProjectId()).and("selectUserId", "in", userIds));
|
||||
}
|
||||
dao().clear(WelfareList.class, Cnd.where("id", "in", welfareListIds));
|
||||
return welfareListIds.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Result syncWelfareListUnitAndUnion(String projectId) {
|
||||
if (StrUtil.isBlank(projectId)) {
|
||||
return Result.error("请选择福利项目");
|
||||
}
|
||||
WelfareProject project = dao().fetch(WelfareProject.class, projectId);
|
||||
if (project == null) {
|
||||
return Result.error("福利项目不存在");
|
||||
}
|
||||
Date currentTime = new Date();
|
||||
if (project.getChoiceTimeStart() == null || project.getChoiceTimeEnd() == null
|
||||
|| currentTime.before(project.getChoiceTimeStart()) || currentTime.after(project.getChoiceTimeEnd())) {
|
||||
return Result.error("仅可在福利项目选择时间内同步工会");
|
||||
}
|
||||
|
||||
String unionScopeSql = "";
|
||||
boolean branchUnionRole = AuthUtil.hasRole(RoleConstant.BRANCH_UNION_CHAIRMAN.name())
|
||||
|| AuthUtil.hasRole(RoleConstant.BRANCH_UNION_ADMIN.name())
|
||||
|| AuthUtil.hasRole(RoleConstant.BRANCH_UNION_WENTI_SPORTS.name());
|
||||
if (branchUnionRole) {
|
||||
unionScopeSql = " AND unit.unionId = @currentUnionId";
|
||||
}
|
||||
|
||||
String changedConditionSql = """
|
||||
(IFNULL(wl.welfareUnitId, '') <> IFNULL(currentUser.unitId, '')
|
||||
OR IFNULL(wl.welfareUnitName, '') <> IFNULL(unit.name, '')
|
||||
OR IFNULL(wl.welfareUnionId, '') <> IFNULL(unionInfo.id, '')
|
||||
OR IFNULL(wl.welfareUnionName, '') <> IFNULL(unionInfo.name, ''))
|
||||
""";
|
||||
Sql countSql = Sqls.create("""
|
||||
SELECT COUNT(1)
|
||||
FROM welfare_list wl
|
||||
INNER JOIN vw_user currentUser ON currentUser.id = wl.userId
|
||||
LEFT JOIN sys_unit unit ON unit.id = currentUser.unitId
|
||||
LEFT JOIN sys_union unionInfo ON unionInfo.id = unit.unionId
|
||||
WHERE wl.projectId = @projectId
|
||||
AND """ + changedConditionSql + unionScopeSql);
|
||||
countSql.setParam("projectId", projectId);
|
||||
if (branchUnionRole) {
|
||||
countSql.setParam("currentUnionId", SecurityUtil.getUnionId());
|
||||
}
|
||||
countSql.setCallback(Sqls.callback.integer());
|
||||
dao().execute(countSql);
|
||||
int changedCount = countSql.getInt();
|
||||
if (changedCount == 0) {
|
||||
return Result.success("没有需要同步的人员");
|
||||
}
|
||||
|
||||
Sql updateSql = Sqls.create("""
|
||||
UPDATE welfare_list wl
|
||||
INNER JOIN vw_user currentUser ON currentUser.id = wl.userId
|
||||
LEFT JOIN sys_unit unit ON unit.id = currentUser.unitId
|
||||
LEFT JOIN sys_union unionInfo ON unionInfo.id = unit.unionId
|
||||
SET wl.welfareUnitId = currentUser.unitId,
|
||||
wl.welfareUnitName = unit.name,
|
||||
wl.welfareUnionId = unionInfo.id,
|
||||
wl.welfareUnionName = unionInfo.name
|
||||
WHERE wl.projectId = @projectId
|
||||
AND """ + changedConditionSql + unionScopeSql);
|
||||
updateSql.setParam("projectId", projectId);
|
||||
if (branchUnionRole) {
|
||||
updateSql.setParam("currentUnionId", SecurityUtil.getUnionId());
|
||||
}
|
||||
dao().execute(updateSql);
|
||||
return Result.success("成功同步" + changedCount + "人");
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建福利名单分页、统计和批量删除共用的筛选条件,确保三种操作范围一致。
|
||||
*
|
||||
* @param pageForm 福利名单搜索条件
|
||||
* @return 数据库查询条件
|
||||
*/
|
||||
private Cnd buildPageDataCnd(WelfareListPageForm pageForm) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("t1.projectId", "=", pageForm.getProjectId());
|
||||
if (StrUtil.isNotBlank(pageForm.getUserName())) {
|
||||
@@ -413,21 +533,14 @@ public class WelfareListServiceImpl extends BaseServiceImpl<WelfareList> impleme
|
||||
cnd.and("t2.unionId", "=", SecurityUtil.getUnionId());
|
||||
}
|
||||
cnd.andEX("t1.welfareUnitId", "in", pageForm.getUnitIds());
|
||||
cnd.andEX("t2.threeUnitId", "in", pageForm.getThreeUnitIds());
|
||||
cnd.andEX("t1.welfareUnionId", "=", pageForm.getUnionId());
|
||||
cnd.andEX("t1.personType", "in", pageForm.getPersonTypes());
|
||||
cnd.andEX("t1.preparedBy", "in", pageForm.getPreparedBys());
|
||||
cnd.andEX("t1.userState", "in", pageForm.getUserStates());
|
||||
cnd.andEX("t2.aidFundMemberUserType", "=", pageForm.getAidFundMemberUserType());
|
||||
cnd.andEX("t2.userAttribute", "=", pageForm.getUserAttribute());
|
||||
if (StrUtil.isAllBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) {
|
||||
cnd.asc("t1.welfareUnionName");
|
||||
cnd.asc("t1.welfareUnitName");
|
||||
} else {
|
||||
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||
}
|
||||
sql.setCondition(cnd);
|
||||
Pagination pagination = listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
return pagination;
|
||||
cnd.andEX("t2.userAttribute", "in", pageForm.getUserAttributes());
|
||||
return cnd;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -572,10 +685,12 @@ public class WelfareListServiceImpl extends BaseServiceImpl<WelfareList> impleme
|
||||
t2.loginname,
|
||||
t2.username,
|
||||
t2.sex,
|
||||
DATE_FORMAT(t2.birthday, '%Y-%m-%d') AS birthday
|
||||
DATE_FORMAT(t2.birthday, '%Y-%m-%d') AS birthday,
|
||||
threeUnit.name AS threeUnitName
|
||||
FROM
|
||||
`welfare_list` t1
|
||||
LEFT JOIN sys_user t2 ON t2.id = t1.userId
|
||||
LEFT JOIN sys_unit threeUnit ON threeUnit.id = t2.threeUnitId
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
@@ -592,10 +707,13 @@ public class WelfareListServiceImpl extends BaseServiceImpl<WelfareList> impleme
|
||||
cnd.andEX("MONTH(t2.birthday)", "in", pageForm.getBirthMonths());
|
||||
}
|
||||
cnd.andEX("t1.welfareUnitId", "in", pageForm.getUnitIds());
|
||||
cnd.andEX("t2.threeUnitId", "in", pageForm.getThreeUnitIds());
|
||||
cnd.andEX("t1.welfareUnionId", "=", pageForm.getUnionId());
|
||||
cnd.andEX("t1.personType", "in", pageForm.getPersonTypes());
|
||||
cnd.andEX("t1.preparedBy", "in", pageForm.getPreparedBys());
|
||||
cnd.andEX("t1.userState", "in", pageForm.getUserStates());
|
||||
cnd.andEX("t2.aidFundMemberUserType", "=", pageForm.getAidFundMemberUserType());
|
||||
cnd.andEX("t2.userAttribute", "in", pageForm.getUserAttributes());
|
||||
|
||||
if (StrUtil.isAllBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) {
|
||||
cnd.asc("t1.welfareUnionName");
|
||||
@@ -617,6 +735,7 @@ public class WelfareListServiceImpl extends BaseServiceImpl<WelfareList> impleme
|
||||
entities.add(new ExcelExportEntity("在职状态", "userState", 20));
|
||||
entities.add(new ExcelExportEntity("所属工会", "welfareUnionName", 20));
|
||||
entities.add(new ExcelExportEntity("所属单位", "welfareUnitName", 20));
|
||||
entities.add(new ExcelExportEntity("三级单位", "threeUnitName", 20));
|
||||
entities.add(new ExcelExportEntity("备注", "remark", 20));
|
||||
|
||||
// 设置导出参数
|
||||
|
||||
@@ -49,6 +49,11 @@ public class WelfareProjectServiceImpl extends BaseServiceImpl<WelfareProject> i
|
||||
return project;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<WelfareProject> listHistoryProject() {
|
||||
return dao().query(WelfareProject.class, Cnd.NEW().desc(WelfareProject::getYear).desc(WelfareProject::getChoiceTimeStart));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String validateSystemDefaultOptionSelection(String projectId, WelfareUserSelection[] selections) {
|
||||
List<WelfareProjectSubjectOption> systemDefaultOptions = dao().query(WelfareProjectSubjectOption.class,
|
||||
@@ -164,6 +169,14 @@ public class WelfareProjectServiceImpl extends BaseServiceImpl<WelfareProject> i
|
||||
dao().clear(Sys_home_activity.class, Cnd.where("id", "=", id));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void clearWelfareList(String projectId) {
|
||||
// 先清空用户选择记录,避免名单清空后保留无归属的福利选择数据。
|
||||
dao().clear(WelfareUserSelection.class, Cnd.where(WelfareUserSelection::getWelfareId, "=", projectId));
|
||||
dao().clear(WelfareList.class, Cnd.where(WelfareList::getProjectId, "=", projectId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createList(String projectId, boolean created) {
|
||||
WelfareProject project = projectInfo(projectId);
|
||||
|
||||
@@ -237,17 +237,18 @@ layout("/layouts/platform.html"){
|
||||
<el-dialog append-to-body :title="menuDialogTitle" :visible.sync="menuDialogVisible" :close-on-click-modal="false"
|
||||
width="70%">
|
||||
<!-- 搜索框 -->
|
||||
<!-- <el-row style="margin-bottom: 10px">-->
|
||||
<!-- <el-input-->
|
||||
<!-- v-model="searchText"-->
|
||||
<!-- placeholder="搜索11"-->
|
||||
<!-- size="small"-->
|
||||
<!-- clearable-->
|
||||
<!-- style="width: 300px"-->
|
||||
<!-- >-->
|
||||
<!-- <i slot="prefix" class="el-input__icon el-icon-search"></i>-->
|
||||
<!-- </el-input>-->
|
||||
<!-- </el-row>-->
|
||||
<el-row style="margin-bottom: 10px">
|
||||
<el-input
|
||||
v-model="searchText"
|
||||
placeholder="请输入权限名称"
|
||||
size="small"
|
||||
clearable
|
||||
style="width: 300px"
|
||||
@input="handleSearch"
|
||||
>
|
||||
<i slot="prefix" class="el-input__icon el-icon-search"></i>
|
||||
</el-input>
|
||||
</el-row>
|
||||
<el-row style="margin-bottom: 3px">
|
||||
<el-button size="small" @click="menuRoleSelAll">全选</el-button>
|
||||
<el-button size="small" @click="menuRoleSelClear">清空</el-button>
|
||||
@@ -257,7 +258,7 @@ layout("/layouts/platform.html"){
|
||||
|
||||
<el-tree
|
||||
ref="doMenuTree"
|
||||
:data="filteredMenuData"
|
||||
:data="doMenuData"
|
||||
:default-checked-keys="doMenuCheckedData"
|
||||
check-strictly
|
||||
show-checkbox
|
||||
@@ -265,6 +266,7 @@ layout("/layouts/platform.html"){
|
||||
check-strictly
|
||||
:props="defaultProps"
|
||||
:filter-node-method="filterNode"
|
||||
@check="handleMenuCheck"
|
||||
>
|
||||
<span class="custom-tree-node" slot-scope="{ node, data }">
|
||||
<span v-html="getDisplayText(node, data)"></span>
|
||||
@@ -444,6 +446,7 @@ layout("/layouts/platform.html"){
|
||||
addMenuData: [],
|
||||
doMenuData: [],
|
||||
doMenuCheckedData: [], //已分配的权限选中状态
|
||||
menuCheckedMap: {}, //完整权限树的勾选状态,搜索隐藏节点时仍需保留
|
||||
doCmsData: [],
|
||||
doCmsCheckedData: [], //已分配的CMS权限
|
||||
doCmsForm: {},
|
||||
@@ -494,7 +497,16 @@ layout("/layouts/platform.html"){
|
||||
methods: {
|
||||
// 搜索处理
|
||||
handleSearch(value) {
|
||||
this.$refs.doMenuTree.filter(value);
|
||||
// 弹框初次渲染完成后再执行筛选,避免树实例尚未创建。
|
||||
this.$nextTick(() => {
|
||||
this.$refs.doMenuTree.filter(value)
|
||||
})
|
||||
},
|
||||
|
||||
// 更新单个权限的勾选状态,避免搜索隐藏的权限在保存时丢失。
|
||||
handleMenuCheck(data, checked) {
|
||||
const isChecked = checked.checkedKeys.indexOf(data.id) !== -1
|
||||
this.$set(this.menuCheckedMap, data.id, isChecked)
|
||||
},
|
||||
|
||||
// 过滤节点方法
|
||||
@@ -578,8 +590,15 @@ layout("/layouts/platform.html"){
|
||||
doMenuLoad() {
|
||||
this.$axios.post("/platform/sys/role/menuRole/" + this.roleId + "/" + this.platform, {}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.doMenuData = res.data.menu
|
||||
this.doMenuCheckedData = res.data.cmenu
|
||||
const menuCheckedMap = {}
|
||||
res.data.cmenu.forEach((menuId) => {
|
||||
menuCheckedMap[menuId] = true
|
||||
})
|
||||
this.$set(this, "doMenuData", res.data.menu)
|
||||
this.$set(this, "doMenuCheckedData", res.data.cmenu)
|
||||
this.$set(this, "menuCheckedMap", menuCheckedMap)
|
||||
// 权限树数据刷新后清空上次搜索产生的筛选状态。
|
||||
this.handleSearch(this.searchText)
|
||||
}
|
||||
})
|
||||
},
|
||||
@@ -669,7 +688,10 @@ layout("/layouts/platform.html"){
|
||||
// return;
|
||||
// }
|
||||
|
||||
const ids = this.$refs["doMenuTree"].getCheckedKeys()
|
||||
// 从完整权限树的状态中组装提交数据,搜索隐藏节点不会被遗漏。
|
||||
const allMenuIds = []
|
||||
this.getTreeAllIds(allMenuIds, this.doMenuData)
|
||||
const ids = allMenuIds.filter((menuId) => this.menuCheckedMap[menuId])
|
||||
if (!ids || ids.length === 0) {
|
||||
this.$message.warning("请选择菜单或数据权限")
|
||||
return
|
||||
@@ -721,6 +743,7 @@ layout("/layouts/platform.html"){
|
||||
this.menuDialogVisible = true
|
||||
this.platform = "PC"
|
||||
this.roleId = command.id
|
||||
this.$set(this, "searchText", "")
|
||||
this.doMenuLoad()
|
||||
}
|
||||
if ("h5_menu" === command.type) {
|
||||
@@ -728,6 +751,7 @@ layout("/layouts/platform.html"){
|
||||
this.menuDialogVisible = true
|
||||
this.platform = "H5"
|
||||
this.roleId = command.id
|
||||
this.$set(this, "searchText", "")
|
||||
this.doMenuLoad()
|
||||
}
|
||||
|
||||
@@ -837,9 +861,15 @@ layout("/layouts/platform.html"){
|
||||
menuRoleSelAll() {
|
||||
const ids = []
|
||||
this.getTreeAllIds(ids, this.doMenuData)
|
||||
const menuCheckedMap = {}
|
||||
ids.forEach((menuId) => {
|
||||
menuCheckedMap[menuId] = true
|
||||
})
|
||||
this.$set(this, "menuCheckedMap", menuCheckedMap)
|
||||
this.$refs["doMenuTree"].setCheckedKeys(ids)
|
||||
},
|
||||
menuRoleSelClear() {
|
||||
this.$set(this, "menuCheckedMap", {})
|
||||
this.$refs["doMenuTree"].setCheckedKeys([])
|
||||
},
|
||||
clearButtons(list) {
|
||||
|
||||
@@ -75,7 +75,14 @@ const branchUnionUserManage = {
|
||||
<el-dialog title="添加" :visible.sync="dialogFormVisible" width="600px" :close-on-click-modal="false">
|
||||
<el-form :model="formData" ref="form" size="small" label-width="80px">
|
||||
<el-form-item prop="roleCode" label="角色">
|
||||
<dict-select v-model="formData.roleCode" code="BRANCH_UNION_ROLES" placeholder="请选择角色"></dict-select>
|
||||
<el-select v-model="formData.roleCode" placeholder="请选择角色" @change="handleRoleChange">
|
||||
<el-option v-for="item in roleOptions" :key="item.code" :label="item.name" :value="item.code"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="isUnitPartySecretary()" prop="unitIds" label="所属单位">
|
||||
<el-select v-model="formData.unitIds" multiple collapse-tags placeholder="请选择单位">
|
||||
<el-option v-for="item in partySecretaryUnitOptions" :key="item.id" :label="item.name" :value="item.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item prop="j" label="届数">
|
||||
<dict-select v-model="formData.j" code="TEACHER_CONGRESS_J" placeholder="请选择届数"></dict-select>
|
||||
@@ -138,6 +145,8 @@ const branchUnionUserManage = {
|
||||
},
|
||||
dialogFormVisible: false,
|
||||
formData: {},
|
||||
roleOptions: [],
|
||||
partySecretaryUnitOptions: [],
|
||||
leaveDialogVisible: false,
|
||||
leaveForm: {
|
||||
id: "",
|
||||
@@ -200,6 +209,32 @@ const branchUnionUserManage = {
|
||||
isLeft(row) {
|
||||
return row.isServing === false || row.isServing === 0 || row.displayStatus === "离任"
|
||||
},
|
||||
isUnitPartySecretary() {
|
||||
return this.formData.roleCode === "UNIT_PARTY_SECRETARY"
|
||||
},
|
||||
loadRoleOptions() {
|
||||
return $.get("/platform/sys/union/branchUnionRoleOptions").then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$set(this, "roleOptions", res.data || [])
|
||||
}
|
||||
})
|
||||
},
|
||||
loadPartySecretaryUnitOptions() {
|
||||
return $.get("/platform/sys/union/branchUnionPartySecretaryUnitOptions", {
|
||||
unionId: this.union_id
|
||||
}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$set(this, "partySecretaryUnitOptions", res.data || [])
|
||||
}
|
||||
})
|
||||
},
|
||||
handleRoleChange() {
|
||||
if (this.isUnitPartySecretary()) {
|
||||
this.loadPartySecretaryUnitOptions()
|
||||
return
|
||||
}
|
||||
this.$set(this.formData, "unitIds", [])
|
||||
},
|
||||
openAdd() {
|
||||
this.dialogFormVisible = true
|
||||
this.$nextTick(() => {
|
||||
@@ -218,8 +253,16 @@ const branchUnionUserManage = {
|
||||
this.$message.error("请选择届数")
|
||||
return
|
||||
}
|
||||
$.post("/platform/sys/union/insertBranchUnionUserRole", {
|
||||
if (this.isUnitPartySecretary() && (!this.formData.unitIds || this.formData.unitIds.length === 0)) {
|
||||
this.$message.error("请选择所属单位")
|
||||
return
|
||||
}
|
||||
const submitUrl = this.isUnitPartySecretary()
|
||||
? "/platform/sys/union/insertBranchUnionPartySecretaryRole"
|
||||
: "/platform/sys/union/insertBranchUnionUserRole"
|
||||
$.post(submitUrl, {
|
||||
...this.formData,
|
||||
unitIds: JSON.stringify(this.formData.unitIds || []),
|
||||
unionId: this.union_id
|
||||
}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
@@ -279,6 +322,7 @@ const branchUnionUserManage = {
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadRoleOptions()
|
||||
this.initJSearch()
|
||||
},
|
||||
style: /*language=CSS*/ `
|
||||
|
||||
@@ -780,13 +780,13 @@ layout("/layouts/platform.html"){
|
||||
return data;
|
||||
|
||||
},
|
||||
async getUnionList(row) {
|
||||
const {activityId, eventId} = row
|
||||
const {data} = await this.$axios.post(loc() + "/getUnionList", {
|
||||
activityId: activityId,
|
||||
eventId: eventId
|
||||
async getUnionList() {
|
||||
// 团体成绩可录入任意分工会,使用全量分工会列表而非项目报名分工会。
|
||||
const unionList = await this.$businessTool.listUnion()
|
||||
return unionList.map(item => {
|
||||
this.$set(item, "unionname", item.name)
|
||||
return item
|
||||
})
|
||||
return data;
|
||||
},
|
||||
openAddUser() {
|
||||
this.userData.push({})
|
||||
|
||||
@@ -73,7 +73,7 @@ layout("/layouts/platform.html"){
|
||||
<evaluate-info ref="evaluateInfoRef">
|
||||
<div v-if="showApprovalForm">
|
||||
<div class="process-title">
|
||||
{{formData.taskName}}
|
||||
会长审核
|
||||
</div>
|
||||
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=":"
|
||||
class="flow-task-form">
|
||||
|
||||
@@ -29,7 +29,7 @@ const EVALUATE_INFO_COMPONENT = {
|
||||
|
||||
<template v-for="task in doneTasks">
|
||||
<div class="mt10">
|
||||
<div class="process-title">{{ task.displayName }}</div>
|
||||
<div class="process-title">{{ getAuditDisplayName(task.displayName) }}</div>
|
||||
<el-descriptions border class="flow-task-form" :column="3" :key="task.id"
|
||||
v-if="task.ext.isFirstTaskNode">
|
||||
<el-descriptions-item label="申请用户">{{ task.ext.initiatorName
|
||||
@@ -72,6 +72,10 @@ const EVALUATE_INFO_COMPONENT = {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 兼容历史流程节点名称,统一展示为会长审核。
|
||||
getAuditDisplayName(displayName) {
|
||||
return displayName === "协会审核" ? "会长审核" : displayName
|
||||
},
|
||||
onOpen(row) {
|
||||
this.row = row
|
||||
this.$axios.post("/platform/club/evaluate/apply/info", { id: row.id }).then((res) => {
|
||||
|
||||
@@ -70,7 +70,7 @@ layout("/layouts/platform.html"){
|
||||
<examine-info ref="examineInfoRef">
|
||||
<div v-if="showApprovalForm">
|
||||
<div class="process-title">
|
||||
{{formData.taskName}}
|
||||
会长审核
|
||||
</div>
|
||||
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=":"
|
||||
class="flow-task-form">
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
<el-tab-pane name="5" label="审核记录">
|
||||
<template v-if="doneTasks.length > 0" v-for="task in doneTasks">
|
||||
<div class="mt10">
|
||||
<div class="process-title">{{ task.displayName }}</div>
|
||||
<div class="process-title">{{ getAuditDisplayName(task.displayName) }}</div>
|
||||
<el-descriptions border class="flow-task-form" :column="3" :key="task.id"
|
||||
v-if="task.ext.isFirstTaskNode">
|
||||
<el-descriptions-item label="申请用户">{{ task.ext.initiatorName
|
||||
@@ -119,6 +119,17 @@
|
||||
</el-descriptions>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="legacyAuditRecords.length > 0">
|
||||
<div class="mt10" v-for="record in legacyAuditRecords" :key="record.id">
|
||||
<div class="process-title">{{ record.auditName }}</div>
|
||||
<el-descriptions border class="flow-task-form" :column="3">
|
||||
<el-descriptions-item label="办理用户">{{ record.userName }}({{ record.loginName }})</el-descriptions-item>
|
||||
<el-descriptions-item label="办理时间">{{ record.auditTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="办理结果">{{ record.auditPass ? "审核通过" : "审核不通过" }}</el-descriptions-item>
|
||||
<el-descriptions-item label="办理意见" span="3">{{ record.auditOpinion }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-empty description="暂无审核记录"></el-empty>
|
||||
</template>
|
||||
@@ -133,6 +144,7 @@
|
||||
activeName: "1",
|
||||
row: {},
|
||||
doneTasks: [],
|
||||
legacyAuditRecords: [],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -149,11 +161,16 @@
|
||||
const totalExpend = Number(row.totalExpend) || 0
|
||||
return lastYearSurplus + income + allocate + support + otherIncome - totalExpend
|
||||
},
|
||||
// 兼容历史流程节点名称,统一展示为会长审核。
|
||||
getAuditDisplayName(displayName) {
|
||||
return displayName === "协会审核" ? "会长审核" : displayName
|
||||
},
|
||||
async onOpen(row) {
|
||||
this.row = row
|
||||
const resp = await this.$axios.post("/platform/club/examine/common/findOne", { id: row.id })
|
||||
if (resp.code === 0) {
|
||||
this.viewData = resp.data
|
||||
this.$set(this, "legacyAuditRecords", resp.data.legacyAuditRecords || [])
|
||||
await this.getClubUserNum(resp.data.clubId)
|
||||
await this.getJgUser(resp.data.clubId)
|
||||
}
|
||||
@@ -176,7 +193,7 @@
|
||||
getDoneTasks() {
|
||||
this.$axios.post("/flow/common/doneTasks", {bizId: this.row.id}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.doneTasks = res.data
|
||||
this.$set(this, "doneTasks", res.data || [])
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
@@ -163,11 +163,7 @@ const CLUB_FORM_TEMPLATE = {
|
||||
clubCode: [{ required: false, message: "请填写社团编码", trigger: ["blur", "change"] }],
|
||||
clubType: [{ required: true, message: "请选择社团类型", trigger: ["blur", "change"] }],
|
||||
//concatPerson: [{ required: true, message: "请选择社团联系人", trigger: ["blur", "change"] }],
|
||||
foundTime: [{ required: true, message: "请选择成立时间", trigger: ["blur", "change"] }],
|
||||
establishReport: [{ required: true, message: "请上传申请成立报告", trigger: ["blur", "change"] }],
|
||||
rulesFile: [{ required: true, message: "请上传章程草案", trigger: ["blur", "change"] }],
|
||||
manageFile: [{ required: true, message: "请上传经费来源及管理办法", trigger: ["blur", "change"] }],
|
||||
yearPlanFile: [{ required: true, message: "请上传年度活动计划", trigger: ["blur", "change"] }]
|
||||
foundTime: [{ required: true, message: "请选择成立时间", trigger: ["blur", "change"] }]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -121,8 +121,11 @@ layout("/layouts/platform.html"){
|
||||
if(valid) await this.doHandle("onFinishTask")
|
||||
},
|
||||
async doHandle(type) {
|
||||
let formData = {}
|
||||
try {
|
||||
// 保存和提交均需传递发起人,确保草稿再次编辑时可正确回显。
|
||||
const sponsors = this.$refs.clubSponsorRef.sponsorData
|
||||
.filter((item) => item.userId !== "" && item.userId !== undefined)
|
||||
.map((item) => ({ sponsorId: item.userId }))
|
||||
if("onSave" !== type) {
|
||||
let hz = this.$refs.clubManagerRef.managePerson.filter((o) => o.roleCode === CLUB_ROLE_CONSTANT.CLUB_PRESIDENT)
|
||||
if (hz.length !== 1) {
|
||||
@@ -134,9 +137,6 @@ layout("/layouts/platform.html"){
|
||||
this.$message.warning({ title: "警告", message: "秘书长需要1人" })
|
||||
return
|
||||
}
|
||||
formData.sponsor = this.$refs.clubSponsorRef.sponsorData
|
||||
.filter((o) => o.userId !== "" && o.userId !== undefined)
|
||||
.map((o) => o.userId)
|
||||
if (['onFinishTask', 'onSubmit'].includes(type) && !this.validateSponsorCount()) {
|
||||
return
|
||||
}
|
||||
@@ -153,15 +153,7 @@ layout("/layouts/platform.html"){
|
||||
}
|
||||
}
|
||||
const cloneData = clone(this.$refs.clubFormRef.formData)
|
||||
let array = []
|
||||
if (formData.sponsor) {
|
||||
formData.sponsor.forEach((item) => {
|
||||
array.push({
|
||||
sponsorId: item
|
||||
})
|
||||
})
|
||||
}
|
||||
cloneData.sponsors = array
|
||||
cloneData.sponsors = sponsors
|
||||
let url = '';
|
||||
if(type === 'onSave') {
|
||||
url = '/platform/club/register/clubRegisterApply/save'
|
||||
|
||||
@@ -229,44 +229,54 @@ const apply_component = {
|
||||
})
|
||||
},
|
||||
onSubmit() {
|
||||
this.$confirm("您确定要提交吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
this.$axios.post('/platform/evaluate/apply/submit', {
|
||||
data: JSON.stringify(this.formData),
|
||||
taskId: this.taskId
|
||||
}).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success("提交成功")
|
||||
if (this.formData.id) {
|
||||
this.$emit('refresh')
|
||||
} else {
|
||||
commonUtil.pjaxPush('/platform/evaluate/mine')
|
||||
this.$refs.formRef.validate((valid) => {
|
||||
if (!valid) {
|
||||
return
|
||||
}
|
||||
this.$confirm("您确定要提交吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
this.$axios.post('/platform/evaluate/apply/submit', {
|
||||
data: JSON.stringify(this.formData),
|
||||
taskId: this.taskId
|
||||
}).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success("提交成功")
|
||||
if (this.formData.id) {
|
||||
this.$emit('refresh')
|
||||
} else {
|
||||
commonUtil.pjaxPush('/platform/evaluate/mine')
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
onFinishTask() {
|
||||
this.$confirm("您确定要提交吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
this.$axios.post('/platform/evaluate/apply/submitAgain', {
|
||||
data: JSON.stringify(this.formData),
|
||||
taskId: this.taskId
|
||||
}).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success("提交成功")
|
||||
if (this.formData.id) {
|
||||
this.$emit('refresh')
|
||||
} else {
|
||||
commonUtil.pjaxPush('/platform/evaluate/mine')
|
||||
this.$refs.formRef.validate((valid) => {
|
||||
if (!valid) {
|
||||
return
|
||||
}
|
||||
this.$confirm("您确定要提交吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
this.$axios.post('/platform/evaluate/apply/submitAgain', {
|
||||
data: JSON.stringify(this.formData),
|
||||
taskId: this.taskId
|
||||
}).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success("提交成功")
|
||||
if (this.formData.id) {
|
||||
this.$emit('refresh')
|
||||
} else {
|
||||
commonUtil.pjaxPush('/platform/evaluate/mine')
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
@@ -168,7 +168,6 @@ layout("/layouts/platform.html"){
|
||||
created() {
|
||||
this.listSession()
|
||||
this.setTableColumnsByProposalResult()
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -77,6 +77,7 @@ layout("/layouts/platform.html"){
|
||||
<el-table :data="tableData" @sort-change="pageOrder" header-align="center" style="width: 100%" row-key="id">
|
||||
<el-table-column label="序号" width="50" type="index" :index="indexMethod"></el-table-column>
|
||||
<el-table-column label="提案编号" prop="code" sortable="custom" width="100px" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="立案编号" prop="caseFilingCode" width="100px" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="提案名称" prop="name" sortable="custom" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="提案人" prop="createUserName" sortable="custom"></el-table-column>
|
||||
<el-table-column label="提案类别" prop="typeName" sortable="custom"></el-table-column>
|
||||
@@ -133,8 +134,16 @@ layout("/layouts/platform.html"){
|
||||
:rules="[{required:true,message:'请输入提案编号',trigger:'blur'}]">
|
||||
<el-input maxlength="100" placeholder="提案编号" v-model="formData.code"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="立案编号" prop="caseFilingCode">
|
||||
<el-input maxlength="100" placeholder="立案编号" v-model="formData.caseFilingCode"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" type="flex">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="提案名称" prop="name"
|
||||
:rules="[{required:true,message:'请输入提案名称',trigger:'blur'}]">
|
||||
<el-input maxlength="100" placeholder="提案名称" v-model="formData.name"></el-input>
|
||||
|
||||
@@ -75,6 +75,7 @@ layout("/layouts/platform.html"){
|
||||
<!-- <el-dropdown-item :command="{type:'status',data:row}">{{row.isDisabled?'发布':'关闭'}}</el-dropdown-item>-->
|
||||
<!-- <el-dropdown-item :command="{type:'sendMsg',data:row}">通知未选择人员</el-dropdown-item>-->
|
||||
<el-dropdown-item :command="{type:'createList',data:row}">生成福利名单</el-dropdown-item>
|
||||
<el-dropdown-item :command="{type:'clearList',data:row}">清空福利名单</el-dropdown-item>
|
||||
<el-dropdown-item :command="{type:'edit',data:row}">编辑</el-dropdown-item>
|
||||
<el-dropdown-item :command="{type:'delete',data:row}">删除</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
@@ -88,6 +89,14 @@ layout("/layouts/platform.html"){
|
||||
|
||||
<template #edit>
|
||||
<el-form :model="formData" :rules="formRules" label-width="150px" ref="form" v-loading="formLoading">
|
||||
<el-form-item label="沿用往期福利" v-if="!formData.id">
|
||||
<el-select clearable filterable placeholder="请选择往期福利" style="width: 100%"
|
||||
v-model="reuseProjectId" @change="reuseHistoryProject">
|
||||
<el-option :key="item.id" :label="item.year + '年 - ' + item.name" :value="item.id"
|
||||
v-for="item in historyProjectOptions"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="项目名称" prop="name">
|
||||
<el-input maxlength="100" placeholder="项目名称" v-model="formData.name"></el-input>
|
||||
</el-form-item>
|
||||
@@ -211,7 +220,7 @@ layout("/layouts/platform.html"){
|
||||
|
||||
<template v-if="formData.flexible">
|
||||
<el-form-item label="福利选项">
|
||||
<welfare-option v-model="formData.options"></welfare-option>
|
||||
<welfare-option :key="welfareOptionKey" v-model="formData.options"></welfare-option>
|
||||
</el-form-item>
|
||||
</template>
|
||||
|
||||
@@ -278,7 +287,10 @@ layout("/layouts/platform.html"){
|
||||
gift: [{ required: true, message: "必填", trigger: ["blur", "change"] }],
|
||||
multiSelectNum: [{ required: true, message: "必填", trigger: ["blur", "change"] }]
|
||||
},
|
||||
welfarePersonTypeList: []
|
||||
welfarePersonTypeList: [],
|
||||
historyProjectOptions: [],
|
||||
reuseProjectId: null,
|
||||
welfareOptionKey: 0
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -290,6 +302,8 @@ layout("/layouts/platform.html"){
|
||||
this.doDelete(data.id)
|
||||
} else if (type === "createList") {
|
||||
this.$refs.filterUserRef.onOpen(data.id)
|
||||
} else if (type === "clearList") {
|
||||
this.clearWelfareList(data)
|
||||
} else if (type === "status") {
|
||||
this.projectStatusChange(data)
|
||||
} else if (type === "sendMsg") {
|
||||
@@ -364,8 +378,9 @@ layout("/layouts/platform.html"){
|
||||
}
|
||||
},
|
||||
sendMsg(row) {},
|
||||
openAdd() {
|
||||
this.formData = {
|
||||
async openAdd() {
|
||||
this.$set(this, "reuseProjectId", null)
|
||||
this.$set(this, "formData", {
|
||||
isPushHome: false,
|
||||
signMode: 4,
|
||||
isRoutine: true,
|
||||
@@ -375,9 +390,54 @@ layout("/layouts/platform.html"){
|
||||
noticePushMode: 1,
|
||||
welfareProjectSubjects: [],
|
||||
flexibleGifts: [{}]
|
||||
}
|
||||
})
|
||||
this.$refs.guava.edit()
|
||||
if (this.$refs.form) this.$refs.form.resetFields()
|
||||
await this.loadHistoryProjectOptions()
|
||||
},
|
||||
// 查询可沿用的历史福利项目,用于下拉选择。
|
||||
async loadHistoryProjectOptions() {
|
||||
const resp = await this.$axios.post(loc() + "/historyProjectList")
|
||||
if (resp.code === 0) {
|
||||
this.$set(this, "historyProjectOptions", resp.data || [])
|
||||
} else {
|
||||
this.$message.error(resp.msg)
|
||||
}
|
||||
},
|
||||
// 清除往期项目的主键、关联和审计字段,确保提交时创建全新的福利项目及选项。
|
||||
clearReuseProjectIdentifiers(project) {
|
||||
["id", "year", "taskId", "createdBy", "createdAt", "updatedBy", "updatedAt"].forEach((field) => {
|
||||
delete project[field]
|
||||
})
|
||||
const options = project.options || []
|
||||
options.forEach((option) => {
|
||||
["id", "subjectId", "welfareId", "createdBy", "createdAt", "updatedBy", "updatedAt"].forEach((field) => {
|
||||
delete option[field]
|
||||
})
|
||||
})
|
||||
},
|
||||
async reuseHistoryProject(projectId) {
|
||||
if (!projectId) {
|
||||
return
|
||||
}
|
||||
this.$set(this, "submitLoading", true)
|
||||
try {
|
||||
const resp = await this.$axios.post(loc() + "/findOne", { id: projectId })
|
||||
if (resp.code !== 0 || !resp.data) {
|
||||
this.$message.error(resp.msg || "往期福利查询失败")
|
||||
return
|
||||
}
|
||||
const projectData = clone(resp.data)
|
||||
this.clearReuseProjectIdentifiers(projectData)
|
||||
this.$set(projectData, "choiceTime", [projectData.choiceTimeStart, projectData.choiceTimeEnd])
|
||||
this.$set(projectData, "provideTime", [projectData.provideTimeStart, projectData.provideTimeEnd])
|
||||
this.$set(this, "formData", projectData)
|
||||
this.$set(this, "welfareOptionKey", this.welfareOptionKey + 1)
|
||||
} catch (e) {
|
||||
this.$message.error("往期福利查询失败,请稍后重试")
|
||||
} finally {
|
||||
this.$set(this, "submitLoading", false)
|
||||
}
|
||||
},
|
||||
async projectStatusChange({ id, isDisabled: val }) {
|
||||
const resp = await this.$axios.post(loc() + "/projectStatusChange", {
|
||||
@@ -391,6 +451,27 @@ layout("/layouts/platform.html"){
|
||||
this.$message.warning(resp.msg)
|
||||
}
|
||||
},
|
||||
// 清空指定项目的福利名单及用户已选福利记录,保留项目配置和历史评价数据。
|
||||
clearWelfareList(row) {
|
||||
this.$confirm("确定清空“" + row.name + "”的福利名单吗?该操作会同时删除已选福利记录,且不可恢复。", "高风险操作", {
|
||||
confirmButtonText: "确认清空",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(async () => {
|
||||
try {
|
||||
this.submitLoading = true
|
||||
const resp = await this.$axios.post(loc() + "/clearWelfareList", { id: row.id })
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
this.pageData()
|
||||
} else {
|
||||
this.$message.error(resp.msg)
|
||||
}
|
||||
} finally {
|
||||
this.submitLoading = false
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
async openEdit(row) {
|
||||
this.submitLoading = true
|
||||
|
||||
@@ -63,12 +63,10 @@ const addUser = {
|
||||
</search-item>
|
||||
|
||||
<search-item label="所属单位">
|
||||
<el-select clearable
|
||||
<el-select @change="unitChange" clearable
|
||||
filterable
|
||||
multiple
|
||||
collapse-tags
|
||||
placeholder="请选择所属单位" style="width: 100%"
|
||||
v-model="pageForm.unitIds">
|
||||
v-model="pageForm.unitId">
|
||||
<el-option
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
@@ -78,6 +76,18 @@ const addUser = {
|
||||
</el-select>
|
||||
</search-item>
|
||||
|
||||
<search-item label="三级单位">
|
||||
<el-select clearable filterable placeholder="请先选择所属单位" style="width: 100%"
|
||||
v-model="pageForm.threeUnitId">
|
||||
<el-option
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
v-for="item in threeUnitOptions">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
|
||||
<search-item label="人员类型:">
|
||||
<dict-select clearable code="USER_PERSON_TYPE"
|
||||
multiple
|
||||
@@ -86,6 +96,13 @@ const addUser = {
|
||||
v-model="pageForm.personTypes"></dict-select>
|
||||
</search-item>
|
||||
|
||||
<search-item label="人员属性:">
|
||||
<dict-select clearable code="USER_ATTRIBUTE"
|
||||
multiple
|
||||
collapse-tags
|
||||
placeholder="请选择人员属性"
|
||||
v-model="pageForm.userAttributes"></dict-select>
|
||||
</search-item>
|
||||
|
||||
<search-item label="在职状态:">
|
||||
<dict-select clearable code="USER_STATE"
|
||||
@@ -153,8 +170,10 @@ const addUser = {
|
||||
birthday: null,
|
||||
birthMonths: [],
|
||||
unionId: null,
|
||||
unitIds: [],
|
||||
unitId: null,
|
||||
threeUnitId: null,
|
||||
personTypes: [],
|
||||
userAttributes: [],
|
||||
preparedBys: [],
|
||||
userStates: [],
|
||||
isMember: null
|
||||
@@ -162,6 +181,7 @@ const addUser = {
|
||||
sexOptions: ["男", "女"],
|
||||
unionOptions: [],
|
||||
unitOptions: [],
|
||||
threeUnitOptions: [],
|
||||
tableColumns: [
|
||||
{ prop: "loginname", label: "工号" },
|
||||
{ prop: "username", label: "姓名" },
|
||||
@@ -170,7 +190,8 @@ const addUser = {
|
||||
{ prop: "personType", label: "人员类型", sortable: true },
|
||||
{ prop: "userState", label: "在职状态", sortable: true },
|
||||
{ prop: "unionName", label: "所属工会", sortable: true },
|
||||
{ prop: "unitName", label: "所属单位", sortable: true }
|
||||
{ prop: "unitName", label: "所属单位", sortable: true },
|
||||
{ prop: "threeUnitName", label: "三级单位", sortable: true }
|
||||
]
|
||||
}
|
||||
},
|
||||
@@ -192,20 +213,45 @@ const addUser = {
|
||||
this.$set(this.pageForm, "birthMonths", [])
|
||||
this.$set(this.pageForm, "unionId", null)
|
||||
this.$set(this.pageForm, "unitId", null)
|
||||
this.$set(this.pageForm, "threeUnitId", null)
|
||||
this.$set(this, "threeUnitOptions", [])
|
||||
this.$set(this.pageForm, "personTypes", [])
|
||||
this.$set(this.pageForm, "userAttributes", [])
|
||||
this.$set(this.pageForm, "preparedBys", [])
|
||||
this.$set(this.pageForm, "userStates", [])
|
||||
this.$set(this.pageForm, "isMember", null)
|
||||
},
|
||||
|
||||
async unionIdChange(val) {
|
||||
this.$set(this.pageForm, "unitId", null)
|
||||
this.unitChange(null)
|
||||
if (val) {
|
||||
this.unitOptions = await this.$businessTool.listUnit(val)
|
||||
this.$set(this, "unitOptions", await this.$businessTool.listUnit(val))
|
||||
} else {
|
||||
this.pageForm.unitIds = []
|
||||
this.$set(this, "unitOptions", await this.$businessTool.listUnit())
|
||||
}
|
||||
},
|
||||
|
||||
// 所属单位改变后,仅加载该单位直属的三级单位,避免跨单位筛选。
|
||||
unitChange(unitId) {
|
||||
this.$set(this.pageForm, "threeUnitId", null)
|
||||
this.$set(this, "threeUnitOptions", [])
|
||||
if (!unitId) {
|
||||
return
|
||||
}
|
||||
this.$axios.post("/platform/sys/unit/child", { pid: unitId })
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$set(this, "threeUnitOptions", res.data || [])
|
||||
} else {
|
||||
this.$message.error(res.msg || "三级单位查询失败")
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.$message.error("三级单位查询失败,请稍后重试")
|
||||
})
|
||||
},
|
||||
|
||||
pageData() {
|
||||
this.tableLoading = true
|
||||
this.$axios
|
||||
|
||||
@@ -81,12 +81,27 @@ layout("/layouts/platform.html"){
|
||||
collapse-tags
|
||||
placeholder="请选择所属单位"
|
||||
style="width: 100%"
|
||||
@change="unitIdsChange"
|
||||
v-model="pageForm.unitIds"
|
||||
>
|
||||
<el-option :key="item.id" :label="item.name" :value="item.id" v-for="item in unitOptions"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
|
||||
<search-item label="三级单位">
|
||||
<el-select
|
||||
clearable
|
||||
filterable
|
||||
multiple
|
||||
collapse-tags
|
||||
placeholder="请先选择所属单位"
|
||||
style="width: 100%"
|
||||
v-model="pageForm.threeUnitIds"
|
||||
>
|
||||
<el-option :key="item.id" :label="item.name" :value="item.id" v-for="item in threeUnitOptions"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
|
||||
<search-item label="人员类型:">
|
||||
<dict-select
|
||||
clearable
|
||||
@@ -114,8 +129,8 @@ layout("/layouts/platform.html"){
|
||||
code="AIDFUND_MEMBER_USER_TYPE"></dict-select>
|
||||
</search-item>
|
||||
<search-item label="人员属性">
|
||||
<dict-select v-model="pageForm.userAttribute" placeholder="请选择人员属性" @change="doSearch"
|
||||
code="USER_ATTRIBUTE"></dict-select>
|
||||
<dict-select v-model="pageForm.userAttributes" placeholder="请选择人员属性" @change="doSearch"
|
||||
code="USER_ATTRIBUTE" clearable multiple collapse-tags></dict-select>
|
||||
</search-item>
|
||||
|
||||
<!-- <search-item label="所选福利:">-->
|
||||
@@ -128,6 +143,9 @@ layout("/layouts/platform.html"){
|
||||
|
||||
<el-card class="mt10" shadow="never">
|
||||
<table-tool :app="this" label="福利名单">
|
||||
<el-button :disabled="!pageForm.projectId" :loading="batchDeleteLoading" @click="deleteSearchUsers" icon="el-icon-delete" size="small" type="danger">
|
||||
删除人员
|
||||
</el-button>
|
||||
<el-button :disabled="!pageForm.projectId" @click="openExport" icon="el-icon-download" size="small" type="primary">
|
||||
导出名单
|
||||
</el-button>
|
||||
@@ -143,6 +161,9 @@ layout("/layouts/platform.html"){
|
||||
>
|
||||
添加人员
|
||||
</el-button>
|
||||
<el-button :disabled="!canSyncUnion" :loading="syncUnionLoading" @click="syncWelfareListUnitAndUnion" icon="el-icon-refresh" size="small" type="primary">
|
||||
同步工会
|
||||
</el-button>
|
||||
</table-tool>
|
||||
|
||||
<el-table
|
||||
@@ -239,6 +260,13 @@ layout("/layouts/platform.html"){
|
||||
return null
|
||||
}
|
||||
return null
|
||||
},
|
||||
canSyncUnion() {
|
||||
const projectInfo = this.projectSelectOptions.find((v) => v.id === this.pageForm.projectId)
|
||||
if (!projectInfo || !projectInfo.choiceTimeStart || !projectInfo.choiceTimeEnd) {
|
||||
return false
|
||||
}
|
||||
return moment().isBetween(projectInfo.choiceTimeStart, projectInfo.choiceTimeEnd, null, "[]")
|
||||
}
|
||||
},
|
||||
components: {
|
||||
@@ -255,6 +283,7 @@ layout("/layouts/platform.html"){
|
||||
},
|
||||
unionOptions: [],
|
||||
unitOptions: [],
|
||||
threeUnitOptions: [],
|
||||
sexOptions: ["男", "女"],
|
||||
projectSelectOptions: [],
|
||||
tableColumns: [
|
||||
@@ -266,6 +295,7 @@ layout("/layouts/platform.html"){
|
||||
{ prop: "userState", label: "在职状态", sortable: true },
|
||||
{ prop: "welfareUnionName", label: "所属工会", sortable: true },
|
||||
{ prop: "welfareUnitName", label: "所属单位", sortable: true },
|
||||
{ prop: "threeUnitName", label: "三级单位", sortable: true },
|
||||
{ prop: "remark", label: "备注", sortable: true }
|
||||
],
|
||||
|
||||
@@ -275,7 +305,9 @@ layout("/layouts/platform.html"){
|
||||
|
||||
welfareListUserDrawer: false,
|
||||
|
||||
showImportDialog: false
|
||||
showImportDialog: false,
|
||||
batchDeleteLoading: false,
|
||||
syncUnionLoading: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -286,6 +318,72 @@ layout("/layouts/platform.html"){
|
||||
})
|
||||
},
|
||||
|
||||
// 按当前搜索条件统计并删除名单人员,删除前必须由用户二次确认。
|
||||
async deleteSearchUsers() {
|
||||
this.$set(this, "batchDeleteLoading", true)
|
||||
try {
|
||||
const countResp = await this.$axios.post("/platform/welfare/list/mange/countByPageForm", {
|
||||
pageForm: JSON.stringify(this.pageForm)
|
||||
})
|
||||
if (countResp.code !== 0) {
|
||||
this.$message.error(countResp.msg)
|
||||
return
|
||||
}
|
||||
const userCount = countResp.data || 0
|
||||
if (userCount === 0) {
|
||||
this.$message.warning("当前搜索条件未查询到人员")
|
||||
return
|
||||
}
|
||||
const confirmed = await this.$confirm("当前搜索条件查询到" + userCount + "人,确认删除吗?该操作会同时删除这些人员的已选福利记录,且不可恢复。", "高风险操作", {
|
||||
confirmButtonText: "确认删除",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => true).catch(() => false)
|
||||
if (!confirmed) {
|
||||
return
|
||||
}
|
||||
const deleteResp = await this.$axios.post("/platform/welfare/list/mange/deleteByPageForm", {
|
||||
pageForm: JSON.stringify(this.pageForm)
|
||||
})
|
||||
if (deleteResp.code === 0) {
|
||||
this.$message.success(deleteResp.msg)
|
||||
this.doSearch()
|
||||
} else {
|
||||
this.$message.error(deleteResp.msg)
|
||||
}
|
||||
} catch (e) {
|
||||
this.$message.error("删除人员失败,请稍后重试")
|
||||
} finally {
|
||||
this.$set(this, "batchDeleteLoading", false)
|
||||
}
|
||||
},
|
||||
|
||||
// 同步当前福利项目名单人员的单位和工会快照,后端会再次校验选择时间。
|
||||
syncWelfareListUnitAndUnion() {
|
||||
this.$confirm("将按人员当前所属单位同步福利名单中的所属单位和所属工会,确认继续吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(async () => {
|
||||
this.$set(this, "syncUnionLoading", true)
|
||||
try {
|
||||
const resp = await this.$axios.post("/platform/welfare/list/mange/syncWelfareListUnitAndUnion", {
|
||||
projectId: this.pageForm.projectId
|
||||
})
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
this.doSearch()
|
||||
} else {
|
||||
this.$message.error(resp.msg)
|
||||
}
|
||||
} catch (e) {
|
||||
this.$message.error("同步工会失败,请稍后重试")
|
||||
} finally {
|
||||
this.$set(this, "syncUnionLoading", false)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
successImport() {
|
||||
this.doSearch()
|
||||
this.importDialog = false
|
||||
@@ -325,6 +423,32 @@ layout("/layouts/platform.html"){
|
||||
this.doSearch()
|
||||
})
|
||||
},
|
||||
// 根据已选所属单位查询直属三级单位,筛选项只保留当前所属单位范围内的数据。
|
||||
async unitIdsChange(unitIds) {
|
||||
this.$set(this.pageForm, "threeUnitIds", [])
|
||||
this.$set(this, "threeUnitOptions", [])
|
||||
if (!unitIds || unitIds.length === 0) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
const responses = await Promise.all(unitIds.map((unitId) => this.$axios.post("/platform/sys/unit/child", { pid: unitId })))
|
||||
const failedResponse = responses.find((res) => res.code !== 0)
|
||||
if (failedResponse) {
|
||||
this.$message.error(failedResponse.msg || "三级单位查询失败")
|
||||
return
|
||||
}
|
||||
const optionMap = {}
|
||||
responses.forEach((res) => {
|
||||
const options = res.data || []
|
||||
options.forEach((item) => {
|
||||
optionMap[item.id] = item
|
||||
})
|
||||
})
|
||||
this.$set(this, "threeUnitOptions", Object.keys(optionMap).map((id) => optionMap[id]))
|
||||
} catch (e) {
|
||||
this.$message.error("三级单位查询失败,请稍后重试")
|
||||
}
|
||||
},
|
||||
pageData() {
|
||||
this.tableLoading = true
|
||||
this.$axios
|
||||
|
||||
@@ -555,7 +555,7 @@ layout("/layouts/platform_tour_signup_h5.html"){
|
||||
}
|
||||
}).catch(() => {
|
||||
this.submitLoading = false
|
||||
vant.Toast("报名提交失败")
|
||||
// 接口失败提示由全局 Axios 拦截器统一展示,避免与名额已满等业务提示重复。
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ layout("/layouts/platform_h5.html"){
|
||||
</van-dropdown-menu>
|
||||
</van-sticky>
|
||||
|
||||
<table-list api="/platform/proposal/mine/pageData" :page_form.sync="pageForm" @ready="onReady" ref="tableListRef"
|
||||
<table-list api="/platform/proposal/mine/h5/pageData" :page_form.sync="pageForm" @ready="onReady" ref="tableListRef"
|
||||
title="name">
|
||||
<template v-slot="{index,row}">
|
||||
<table-column label="提案编号">{{row.code}}</table-column>
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ layout("/layouts/platform_h5.html"){
|
||||
</van-tabs>
|
||||
</van-sticky>
|
||||
|
||||
<table-list api="/platform/proposal/seconded/pageData" :page_form.sync="pageForm" @ready="onReady"
|
||||
<table-list api="/platform/proposal/seconded/h5/pageData" :page_form.sync="pageForm" @ready="onReady"
|
||||
ref="tableListRef"
|
||||
title="name">
|
||||
<template v-slot="{index,row}">
|
||||
|
||||
+13
-1
@@ -189,7 +189,19 @@ layout("/layouts/platform_h5.html"){
|
||||
this.$refs.proposalInfoRef.onOpen(row)
|
||||
},
|
||||
|
||||
onApproval(row) {
|
||||
async onApproval(row) {
|
||||
// 与 PC 端答复入口保持一致,确认已沟通后才允许进入答复表单。
|
||||
try {
|
||||
await this.$dialog.confirm({
|
||||
title: "提示",
|
||||
message: "是否已与提案代表进行充分沟通?",
|
||||
confirmButtonText: "是",
|
||||
cancelButtonText: "否"
|
||||
})
|
||||
} catch (error) {
|
||||
return
|
||||
}
|
||||
|
||||
this.loadCandidates(row.taskId)
|
||||
|
||||
this.showApprovalForm = true
|
||||
|
||||
Reference in New Issue
Block a user