Merge remote-tracking branch 'refs/remotes/origin/feature_主分支合并UI优化' into feature_教代会代表证

# Conflicts:
#	src/main/java/com/budwk/app/sys/controller/SysConfController.java
This commit is contained in:
2026-08-29 16:27:12 +08:00
577 changed files with 39023 additions and 8239 deletions
@@ -12,6 +12,8 @@ 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.dao.util.cri.Static;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
@@ -51,7 +53,8 @@ public class FlowTodoCenterController {
t.h5FormKey,
t.createdAt,
t.finishTime,
t.variable,
t.variable AS taskVariable,
ins.variable,
ins.state AS instanceState,
ins.id AS instanceId,
ins.businessNo,
@@ -66,7 +69,14 @@ public class FlowTodoCenterController {
$condition
""");
Cnd cnd = Cnd.NEW();
cnd.and("t.taskState", "=", ProcessTaskStateEnum.DOING.getCode());
// 普通待办仍按进行中任务查询;提案进入团长审核后,补充展示尚未附议的已废弃 second 任务。
SqlExpressionGroup todoTaskGroup = Cnd.exps("t.taskState", "=", ProcessTaskStateEnum.DOING.getCode());
SqlExpressionGroup proposalSecondGroup = Cnd.exps("t.taskState", "=", ProcessTaskStateEnum.ABANDON.getCode())
.and("t.taskName", "=", "second")
.and(new Static("EXISTS (SELECT 1 FROM proposal_second ps WHERE ps.proposalId = ins.businessNo AND ps.seconderId = ta.actorId AND ps.isAgree IS NULL)"))
.and(new Static("EXISTS (SELECT 1 FROM wf_process_task dt WHERE dt.processInstanceId = t.processInstanceId AND dt.taskName = 'delegation' AND dt.taskState = 10)"));
todoTaskGroup.or(proposalSecondGroup);
cnd.and(todoTaskGroup);
cnd.and("ta.actorId", "=", SecurityUtil.getUserId());
cnd.andEX("def.category", "=", category);
if (StrUtil.isNotBlank(searchKeyword)) {
@@ -96,7 +106,8 @@ public class FlowTodoCenterController {
t.h5FormKey,
t.createdAt,
t.finishTime,
t.variable,
t.variable AS taskVariable,
ins.variable,
ins.state AS instanceState,
ins.id AS instanceId,
ins.businessNo,
@@ -223,7 +234,27 @@ public class FlowTodoCenterController {
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = t.id
WHERE
ta.actorId = @userId
AND t.taskState = 10
AND (
t.taskState = 10
OR (
t.taskState = 99
AND t.taskName = 'second'
AND EXISTS (
SELECT 1
FROM proposal_second ps
WHERE ps.proposalId = (SELECT businessNo FROM wf_process_instance WHERE id = t.processInstanceId)
AND ps.seconderId = ta.actorId
AND ps.isAgree IS NULL
)
AND EXISTS (
SELECT 1
FROM wf_process_task dt
WHERE dt.processInstanceId = t.processInstanceId
AND dt.taskName = 'delegation'
AND dt.taskState = 10
)
)
)
""");
todoSql.setParam("userId", SecurityUtil.getUserId());
todoSql.setCallback(Sqls.callback.integer());
@@ -6,7 +6,9 @@ import lombok.Setter;
import org.nutz.dao.entity.annotation.Column;
import org.nutz.dao.entity.annotation.Comment;
import org.nutz.dao.entity.annotation.Id;
import org.nutz.dao.entity.annotation.Index;
import org.nutz.dao.entity.annotation.Table;
import org.nutz.dao.entity.annotation.TableIndexes;
import java.io.Serializable;
import java.util.Date;
@@ -22,6 +24,9 @@ import java.util.Date;
@Getter
@Setter
@Table("wf_process_instance")
@TableIndexes({
@Index(name = "INDEX_WF_PROCESS_INSTANCE_BUSINESS_NO", fields = {"businessNo"}, unique = false)
})
@Comment("流程实例")
public class ProcessInstance extends BaseModel {
@@ -6,7 +6,9 @@ import lombok.Setter;
import org.nutz.dao.entity.annotation.Column;
import org.nutz.dao.entity.annotation.Comment;
import org.nutz.dao.entity.annotation.Id;
import org.nutz.dao.entity.annotation.Index;
import org.nutz.dao.entity.annotation.Table;
import org.nutz.dao.entity.annotation.TableIndexes;
import java.io.Serializable;
import java.util.Date;
@@ -19,6 +21,9 @@ import java.util.Date;
@Getter
@Setter
@Table("wf_process_task")
@TableIndexes({
@Index(name = "INDEX_WF_PROCESS_TASK_INSTANCE_STATE", fields = {"processInstanceId", "taskState"}, unique = false)
})
@Comment("流程任务")
public class ProcessTask extends BaseModel {
@@ -11,6 +11,8 @@ import com.budwk.app.flow.engine.event.ProcessPublisher;
import com.budwk.app.flow.entity.ProcessInstance;
import com.budwk.app.flow.entity.ProcessTask;
import com.budwk.app.flow.enums.*;
import com.budwk.app.sys.models.Sys_unit;
import com.budwk.app.sys.views.View_user;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Chain;
@@ -22,6 +24,7 @@ import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import java.util.List;
import java.util.Optional;
@IocBean
public class FlowCommonService {
@@ -61,11 +64,13 @@ public class FlowCommonService {
args.put(FlowConst.SUBMIT_TYPE, submitType);
Sys_unit sysUnit = dao.fetch(Sys_unit.class, Cnd.where("id", "=", SecurityUtil.getUnitId()));
// 设置办理人信息到表单参数
args.put(FlowConst.TASK_FORM_DATA_PREFIX + "userName", SecurityUtil.getUserUsername());
args.put(FlowConst.TASK_FORM_DATA_PREFIX + "loginName", SecurityUtil.getUserLoginname());
args.put(FlowConst.TASK_FORM_DATA_PREFIX + "unitId", SecurityUtil.getUnitId());
args.put(FlowConst.TASK_FORM_DATA_PREFIX + "unitName", SecurityUtil.getUnitId());
args.put(FlowConst.TASK_FORM_DATA_PREFIX + "unitName", Optional.of(sysUnit).map(Sys_unit::getName).orElse(""));
args.put(FlowConst.TASK_FORM_DATA_PREFIX + "unionId", SecurityUtil.getUnionId());
if (ObjectUtil.equals(submitType, ProcessSubmitTypeEnum.ROLLBACK.getCode())) {
@@ -4,7 +4,6 @@ import cn.dev33.satoken.annotation.SaCheckPermission;
import com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.constant.RedisConstant;
import com.budwk.app.base.result.Result;
import com.budwk.app.base.utils.PageUtil;
import com.budwk.app.sys.models.Sys_config;
import com.budwk.app.sys.services.SysConfigService;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
@@ -140,18 +139,19 @@ public class SysConfController {
@At
@Ok("json:full")
@SaCheckPermission("sys.manager.conf")
public Object data(@Param("pageNumber") int pageNumber, @Param("pageSize") int pageSize, @Param("pageOrderName") String pageOrderName, @Param("pageOrderBy") String pageOrderBy) {
public Object data(@Param("pageNumber") int pageNumber,
@Param("pageSize") int pageSize,
@Param("pageOrderName") String pageOrderName,
@Param("pageOrderBy") String pageOrderBy,
@Param("configKey") String configKey) {
try {
ensureAppImageConfig("AppHomeImg", "PC首页轮播图");
ensureAppImageConfig("H5AppHomeImg", "移动端首页轮播图");
ensureAppImageConfig("AppFeaturedActivityImg", "精彩活动页顶部图片");
ensureAppImageConfig("AppFestivalBenefitImg", "节日福利页顶部图片");
ensureAppImageConfig("TeacherCongressCardBackImg", "教代会代表证背景图片");
Cnd cnd = Cnd.NEW();
if (Strings.isNotBlank(pageOrderName) && Strings.isNotBlank(pageOrderBy)) {
cnd.orderBy(pageOrderName, PageUtil.getOrder(pageOrderBy));
}
return Result.success().addData(sysConfigService.listPage(pageNumber, pageSize, cnd));
return Result.success().addData(sysConfigService.pageData(
pageNumber, pageSize, pageOrderName, pageOrderBy, configKey));
} catch (Exception e) {
return Result.error();
}
@@ -154,10 +154,15 @@ public class SysHomeController {
.and(Sys_menu::getPlatform, "=", platform)
);
List<Sys_menu> menus = sysUserService.getMenus(SecurityUtil.getUserId());
List<String> allMenuIds = menus.stream().map(Sys_menu::getId).toList();
Set<String> allMenuIds = menus.stream().map(Sys_menu::getId).collect(Collectors.toSet());
Set<String> allParentMenuIds = menus.stream()
.map(Sys_menu::getParentId)
.filter(StrUtil::isNotBlank)
.collect(Collectors.toSet());
List<Sys_menu> sysMenus = list.stream()
// 推荐项必须同时属于当前用户已授权菜单,避免首页展示无权限入口。
.filter(menu -> allMenuIds.contains(menu.getId()))
// 应用有已授权菜单,或根菜单自身有链接且已授权时,才允许在首页展示入口。
.filter(menu -> allParentMenuIds.contains(menu.getId())
|| (StrUtil.isNotBlank(menu.getHref()) && allMenuIds.contains(menu.getId())))
.sorted(Comparator.comparing(Sys_menu::getLocation, Comparator.nullsLast(Integer::compareTo))
.thenComparing(Sys_menu::getId))
.toList();
@@ -175,7 +180,7 @@ public class SysHomeController {
.and(Sys_menu::getPlatform, "=", platform)
);
List<Sys_menu> menus = sysUserService.getMenus(SecurityUtil.getUserId());
List<String> allMenuIds = menus.stream().map(Sys_menu::getId).toList();
Set<String> allMenuIds = menus.stream().map(Sys_menu::getId).collect(Collectors.toSet());
List<Sys_menu> sysMenus = list.stream()
// 推荐项必须同时属于当前用户已授权菜单,避免首页展示无权限入口。
.filter(menu -> allMenuIds.contains(menu.getId()))
@@ -419,14 +419,13 @@ public class SysRoleController {
public Object user(@Param("roleId") String roleId, @Param("searchName") String searchName, @Param("searchKeyword") String searchKeyword,
@Param("pageNumber") int pageNumber, @Param("pageSize") int pageSize, @Param("pageOrderName") String pageOrderName, @Param("pageOrderBy") String pageOrderBy) {
try {
Sql sql = Sqls.create("SELECT a.*,c.name as unitname FROM sys_user a,sys_user_role b,sys_unit c WHERE a.unitid=c.id and a.id=b.userId and b.roleId=@roleId $s $o");
Sql sql = Sqls.create("SELECT a.*,c.name as unitname FROM sys_user a,sys_user_role b,sys_unit c WHERE a.unitid=c.id and a.id=b.userId and enable='1' and b.roleId=@roleId $s $o");
sql.params().set("roleId", roleId);
if (Strings.isNotBlank(searchName) && Strings.isNotBlank(searchKeyword)) {
sql.vars().set("s", " and a." + searchName + " like '%" + searchKeyword + "%'");
}
if (Strings.isNotBlank(pageOrderName) && Strings.isNotBlank(pageOrderBy)) {
sql.vars().set("o", " order by a." + pageOrderName + " " + PageUtil.getOrder(pageOrderBy));
}
return Result.success().addData(sysUserService.listPage(pageNumber, pageSize, sql));
} catch (Exception e) {
@@ -554,20 +553,9 @@ public class SysRoleController {
@Ok("json:full")
@SaCheckLogin
public Result getRoleNames(){
Sql sql = Sqls.create("""
SELECT
GROUP_CONCAT(DISTINCT sr.`name`) roleNames
FROM
`sys_user_role` sur
LEFT JOIN sys_role sr ON sr.id = sur.roleId
WHERE
sur.userId = @userId
ORDER BY
sr.sort DESC
""").setParam("userId", SecurityUtil.getUserId());
sql.setCallback(Sqls.callback.map());
sysRoleService.dao().execute(sql);
return Result.success(sql.getResult());
// 首页身份与菜单、接口权限使用同一启用角色集合。
String roleNames = sysUserService.getEnabledRoleNames(SecurityUtil.getUserId());
return Result.success(NutMap.NEW().addv("roleNames", roleNames));
}
@@ -131,7 +131,8 @@ public class SysSignatureController {
@Aop(TransAop.READ_COMMITTED)
public Result update(@Param("file") TempFile tempFile) {
String url = sysFileService.uploadReturnUrl(SysFileEngineTypeEnum.MINIO.getValue(), tempFile);
Sys_user_signature sysUserSignature = dao.fetch(Sys_user_signature.class);
// 签字记录必须按当前登录用户读取,避免后续用户更新时覆盖其他用户的签字。
Sys_user_signature sysUserSignature = dao.fetch(Sys_user_signature.class, Cnd.where(Sys_user_signature::getUserId, "=", SecurityUtil.getUserId()));
if (ObjectUtil.isNull(sysUserSignature)) {
sysUserSignature = new Sys_user_signature();
}
@@ -456,10 +456,16 @@ public class SysUnionController {
unionCadre.setIsJoin(true);
dao.insert(unionCadre);
// 去走工作流
// 校级管理员新增普通干部时直接授权,不生成无实际审核意义的流程数据。
boolean isAdmin = AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name());
if (isAdmin) {
sysUnionService.assignBranchUnionRole(userId, role.getId(), unionId, List.of());
return Result.success();
}
// 非校级管理员仍按原业务发起基层干部授权审核流程。
Dict args = Dict.create();
args.set("submit", isAdmin ? "admin" : "branch");
args.set("submit", "branch");
args.set(FlowConst.SUBMIT_TYPE, ProcessSubmitTypeEnum.APPLY.getCode());
args.set(FlowConst.FORM_DATA, unionCadre);
@@ -470,20 +476,12 @@ public class SysUnionController {
flowEngine.executeProcessTask(task.getId(), SecurityUtil.getUserId(), args);
}
if (isAdmin) {
// 如果是管理员,直接加角色
sysRoleService.clear("sys_user_role", Cnd.where("roleId", "=", role.getId()).and("userId", "=", userId).and("unionId", "=", unionId));
sysRoleService.insert("sys_user_role", Chain.make("roleId", role.getId()).add("userId", userId).add("unionId", unionId));
sysRoleService.clearCache();
sysUserService.clearCache();
}
return Result.success();
}
/**
* 发起二级党委书记授权审批。一个审批申请可关联当前分工会下的多个单位。
* 审核通过后由流程拦截器按单位写入角色,避免影响普通分工会角色的授权方式
* 新增二级党委书记授权。校级管理员直接按单位授权,其他用户发起审批,
* 审核通过后由流程拦截器按单位写入角色。
*
* @param userId 人员ID
* @param unionId 分工会ID
@@ -536,11 +534,18 @@ public class SysUnionController {
unionCadre.setIsJoin(true);
dao.insert(unionCadre);
boolean isAdmin = AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name());
if (isAdmin) {
// 校级管理员直接按所选单位授权,不创建 JCGHWY 流程实例和审核任务。
sysUnionService.assignBranchUnionRole(userId, role.getId(), unionId, distinctUnitIds);
return Result.success();
}
// 非校级管理员保留原审批流程,并将所选单位随表单传给审核通过拦截器。
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("submit", "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);
@@ -624,22 +629,21 @@ public class SysUnionController {
}
/**
* 分页查询当前分工会的组成单位。
*
* @param pageForm 分页和查询参数;pageNumber 为页码,pageSize 为每页条数,searchKeyword 为单位编码或名称
* @param unionId 分工会ID,不能为空
* @return Resultdata 为 Paginationlist 是当前页单位列表,totalCount 是符合条件的单位总数
*/
@At
@ApiOperation("分工会组成单位分页")
@SaCheckPermission("sys.manager.union")
public Result branchUnionPartUnitPageData(PageForm pageForm, String unionId) {
Cnd cnd = Cnd.NEW();
cnd.and("unionId", "=", unionId);
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
SqlExpressionGroup seg = new SqlExpressionGroup();
seg.orLike("`name`", pageForm.getSearchKeyword());
seg.orLike("unitcode", pageForm.getSearchKeyword());
cnd.and(seg);
public Result branchUnionPartUnitPageData(@Valid PageForm pageForm, String unionId) {
if (StrUtil.isBlank(unionId)) {
return Result.error("分工会参数不能为空");
}
cnd.desc("unitcode");
List<Sys_unit> list = dao.query(Sys_unit.class, cnd);
return Result.success(list);
return Result.success(sysUnitService.pageBranchUnionPartUnits(pageForm, unionId));
}
@At
@@ -1,6 +1,7 @@
package com.budwk.app.sys.controller.v4;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result;
@@ -50,6 +51,7 @@ public class SysV4MsgController {
m.title,
m.content,
m.type,
m.sendTime,
r.isRead,
r.readTime
FROM
@@ -69,6 +71,10 @@ public class SysV4MsgController {
cnd.andEX("m.type", "=", type);
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
String keyword = "%" + pageForm.getSearchKeyword() + "%";
cnd.and(Cnd.exps("m.title", "like", keyword).or("m.content", "like", keyword));
}
cnd.desc("m.sendTime");
sql.setCondition(cnd);
@@ -211,6 +211,12 @@ public class Sys_user extends BaseModel implements Serializable {
@DataCenterColumn(name = "教职工类别码", key = "RYLX", dict = "USER_PERSON_TYPE")
private String personType;
@Column
@Comment("待确认状态:0不用确认、1待确认、2已确认")
@ColDefine(type = ColType.INT, width = 1)
@Default("0")
private Integer pendingConfirmStatus;
@Column
@Comment("编制类别码")
@ColDefine(type = ColType.VARCHAR, width = 30)
@@ -16,6 +16,15 @@ public class Sys_user_role {
@ColDefine(type = ColType.VARCHAR, width = 32)
private String userId;
/**
* 用户角色关系是否启用。普通角色默认启用,教代会届次切换时按届次统一刷新。
*/
@Column
@Comment("是否启用:1启用,0禁用")
@ColDefine(type = ColType.BOOLEAN)
@Default("1")
private Boolean enable = true;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
private String unitId;
@@ -1,5 +1,6 @@
package com.budwk.app.sys.services;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.sys.models.Sys_config;
import com.budwk.app.base.service.BaseService;
@@ -16,4 +17,17 @@ public interface SysConfigService extends BaseService<Sys_config> {
List<Sys_config> getAllList();
Sys_config getValueByKey(String key);
/**
* 分页查询系统参数,支持按参数名模糊查询和安全排序。
*
* @param pageNumber 页码
* @param pageSize 每页条数
* @param pageOrderName 排序字段
* @param pageOrderBy 排序方向
* @param configKey 参数名关键字
* @return 系统参数分页数据
*/
Pagination<Sys_config> pageData(int pageNumber, int pageSize, String pageOrderName,
String pageOrderBy, String configKey);
}
@@ -3,5 +3,18 @@ package com.budwk.app.sys.services;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.sys.models.Sys_union;
import java.util.List;
public interface SysUnionService extends BaseService<Sys_union> {
/**
* 直接分配分工会干部角色。普通干部传空单位集合时按分工会写入一条角色关系;
* 二级党委书记传单位集合时按单位分别写入角色关系。
*
* @param userId 用户ID
* @param roleId 角色ID
* @param unionId 分工会ID
* @param unitIds 授权单位ID集合,普通干部角色传空集合
*/
void assignBranchUnionRole(String userId, String roleId, String unionId, List<String> unitIds);
}
@@ -1,5 +1,7 @@
package com.budwk.app.sys.services;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.sys.models.Sys_unit;
@@ -7,6 +9,15 @@ import com.budwk.app.sys.models.Sys_unit;
* Created by wizzer on 2016/12/22.
*/
public interface SysUnitService extends BaseService<Sys_unit> {
/**
* 分页查询指定分工会的组成单位。
*
* @param pageForm 分页和查询参数;pageNumber 为页码,pageSize 为每页条数,searchKeyword 为单位编码或名称
* @param unionId 分工会ID,用于限制只查询当前分工会的组成单位
* @return 分页结果;list 为当前页单位数据,totalCount 为符合条件的单位总数
*/
Pagination<Sys_unit> pageBranchUnionPartUnits(PageForm pageForm, String unionId);
/**
* 保存单位
*
@@ -6,6 +6,7 @@ import com.budwk.app.base.exception.BaseException;
import com.budwk.app.base.exception.UnknownAccountException;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.sys.models.Sys_menu;
import com.budwk.app.sys.models.Sys_role;
import com.budwk.app.sys.models.Sys_user;
import javax.servlet.http.HttpServletRequest;
@@ -31,6 +32,21 @@ public interface SysUserService extends BaseService<Sys_user> {
*/
List<String> getRoleCodeList(Sys_user user);
/**
* 查询用户当前启用的角色关系对应角色,供菜单、接口权限和首页身份统一使用。
*
* @param userId 用户ID
* @return 当前启用且角色本身未禁用的角色列表
*/
List<Sys_role> getEnabledRoles(String userId);
/**
* 查询用户当前启用角色的显示名称。
*
* @param userId 用户ID
* @return 去重并按角色顺序排列的角色名称
*/
String getEnabledRoleNames(String userId);
/**
* 获取用户的菜单
@@ -1,15 +1,19 @@
package com.budwk.app.sys.services.impl;
import com.budwk.app.base.exception.BaseException;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.base.utils.PageUtil;
import com.budwk.app.sys.models.Sys_config;
import com.budwk.app.sys.services.SysConfigService;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import java.util.List;
import java.util.Set;
/**
* Created by wizzer on 2016/12/23.
@@ -32,4 +36,32 @@ public class SysConfigServiceImpl extends BaseServiceImpl<Sys_config> implements
}
return sys_config;
}
/**
* 分页查询系统参数。参数名使用模糊匹配,排序字段限定在列表可展示字段内,
* 防止未经校验的前端字段直接进入排序 SQL。
*
* @param pageNumber 页码
* @param pageSize 每页条数
* @param pageOrderName 排序字段
* @param pageOrderBy 排序方向
* @param configKey 参数名关键字
* @return 系统参数分页数据
*/
@Override
@SuppressWarnings("unchecked")
public Pagination<Sys_config> pageData(int pageNumber, int pageSize, String pageOrderName,
String pageOrderBy, String configKey) {
Cnd cnd = Cnd.NEW();
if (Strings.isNotBlank(configKey)) {
cnd.where().andLike("configKey", configKey.trim());
}
Set<String> sortableColumns = Set.of("configKey", "configValue", "note");
if (sortableColumns.contains(pageOrderName) && Strings.isNotBlank(pageOrderBy)) {
cnd.orderBy(pageOrderName, PageUtil.getOrder(pageOrderBy));
} else {
cnd.asc("configKey");
}
return listPage(pageNumber, pageSize, cnd);
}
}
@@ -23,9 +23,12 @@ import com.budwk.app.zhgh.democratic.proposal.models.ProposalConfig;
import com.budwk.app.zhgh.staffmanage.member.constant.MemberChangeOrigin;
import com.budwk.app.zhgh.staffmanage.member.constant.MemberChangeType;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
@@ -50,6 +53,10 @@ import java.util.stream.Collectors;
@IocBean
public class SysDataUserAllUpdateServiceImpl implements SysDataUserUpdateService {
private static final int BATCH_SIZE = 500;
/** 不需要人工确认。 */
private static final int PENDING_CONFIRM_STATUS_NONE = 0;
/** 数据源缺失,等待人工确认。 */
private static final int PENDING_CONFIRM_STATUS_PENDING = 1;
@Inject
private Dao dao;
@@ -154,6 +161,10 @@ public class SysDataUserAllUpdateServiceImpl implements SysDataUserUpdateService
for (Sys_user_source source : sources) {
Sys_user user = userMap.get(source.getLoginname());
source.setMember(null);
String unitId = source.getUnitId();
if (StringUtils.isNotBlank(unitId) && unitId.length() == 5) {
source.setUnitId(unitId.substring(0, 3));
}
// 创建用户对象
Sys_user u = new Sys_user();
@@ -174,7 +185,7 @@ public class SysDataUserAllUpdateServiceImpl implements SysDataUserUpdateService
* 全量更新已有用户时置空,避免 updateIgnoreNull 把已迁移的基金会员标识覆盖为非会员。
*/
u.setAidFundMember(null);
u.setPersonType(null);
needDoUpdateList.add(u);
}
@@ -346,6 +357,12 @@ public class SysDataUserAllUpdateServiceImpl implements SysDataUserUpdateService
RoleEventPublisher.broadcast(new RoleEventMsg(unitId, RoleConstant.PROPOSAL_BRANCH_SCHOOL_LEADER.name(), RoleEventMsg.RENEW_ROLE));
}
/*
* 所有异步用户更新完成后再校正待确认状态,避免主事务提前锁定 sys_user,
* 导致异步更新线程等待主事务释放行锁而形成相互等待。
*/
reconcilePendingConfirmStatus(updateParam.getPullTime());
long endTime = System.currentTimeMillis();
log.info("全量更新用户数据完成,耗时: {} 毫秒", (endTime - startTime));
@@ -356,6 +373,49 @@ public class SysDataUserAllUpdateServiceImpl implements SysDataUserUpdateService
+ "";
}
/**
* 根据指定批次的完整数据源校正系统用户待确认状态。
* 已人工确认且仍未重新出现的人员保持已确认状态,避免每次全量更新重复转为待确认。
*
* @param pullTime 本次全量数据的拉取时间
*/
private void reconcilePendingConfirmStatus(String pullTime) {
Sql resetStatusSql = Sqls.create("""
UPDATE sys_user userInfo
SET userInfo.pendingConfirmStatus = @noneStatus
WHERE userInfo.personType IN ('教职工', '劳务派遣人员')
AND userInfo.pendingConfirmStatus <> @noneStatus
AND EXISTS (
SELECT 1
FROM sys_user_source sourceInfo
WHERE sourceInfo.pullTime = @pullTime
AND sourceInfo.loginname = userInfo.loginname
AND sourceInfo.personType IN ('教职工', '劳务派遣人员')
)
""");
resetStatusSql.setParam("noneStatus", PENDING_CONFIRM_STATUS_NONE);
resetStatusSql.setParam("pullTime", pullTime);
dao.execute(resetStatusSql);
Sql pendingStatusSql = Sqls.create("""
UPDATE sys_user userInfo
SET userInfo.pendingConfirmStatus = @pendingStatus
WHERE userInfo.personType IN ('教职工', '劳务派遣人员')
AND IFNULL(userInfo.pendingConfirmStatus, @noneStatus) = @noneStatus
AND NOT EXISTS (
SELECT 1
FROM sys_user_source sourceInfo
WHERE sourceInfo.pullTime = @pullTime
AND sourceInfo.loginname = userInfo.loginname
AND sourceInfo.personType IN ('教职工', '劳务派遣人员')
)
""");
pendingStatusSql.setParam("pendingStatus", PENDING_CONFIRM_STATUS_PENDING);
pendingStatusSql.setParam("noneStatus", PENDING_CONFIRM_STATUS_NONE);
pendingStatusSql.setParam("pullTime", pullTime);
dao.execute(pendingStatusSql);
}
/**
* 构建变更的历史数据
*
@@ -2,13 +2,65 @@ package com.budwk.app.sys.services.impl;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.sys.models.Sys_union;
import com.budwk.app.sys.models.Sys_user_role;
import com.budwk.app.sys.services.SysRoleService;
import com.budwk.app.sys.services.SysUnionService;
import com.budwk.app.sys.services.SysUserService;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import java.util.List;
@IocBean(args = {"refer:dao"})
public class SysUnionServiceImpl extends BaseServiceImpl<Sys_union> implements SysUnionService {
@Inject
private SysRoleService sysRoleService;
@Inject
private SysUserService sysUserService;
public SysUnionServiceImpl(Dao dao) {
super(dao);
}
/**
* 直接分配分工会干部角色,并在授权完成后统一清理权限缓存。
* 普通角色按分工会授权一次,包含单位的角色按每个单位分别授权。
*
* @param userId 用户ID
* @param roleId 角色ID
* @param unionId 分工会ID
* @param unitIds 授权单位ID集合,普通干部角色传空集合
*/
@Override
public void assignBranchUnionRole(String userId, String roleId, String unionId, List<String> unitIds) {
// 先清理同一用户在当前分工会下的相同角色,保证重新授权后不存在重复关系。
dao().clear(Sys_user_role.class, Cnd.where(Sys_user_role::getRoleId, "=", roleId)
.and(Sys_user_role::getUserId, "=", userId)
.and(Sys_user_role::getUnionId, "=", unionId));
if (unitIds == null || unitIds.isEmpty()) {
Sys_user_role userRole = new Sys_user_role();
userRole.setRoleId(roleId);
userRole.setUserId(userId);
userRole.setUnionId(unionId);
dao().insert(userRole);
} else {
// 二级党委书记按选中的单位分别生成角色关系,供后续单位级权限判断使用。
for (String unitId : unitIds) {
Sys_user_role userRole = new Sys_user_role();
userRole.setRoleId(roleId);
userRole.setUserId(userId);
userRole.setUnionId(unionId);
userRole.setUnitId(unitId);
dao().insert(userRole);
}
}
sysRoleService.clearCache();
sysUserService.clearCache();
}
}
@@ -2,6 +2,8 @@ package com.budwk.app.sys.services.impl;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.constant.RedisConstant;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.sys.models.Sys_unit;
import com.budwk.app.sys.services.SysUnitService;
@@ -10,6 +12,7 @@ import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.util.cri.SqlExpressionGroup;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;
@@ -26,6 +29,22 @@ public class SysUnitServiceImpl extends BaseServiceImpl<Sys_unit> implements Sys
super(dao);
}
/**
* 按单位编码或名称筛选当前分工会的组成单位并按单位编码倒序分页
*/
@Override
public Pagination<Sys_unit> pageBranchUnionPartUnits(PageForm pageForm, String unionId) {
Cnd cnd = Cnd.where("unionId", "=", unionId);
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
SqlExpressionGroup keywordCondition = new SqlExpressionGroup();
keywordCondition.orLike("`name`", pageForm.getSearchKeyword());
keywordCondition.orLike("unitcode", pageForm.getSearchKeyword());
cnd.and(keywordCondition);
}
cnd.desc("unitcode");
return listPage(pageForm.getPageNumber(), pageForm.getPageSize(), Sys_unit.class, cnd);
}
/**
* 新增单位
*
@@ -67,19 +67,10 @@ public class SysUserServiceImpl extends BaseServiceImpl<Sys_user> implements Sys
@Override
@CacheResult(cacheKey = "${userId}_getPermissionList")
public List<String> getPermissionList(String userId) {
Sys_user user = this.fetch(userId);
if (user == null) {
return new ArrayList<>();
}
this.fetchLinks(user, "roles");
if (user.getRoles() == null) {
return new ArrayList<>();
}
List<String> permissionList = new ArrayList<String>();
for (Sys_role role : user.getRoles()) {
if (!role.isDisabled()) {
permissionList.addAll(sysRoleService.getPermissionList(role));
}
// Sa-Token接口权限只汇总启用的用户角色关系历史届次角色不再参与鉴权
for (Sys_role role : getEnabledRoles(userId)) {
permissionList.addAll(sysRoleService.getPermissionList(role));
}
// 追加public公共角色权限
permissionList.addAll(sysRoleService.getPermissionList(sysRoleService.fetch(Cnd.where("code", "=", "public"))));
@@ -94,12 +85,63 @@ public class SysUserServiceImpl extends BaseServiceImpl<Sys_user> implements Sys
*/
@CacheResult(cacheKey = "${user.id}_getRoleCodeList")
public List<String> getRoleCodeList(Sys_user user) {
dao().fetchLinks(user, "roles");
List<String> roleNameList = new ArrayList<String>();
for (Sys_role role : user.getRoles()) {
if (!role.isDisabled()) roleNameList.add(role.getCode());
if (user == null) {
return new ArrayList<>();
}
return roleNameList;
// AuthUtil.hasRole与Sa-Token角色判断共用启用角色集合
return getEnabledRoles(user.getId()).stream()
.map(Sys_role::getCode)
.filter(StrUtil::isNotBlank)
.distinct()
.toList();
}
/**
* 查询用户当前启用角色用户角色关系和角色本身必须同时处于启用状态
*
* @param userId 用户ID
* @return 当前启用角色列表
*/
@Override
@CacheResult(cacheKey = "${userId}_getEnabledRoles")
public List<Sys_role> getEnabledRoles(String userId) {
if (StrUtil.isBlank(userId) || fetch(userId) == null) {
return new ArrayList<>();
}
Sql sql = Sqls.create("""
SELECT DISTINCT
role.*
FROM
sys_role role
INNER JOIN sys_user_role userRole ON userRole.roleId = role.id
WHERE
userRole.userId = @userId
AND userRole.enable = @t
AND role.disabled = @f
ORDER BY role.sort DESC, role.id
""");
sql.setParam("userId", userId);
sql.setParam("t", true);
sql.setParam("f", false);
sql.setCallback(Sqls.callback.entities());
sql.setEntity(dao().getEntity(Sys_role.class));
dao().execute(sql);
return sql.getList(Sys_role.class);
}
/**
* 汇总用户当前启用角色名称首页展示与菜单及接口权限保持相同数据口径
*
* @param userId 用户ID
* @return 逗号分隔的角色名称
*/
@Override
public String getEnabledRoleNames(String userId) {
return getEnabledRoles(userId).stream()
.map(Sys_role::getName)
.filter(StrUtil::isNotBlank)
.distinct()
.collect(Collectors.joining(","));
}
/**
@@ -161,7 +203,8 @@ public class SysUserServiceImpl extends BaseServiceImpl<Sys_user> implements Sys
*/
// @CacheResult(cacheKey = "${userId}_getMenus")
public List<Sys_menu> getMenus(String userId) {
Sql sql = Sqls.create("select distinct a.* from sys_menu a,sys_role_menu b where a.id=b.menuId and " + " b.roleId in(select c.roleId from sys_user_role c,sys_role d where c.roleId=d.id and c.userId=@userId and d.disabled=@f) and a.disabled=@f and a.showit=@t and a.type='menu' order by a.location ASC,a.path asc");
// 菜单仅使用启用的用户角色关系普通角色与当前开启届次角色保持原有权限
Sql sql = Sqls.create("select distinct a.* from sys_menu a,sys_role_menu b where a.id=b.menuId and " + " b.roleId in(select c.roleId from sys_user_role c,sys_role d where c.roleId=d.id and c.userId=@userId and c.enable=@t and d.disabled=@f) and a.disabled=@f and a.showit=@t and a.type='menu' order by a.location ASC,a.path asc");
sql.params().set("userId", userId);
sql.params().set("f", false);
sql.params().set("t", true);
@@ -176,9 +219,10 @@ public class SysUserServiceImpl extends BaseServiceImpl<Sys_user> implements Sys
*/
// @CacheResult(cacheKey = "${userId}_getMenusAndButtons")
public List<Sys_menu> getMenusAndButtons(String userId) {
Sql sql = Sqls.create("select distinct a.* from sys_menu a,sys_role_menu b where a.id=b.menuId and " + " b.roleId in(select c.roleId from sys_user_role c,sys_role d where c.roleId=d.id and c.userId=@userId and d.disabled=@f) and a.disabled=@f order by a.location ASC,a.path asc");
Sql sql = Sqls.create("select distinct a.* from sys_menu a,sys_role_menu b where a.id=b.menuId and " + " b.roleId in(select c.roleId from sys_user_role c,sys_role d where c.roleId=d.id and c.userId=@userId and c.enable=@t and d.disabled=@f) and a.disabled=@f order by a.location ASC,a.path asc");
sql.params().set("userId", userId);
sql.params().set("f", false);
sql.params().set("t", true);
return sysMenuService.listEntity(sql);
}
@@ -195,9 +239,10 @@ public class SysUserServiceImpl extends BaseServiceImpl<Sys_user> implements Sys
*/
@CacheResult(cacheKey = "${userId}_getDatas")
public List<Sys_menu> getDatas(String userId) {
Sql sql = Sqls.create("select distinct a.* from sys_menu a,sys_role_menu b where a.id=b.menuId and " + " b.roleId in(select c.roleId from sys_user_role c,sys_role d where c.roleId=d.id and c.userId=@userId and d.disabled=@f) and a.disabled=@f and a.type='data' order by a.location ASC,a.path asc");
Sql sql = Sqls.create("select distinct a.* from sys_menu a,sys_role_menu b where a.id=b.menuId and " + " b.roleId in(select c.roleId from sys_user_role c,sys_role d where c.roleId=d.id and c.userId=@userId and c.enable=@t and d.disabled=@f) and a.disabled=@f and a.type='data' order by a.location ASC,a.path asc");
sql.params().set("userId", userId);
sql.params().set("f", false);
sql.params().set("t", true);
return sysMenuService.listEntity(sql);
}
@@ -232,9 +277,10 @@ public class SysUserServiceImpl extends BaseServiceImpl<Sys_user> implements Sys
*/
@CacheResult(cacheKey = "${userId}_${pid}_getRoleMenus")
public List<Sys_menu> getRoleMenus(String userId, String pid) {
Sql sql = Sqls.create("select distinct a.* from sys_menu a,sys_role_menu b where a.id=b.menuId and " + "$m and b.roleId in(select c.roleId from sys_user_role c,sys_role d where c.roleId=d.id and c.userId=@userId and d.disabled=@f) and a.disabled=@f order by a.location ASC,a.path asc");
Sql sql = Sqls.create("select distinct a.* from sys_menu a,sys_role_menu b where a.id=b.menuId and " + "$m and b.roleId in(select c.roleId from sys_user_role c,sys_role d where c.roleId=d.id and c.userId=@userId and c.enable=@t and d.disabled=@f) and a.disabled=@f order by a.location ASC,a.path asc");
sql.params().set("userId", userId);
sql.params().set("f", false);
sql.params().set("t", true);
if (Strings.isNotBlank(pid)) {
sql.vars().set("m", "a.parentId='" + pid + "'");
} else {
@@ -251,9 +297,10 @@ public class SysUserServiceImpl extends BaseServiceImpl<Sys_user> implements Sys
*/
@CacheResult(cacheKey = "${userId}_${pid}_hasChildren")
public boolean hasChildren(String userId, String pid) {
Sql sql = Sqls.create("select count(*) from sys_menu a,sys_role_menu b where a.id=b.menuId and " + "$m and b.roleId in(select c.roleId from sys_user_role c,sys_role d where c.roleId=d.id and c.userId=@userId and d.disabled=@f) and a.disabled=@f order by a.location ASC,a.path asc");
Sql sql = Sqls.create("select count(*) from sys_menu a,sys_role_menu b where a.id=b.menuId and " + "$m and b.roleId in(select c.roleId from sys_user_role c,sys_role d where c.roleId=d.id and c.userId=@userId and c.enable=@t and d.disabled=@f) and a.disabled=@f order by a.location ASC,a.path asc");
sql.params().set("userId", userId);
sql.params().set("f", false);
sql.params().set("t", true);
if (Strings.isNotBlank(pid)) {
sql.vars().set("m", "a.parentId='" + pid + "'");
} else {
@@ -387,6 +434,8 @@ public class SysUserServiceImpl extends BaseServiceImpl<Sys_user> implements Sys
user.setUnion(union);
}
user = this.fillMenu(user);
// 登录用户返回给前端的角色同样只保留启用关系避免历史届次角色继续触发页面 hasRole 判断
user.setRoles(this.getEnabledRoles(userId));
user.setPermissions(this.getPermissionList(userId));
return user;
}
@@ -196,6 +196,8 @@ public class ActivityCultureApplyActivityController {
}
private void cleanNewActivityData(ActivityTissue tissue) {
// 从模板另存或直接新建的活动必须进入活动列表不能继承来源活动的模板状态
tissue.setTemplateStatus(ActivityTissue.TEMPLATE_STATUS_UNSET);
tissue.setId(null);
tissue.setAuditId(null);
tissue.setState(null);
@@ -4,6 +4,7 @@ import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaMode;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.param.PageForm;
@@ -69,8 +70,9 @@ public class ActivityCultureInfoManageController {
public Result pageData(PageForm page, String year,
String name,
String unionId,
@Valid Integer activity_type) {
return Result.success(activityCultureService.pageData(page, year, name, unionId, activity_type));
@Valid Integer activity_type,
Integer templateStatus) {
return Result.success(activityCultureService.pageData(page, year, name, unionId, activity_type, templateStatus));
}
@At
@@ -90,47 +92,25 @@ public class ActivityCultureInfoManageController {
}
@At
@Aop(TransAop.READ_COMMITTED)
@SaCheckPermission("activity.culture.infoManage.school")
@SaCheckPermission(value = {"activity.culture.infoManage.school", "activity.culture.infoManage.union"}, mode = SaMode.OR)
public Result setTemplate(@Valid String id) {
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
return Result.error("无权操作");
}
ActivityTissue tissue = activityCultureService.fetch(id);
if (tissue == null) {
return Result.error("活动不存在");
String errorMessage = activityCultureService.setTemplate(id);
if (StrUtil.isNotBlank(errorMessage)) {
return Result.error(errorMessage);
}
if (tissue.getActivity_type() == null || tissue.getActivity_type() != 40001) {
return Result.error("仅校工会文化活动可设为模板");
}
Sys_home_template oldHomeTemplate = activityCultureService.dao().fetch(Sys_home_template.class, id);
Sys_home_template sysHomeTemplate = tissue.covertToSysHomeTemplate();
if (oldHomeTemplate != null) {
sysHomeTemplate.setTop(oldHomeTemplate.getTop());
sysHomeTemplate.setPush(oldHomeTemplate.getPush());
sysHomeTemplate.setSortNo(oldHomeTemplate.getSortNo());
if (oldHomeTemplate.getTemplateName() != null) {
sysHomeTemplate.setTemplateName(oldHomeTemplate.getTemplateName());
}
if (oldHomeTemplate.getTemplateIcon() != null) {
sysHomeTemplate.setTemplateIcon(oldHomeTemplate.getTemplateIcon());
}
if (oldHomeTemplate.getTemplateFile() != null) {
sysHomeTemplate.setTemplateFile(oldHomeTemplate.getTemplateFile());
}
}
activityCultureService.dao().insertOrUpdate(sysHomeTemplate);
return Result.success();
}
@At
@Aop(TransAop.READ_COMMITTED)
@SaCheckPermission("activity.culture.infoManage.school")
@SaCheckPermission(value = {"activity.culture.infoManage.school", "activity.culture.infoManage.union"}, mode = SaMode.OR)
public Result cancelTemplate(@Valid String id) {
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
return Result.error("无权操作");
}
activityCultureService.dao().delete(Sys_home_template.class, id);
activityCultureService.cancelTemplate(id);
return Result.success();
}
@@ -28,6 +28,12 @@ import java.util.List;
@Table("activity_tissue")
public class ActivityTissue extends BaseModel implements Serializable, SysHomeConvert {
/** 未设置为活动模板。 */
public static final int TEMPLATE_STATUS_UNSET = 0;
/** 已设置为活动模板。 */
public static final int TEMPLATE_STATUS_SET = 1;
@Column
@Name
@Comment("ID")
@@ -236,6 +242,12 @@ public class ActivityTissue extends BaseModel implements Serializable, SysHomeCo
@ColDefine(type = ColType.BOOLEAN)
private Boolean isUnseal;
@Column
@Comment("模板设置状态(0:未设置,1:已设置)")
@ColDefine(type = ColType.INT, width = 1)
@Default("0")
private Integer templateStatus;
@Column
@Comment("物品")
@ColDefine(type = ColType.MYSQL_JSON)
@@ -21,7 +21,33 @@ public interface ActivityCultureService extends BaseService<ActivityTissue> {
void doEditActivity(ActivityTissue tissue);
Object pageData(PageForm page, String year, String name, String unionId, Integer activity_type);
/**
* 分页查询文化活动
*
* @param page 分页参数
* @param year 年度
* @param name 活动名称
* @param unionId 工会ID
* @param activity_type 活动类型
* @param templateStatus 模板设置状态为空时不限制
* @return 文化活动分页数据
*/
Object pageData(PageForm page, String year, String name, String unionId, Integer activity_type, Integer templateStatus);
/**
* 将校工会或分工会文化活动设置为工作模板并同步模板状态
*
* @param id 活动ID
* @return 空字符串表示成功否则返回业务错误信息
*/
String setTemplate(String id);
/**
* 取消校工会或分工会文化活动模板并同步模板状态
*
* @param id 活动ID
*/
void cancelTemplate(String id);
NutMap findOne(String id);
@@ -6,6 +6,7 @@ import com.budwk.app.base.model.Audit;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.sys.models.Sys_home_activity;
import com.budwk.app.sys.models.Sys_home_template;
import com.budwk.app.web.commons.auth.utils.AuthUtil;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.activity.basic.service.ActivityBasicScopeService;
@@ -14,6 +15,8 @@ import com.budwk.app.zhgh.activity.culture.models.ActivityTissuePerson;
import com.budwk.app.zhgh.activity.culture.service.ActivityCultureService;
import com.budwk.app.zhgh.club.model.SysClub;
import com.budwk.app.zhgh.club.service.SysClubService;
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;
@@ -21,6 +24,7 @@ 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.ioc.aop.Aop;
import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
@@ -85,7 +89,7 @@ public class ActivityCultureServiceImpl extends BaseServiceImpl<ActivityTissue>
}
@Override
public Object pageData(PageForm page, String year, String name, String unionId, Integer activity_type) {
public Object pageData(PageForm page, String year, String name, String unionId, Integer activity_type, Integer templateStatus) {
Cnd cnd = Cnd.NEW();
Sql sql = Sqls.create("""
@@ -110,7 +114,7 @@ public class ActivityCultureServiceImpl extends BaseServiceImpl<ActivityTissue>
t.variable taskVariable,
IF((SELECT taskName FROM wf_process_task tt WHERE tt.id = t.taskParentId) = 'startTask', 1, 0) canRevoke,
(select MAX(id) from wf_process_task where processInstanceId = ins.id and taskName = 'startTask') AS startTaskId,
IF(sht.id IS NULL, 0, 1) AS isTemplate
tissue.templateStatus AS isTemplate
FROM
activity_tissue tissue
LEFT JOIN sys_union uni ON uni.id = tissue.unionId
@@ -119,7 +123,6 @@ public class ActivityCultureServiceImpl extends BaseServiceImpl<ActivityTissue>
LEFT JOIN `wf_process_instance` ins ON ins.businessNo = tissue.id
LEFT JOIN wf_process_task t ON t.processInstanceId = ins.id AND t.taskState = 10
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = t.id
LEFT JOIN sys_home_template sht ON sht.id = tissue.id
$condition
""");
@@ -127,6 +130,8 @@ public class ActivityCultureServiceImpl extends BaseServiceImpl<ActivityTissue>
cnd.andEX("tissue.projectTypeCode", "!=", "50004");
cnd.andEX("tissue.unionId", "=", unionId);
cnd.andEX("tissue.activity_type", "=", activity_type);
// 校工会管理页按页签传入模板状态其他文化活动页面不传时保持原查询范围
cnd.andEX("tissue.templateStatus", "=", templateStatus);
cnd.groupBy("tissue.id");
if (Strings.isNotBlank(name)) {
@@ -159,6 +164,61 @@ public class ActivityCultureServiceImpl extends BaseServiceImpl<ActivityTissue>
return this.listPageMap(page.getPageNumber(), page.getPageSize(), sql);
}
/**
* 将校工会或分工会文化活动转换为工作模板并保留模板中心已维护的展示配置
*
* @param id 活动ID
* @return 空字符串表示成功否则返回业务错误信息
*/
@Override
@Aop(TransAop.READ_COMMITTED)
public String setTemplate(String id) {
ActivityTissue tissue = fetch(id);
if (tissue == null) {
return "活动不存在";
}
if (tissue.getActivity_type() == null || !List.of(40001, 40002).contains(tissue.getActivity_type())) {
return "仅校工会或分工会文化活动可设为模板";
}
Sys_home_template oldHomeTemplate = dao().fetch(Sys_home_template.class, id);
Sys_home_template sysHomeTemplate = tissue.covertToSysHomeTemplate();
if (oldHomeTemplate != null) {
// 重复设置时保留模板中心人工配置避免覆盖置顶推送排序及模板素材
sysHomeTemplate.setTop(oldHomeTemplate.getTop());
sysHomeTemplate.setPush(oldHomeTemplate.getPush());
sysHomeTemplate.setSortNo(oldHomeTemplate.getSortNo());
if (oldHomeTemplate.getTemplateName() != null) {
sysHomeTemplate.setTemplateName(oldHomeTemplate.getTemplateName());
}
if (oldHomeTemplate.getTemplateIcon() != null) {
sysHomeTemplate.setTemplateIcon(oldHomeTemplate.getTemplateIcon());
}
if (oldHomeTemplate.getTemplateFile() != null) {
sysHomeTemplate.setTemplateFile(oldHomeTemplate.getTemplateFile());
}
}
dao().insertOrUpdate(sysHomeTemplate);
dao().update(ActivityTissue.class,
Chain.make("templateStatus", ActivityTissue.TEMPLATE_STATUS_SET),
Cnd.where("id", "=", id));
return "";
}
/**
* 删除模板中心记录并将文化活动恢复为未设置模板状态
*
* @param id 活动ID
*/
@Override
@Aop(TransAop.READ_COMMITTED)
public void cancelTemplate(String id) {
dao().delete(Sys_home_template.class, id);
dao().update(ActivityTissue.class,
Chain.make("templateStatus", ActivityTissue.TEMPLATE_STATUS_UNSET),
Cnd.where("id", "=", id));
}
@Override
public NutMap findOne(String id) {
Sql sql = Sqls.create("""
@@ -87,6 +87,9 @@ public class FamilyActivityApplyController {
Cnd cnd = Cnd.NEW();
cnd.andEX("id", "=", id);
cnd.andEX("`year`", "=", year);
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
cnd.and("activityName", "like", "%" + pageForm.getSearchKeyword().trim() + "%");
}
//查询报名中
if (activityType == 2) {
cnd.and(new Static("now() < activitySignUpEndTime"));
@@ -117,6 +120,7 @@ public class FamilyActivityApplyController {
@Param(value = "courseTypeId") String courseTypeId,
@Param(value = "activityId") String activityId,
@Param(value = "assortTypes") String[] assortTypes,
@Param(value = "searchKeyword") String searchKeyword,
@Param(value = "dataType") String dataType) {
FamilyActivity activity = dao.fetch(FamilyActivity.class, activityId);
Sql sql = Sqls.create("""
@@ -131,6 +135,9 @@ public class FamilyActivityApplyController {
Cnd cnd = Cnd.NEW();
cnd.andEX("type.id", "=", courseTypeId);
cnd.and("tsuc.activityId", "=", activityId);
if (StrUtil.isNotBlank(searchKeyword)) {
cnd.and("tsuc.courseName", "like", "%" + searchKeyword.trim() + "%");
}
if(Lang.isNotEmpty(assortTypes)) {
cnd.and("tsuc.assort", "in", assortTypes);
}
@@ -6,7 +6,6 @@ import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result;
import com.budwk.app.sys.models.Sys_home_activity;
@@ -68,20 +67,15 @@ public class FamilyActivityController {
@SaCheckPermission("family.manage")
public Result pageData(PageForm pageForm,
@Param(value = "year") Integer year,
@Param(value = "activityName") String activityName) {
@Param(value = "activityName") String activityName,
@Param(value = "templateStatus") Integer templateStatus) {
Cnd cnd = Cnd.NEW();
cnd.andEX("year", "=", year);
cnd.and(Cnd.likeEX("activityName", activityName));
// 有模板管理角色时前端按页签传入状态普通用户不传时保持原列表范围
cnd.andEX("templateStatus", "=", templateStatus);
cnd.orderBy("createdAt", "desc");
Pagination<FamilyActivity> pagination = familyActivityManageService.pageData(pageForm, cnd);
List<FamilyActivity> list = pagination.getList(FamilyActivity.class);
if (list != null && !list.isEmpty()) {
List<String> ids = list.stream().map(FamilyActivity::getId).toList();
List<Sys_home_template> templateList = dao.query(Sys_home_template.class, Cnd.where("id", "in", ids));
List<String> templateIds = templateList.stream().map(Sys_home_template::getId).toList();
list.forEach(activity -> activity.setIsTemplate(templateIds.contains(activity.getId())));
}
return Result.success().addData(pagination);
return Result.success().addData(familyActivityManageService.pageData(pageForm, cnd));
}
@At
@@ -91,27 +85,9 @@ public class FamilyActivityController {
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
return Result.error("无权操作");
}
FamilyActivity activity = familyActivityManageService.fetch(id);
if (activity == null) {
if (!familyActivityManageService.setTemplate(id)) {
return Result.error("活动不存在");
}
Sys_home_template oldHomeTemplate = dao.fetch(Sys_home_template.class, id);
Sys_home_template sysHomeTemplate = activity.covertToSysHomeTemplate();
if (oldHomeTemplate != null) {
sysHomeTemplate.setTop(oldHomeTemplate.getTop());
sysHomeTemplate.setPush(oldHomeTemplate.getPush());
sysHomeTemplate.setSortNo(oldHomeTemplate.getSortNo());
if (oldHomeTemplate.getTemplateName() != null) {
sysHomeTemplate.setTemplateName(oldHomeTemplate.getTemplateName());
}
if (oldHomeTemplate.getTemplateIcon() != null) {
sysHomeTemplate.setTemplateIcon(oldHomeTemplate.getTemplateIcon());
}
if (oldHomeTemplate.getTemplateFile() != null) {
sysHomeTemplate.setTemplateFile(oldHomeTemplate.getTemplateFile());
}
}
dao.insertOrUpdate(sysHomeTemplate);
return Result.success();
}
@@ -122,7 +98,7 @@ public class FamilyActivityController {
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
return Result.error("无权操作");
}
dao.delete(Sys_home_template.class, id);
familyActivityManageService.cancelTemplate(id);
return Result.success();
}
@@ -224,6 +200,8 @@ public class FamilyActivityController {
if (activity == null) {
return;
}
// 直接新建或从模板另存时明确重置状态防止前端历史字段被带回
activity.setTemplateStatus(FamilyActivity.TEMPLATE_STATUS_UNSET);
activity.setId(null);
activity.setIsTemplate(false);
activity.setCreatedBy(null);
@@ -25,6 +25,12 @@ import java.util.List;
@EqualsAndHashCode(callSuper = false)
public class FamilyActivity extends BaseModel implements Serializable, SysHomeConvert {
/** 未设置为活动模板。 */
public static final int TEMPLATE_STATUS_UNSET = 0;
/** 已设置为活动模板。 */
public static final int TEMPLATE_STATUS_SET = 1;
@Name
@PrevInsert(uu32 = true)
private String id;
@@ -114,6 +120,12 @@ public class FamilyActivity extends BaseModel implements Serializable, SysHomeCo
private Boolean isTemplate;
@Column
@Comment("模板设置状态(0:未设置,1:已设置)")
@ColDefine(type = ColType.INT, width = 1)
@Default("0")
private Integer templateStatus;
@Column
@Comment("活动类型")
@ColDefine(type = ColType.VARCHAR, width = 20)
@@ -50,6 +50,21 @@ public interface FamilyActivityService extends BaseService<FamilyActivity> {
*/
Pagination pageData(PageForm pageForm, Cnd cnd);
/**
* 将亲子活动设置为工作模板并同步模板状态
*
* @param id 活动ID
* @return true 表示活动存在且设置成功false 表示活动不存在
*/
boolean setTemplate(String id);
/**
* 取消亲子活动模板并同步模板状态
*
* @param id 活动ID
*/
void cancelTemplate(String id);
/**
* 手机端分页查询
@@ -6,6 +6,7 @@ import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.sys.models.Sys_home_activity;
import com.budwk.app.sys.models.Sys_home_template;
import com.budwk.app.sys.views.View_user;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.activity.family.models.*;
@@ -48,7 +49,8 @@ public class FamilyActivityServiceImpl extends BaseServiceImpl<FamilyActivity> i
@Override
@Aop(TransAop.READ_COMMITTED)
public void add(FamilyActivity activity, FamilyCourse course) {
// 新建活动包括从模板另存统一归入活动列表不能继承来源活动的模板状态
activity.setTemplateStatus(FamilyActivity.TEMPLATE_STATUS_UNSET);
dao().insert(activity);
//插入类型限制
@@ -215,6 +217,57 @@ public class FamilyActivityServiceImpl extends BaseServiceImpl<FamilyActivity> i
return pagination;
}
/**
* 将亲子活动转换为工作模板并保留模板中心已维护的展示配置
*
* @param id 活动ID
* @return true 表示活动存在且设置成功false 表示活动不存在
*/
@Override
@Aop(TransAop.READ_COMMITTED)
public boolean setTemplate(String id) {
FamilyActivity activity = fetch(id);
if (activity == null) {
return false;
}
Sys_home_template oldHomeTemplate = dao().fetch(Sys_home_template.class, id);
Sys_home_template sysHomeTemplate = activity.covertToSysHomeTemplate();
if (oldHomeTemplate != null) {
// 重复设置时保留模板中心人工配置避免覆盖置顶推送排序及模板素材
sysHomeTemplate.setTop(oldHomeTemplate.getTop());
sysHomeTemplate.setPush(oldHomeTemplate.getPush());
sysHomeTemplate.setSortNo(oldHomeTemplate.getSortNo());
if (oldHomeTemplate.getTemplateName() != null) {
sysHomeTemplate.setTemplateName(oldHomeTemplate.getTemplateName());
}
if (oldHomeTemplate.getTemplateIcon() != null) {
sysHomeTemplate.setTemplateIcon(oldHomeTemplate.getTemplateIcon());
}
if (oldHomeTemplate.getTemplateFile() != null) {
sysHomeTemplate.setTemplateFile(oldHomeTemplate.getTemplateFile());
}
}
dao().insertOrUpdate(sysHomeTemplate);
dao().update(FamilyActivity.class,
Chain.make("templateStatus", FamilyActivity.TEMPLATE_STATUS_SET),
Cnd.where("id", "=", id));
return true;
}
/**
* 删除模板中心记录并将亲子活动恢复为未设置模板状态
*
* @param id 活动ID
*/
@Override
@Aop(TransAop.READ_COMMITTED)
public void cancelTemplate(String id) {
dao().delete(Sys_home_template.class, id);
dao().update(FamilyActivity.class,
Chain.make("templateStatus", FamilyActivity.TEMPLATE_STATUS_UNSET),
Cnd.where("id", "=", id));
}
@Override
public Pagination mPageData(PageForm pageForm, Integer year, int activityStatus, Integer activityType) {
Cnd cnd = Cnd.NEW();
@@ -65,7 +65,8 @@ public class ActivitySportsInfoManageController {
@Param(value = "gameStyle") String gameStyle,
@Param(value = "query") String query,
@Param(value = "activityId") String activityId,
@Param(value = "activityLevel") String activityLevel) {
@Param(value = "activityLevel") String activityLevel,
@Param(value = "templateStatus") Integer templateStatus) {
Cnd cnd = Cnd.NEW();
Sql sql = Sqls.create("""
SELECT
@@ -91,13 +92,12 @@ public class ActivitySportsInfoManageController {
school.activityCode,
school.foundDate,
school.applyType,
IF(sht.id IS NULL, 0, 1) isTemplate,
school.templateStatus isTemplate,
(SELECT COUNT(1) FROM activity_school_apply asa WHERE asa.activityId = school.id and status=2) applyNum
FROM
activity_school school
LEFT JOIN activity_basic_settings ba ON ba.`code` = school.activityLevel
LEFT JOIN sys_union un ON un.id = school.belongUnionId
LEFT JOIN sys_home_template sht ON sht.id = school.id
$condition
""");
@@ -121,6 +121,8 @@ public class ActivitySportsInfoManageController {
cnd.andEX("school.activityLevel", "=", activityLevel);
cnd.andEX("school.gameStyle", "=", gameStyle);
// 管理员页签传入模板状态未展示页签的用户不传该参数继续查询原完整列表
cnd.andEX("school.templateStatus", "=", templateStatus);
cnd.andEX("YEAR(school.applyStartTime)", "=", year);
if (StrUtil.isNotBlank(name)) {
cnd.and(Cnd.likeEX("school.name", name));
@@ -141,27 +143,9 @@ public class ActivitySportsInfoManageController {
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
return Result.error("无权操作");
}
ActivitySchool activitySchool = activitySportsService.fetch(id);
if (activitySchool == null) {
if (!activitySportsService.setTemplate(id)) {
return Result.error("活动不存在");
}
Sys_home_template oldHomeTemplate = dao.fetch(Sys_home_template.class, id);
Sys_home_template sysHomeTemplate = activitySchool.covertToSysHomeTemplate();
if (oldHomeTemplate != null) {
sysHomeTemplate.setTop(oldHomeTemplate.getTop());
sysHomeTemplate.setPush(oldHomeTemplate.getPush());
sysHomeTemplate.setSortNo(oldHomeTemplate.getSortNo());
if (oldHomeTemplate.getTemplateName() != null) {
sysHomeTemplate.setTemplateName(oldHomeTemplate.getTemplateName());
}
if (oldHomeTemplate.getTemplateIcon() != null) {
sysHomeTemplate.setTemplateIcon(oldHomeTemplate.getTemplateIcon());
}
if (oldHomeTemplate.getTemplateFile() != null) {
sysHomeTemplate.setTemplateFile(oldHomeTemplate.getTemplateFile());
}
}
dao.insertOrUpdate(sysHomeTemplate);
return Result.success();
}
@@ -172,7 +156,7 @@ public class ActivitySportsInfoManageController {
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
return Result.error("无权操作");
}
dao.delete(Sys_home_template.class, id);
activitySportsService.cancelTemplate(id);
return Result.success();
}
@@ -64,8 +64,8 @@ public class H5ActivitySportsApplyUserController {
@At
@SaCheckPermission("h5.activity.sports.applyUser")
public Result activityData(Integer year, Integer isActivity, Integer applyStatus) {
return Result.success(activitySportsApplyUserService.activityData(year, isActivity, applyStatus));
public Result activityData(Integer year, Integer isActivity, Integer applyStatus, String searchKeyword) {
return Result.success(activitySportsApplyUserService.activityData(year, isActivity, applyStatus, searchKeyword));
}
@@ -171,6 +171,18 @@ public class ActivitySchool extends BaseModel implements Serializable , SysHomeC
@ColDefine(type = ColType.BOOLEAN)
private Integer isSave;
/** 未设置为工作模板。 */
public static final int TEMPLATE_STATUS_UNSET = 0;
/** 已设置为工作模板。 */
public static final int TEMPLATE_STATUS_SET = 1;
@Column
@Comment("模板设置状态(0:未设置 1:已设置)")
@ColDefine(type = ColType.INT, width = 1)
@Default("0")
private Integer templateStatus;
@Column
@Comment("小程序活动封面")
@ColDefine(type = ColType.VARCHAR,width = 100)
@@ -18,6 +18,7 @@ public class ActivitySportsApplyUserPageParam extends PageForm {
private String applyType;
private String isAudit;
private String groupName;
private String searchKeyword;
private String activityId;
private String eventId;
private String year;
@@ -19,6 +19,17 @@ public interface ActivitySportsApplyUserService extends BaseService<ActivityScho
Pagination activityData(Integer year, Integer isActivity,Integer applyStatus);
/**
* 根据年份活动状态报名状态和活动名称查询体育活动
*
* @param year 活动年份
* @param isActivity 活动状态
* @param applyStatus 当前用户报名状态
* @param searchKeyword 活动名称模糊查询关键词
* @return 体育活动分页数据
*/
Pagination activityData(Integer year, Integer isActivity, Integer applyStatus, String searchKeyword);
List<NutMap> getEvents(String activityId);
Object getUnionCoachLeaderHead(String activityId,String unionId);
@@ -18,5 +18,20 @@ public interface ActivitySportsService extends BaseService<ActivitySchool> {
void doDelete(String id);
/**
* 将体育活动设置为工作模板并同步活动表中的模板设置状态
*
* @param id 体育活动ID
* @return 活动存在且设置成功时返回 true活动不存在时返回 false
*/
boolean setTemplate(String id);
/**
* 取消体育活动的工作模板并同步活动表中的模板设置状态
*
* @param id 体育活动ID
*/
void cancelTemplate(String id);
void exportXlsx(String id, String unionId, HttpServletResponse response);
}
@@ -122,6 +122,9 @@ public class ActivitySportsApplyUserServiceImpl extends BaseServiceImpl<Activity
cnd.and(new Static("(SELECT COUNT(1) FROM activity_school_apply WHERE eventId = ase.eventId AND activityId = ase.activityId AND userId='%s')%s0".formatted(SecurityUtil.getUserId(), (pageParam.getIsAudit().equals("true") ? ">" : "="))));
}
cnd.and("ase.activityId", "=", pageParam.getActivityId());
if (StrUtil.isNotBlank(pageParam.getSearchKeyword())) {
cnd.and("eve.allName", "like", "%" + pageParam.getSearchKeyword().trim() + "%");
}
cnd.andEX("ase.eventId", "=", pageParam.getEventId());
cnd.andEX("YEAR(school.applyStartTime)", "=", pageParam.getYear());
@@ -144,6 +147,20 @@ public class ActivitySportsApplyUserServiceImpl extends BaseServiceImpl<Activity
@Override
public Pagination activityData(Integer year, Integer isActivity, Integer applyStatus) {
return activityData(year, isActivity, applyStatus, null);
}
/**
* 根据筛选条件及活动名称查询当前用户可见的体育活动
*
* @param year 活动年份
* @param isActivity 活动状态
* @param applyStatus 当前用户报名状态
* @param searchKeyword 活动名称模糊查询关键词
* @return 体育活动分页数据
*/
@Override
public Pagination activityData(Integer year, Integer isActivity, Integer applyStatus, String searchKeyword) {
Sql sql = Sqls.create("""
SELECT
@@ -183,6 +200,10 @@ public class ActivitySportsApplyUserServiceImpl extends BaseServiceImpl<Activity
cnd.and("school.isSave", "!=", true);
if (Lang.isNotEmpty(searchKeyword)) {
cnd.and("school.NAME", "like", "%" + searchKeyword.trim() + "%");
}
//查询报名中
if (isActivity == 2) {
cnd.and(new Static("now() >applyStartTime and now() < applyEndTime"));
@@ -8,6 +8,7 @@ import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.base.utils.CommonDownloadUtil;
import com.budwk.app.base.utils.DateUtil;
import com.budwk.app.sys.models.Sys_home_activity;
import com.budwk.app.sys.models.Sys_home_template;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.activity.basic.models.ActivityBasicUnit;
import com.budwk.app.zhgh.activity.basic.models.ActivityBasicUnion;
@@ -61,6 +62,8 @@ public class ActivitySportsServiceImpl extends BaseServiceImpl<ActivitySchool> i
}
activitySchool.setFoundDate(DateUtil.getDate());
activitySchool.setClose(false);
// 新建活动只能从未设置模板状态开始防止客户端提交模板状态造成数据不一致
activitySchool.setTemplateStatus(ActivitySchool.TEMPLATE_STATUS_UNSET);
ActivitySchool school = insert(activitySchool);
addTeam(school.getId(), events);
@@ -190,6 +193,59 @@ public class ActivitySportsServiceImpl extends BaseServiceImpl<ActivitySchool> i
dao().delete(Sys_home_activity.class, id);
}
/**
* 将活动内容转换为首页工作模板并在同一事务内更新活动模板状态
* 重复设置时保留管理员在工作模板管理中维护的名称图标文件及排序配置
*
* @param id 体育活动ID
* @return 活动存在且设置成功时返回 true否则返回 false
*/
@Override
@Aop(TransAop.READ_COMMITTED)
public boolean setTemplate(String id) {
ActivitySchool activitySchool = fetch(id);
if (activitySchool == null) {
return false;
}
Sys_home_template oldHomeTemplate = dao().fetch(Sys_home_template.class, id);
Sys_home_template sysHomeTemplate = activitySchool.covertToSysHomeTemplate();
if (oldHomeTemplate != null) {
// 模板业务数据随活动刷新模板管理页面维护的展示配置继续沿用
sysHomeTemplate.setTop(oldHomeTemplate.getTop());
sysHomeTemplate.setPush(oldHomeTemplate.getPush());
sysHomeTemplate.setSortNo(oldHomeTemplate.getSortNo());
if (oldHomeTemplate.getTemplateName() != null) {
sysHomeTemplate.setTemplateName(oldHomeTemplate.getTemplateName());
}
if (oldHomeTemplate.getTemplateIcon() != null) {
sysHomeTemplate.setTemplateIcon(oldHomeTemplate.getTemplateIcon());
}
if (oldHomeTemplate.getTemplateFile() != null) {
sysHomeTemplate.setTemplateFile(oldHomeTemplate.getTemplateFile());
}
}
dao().insertOrUpdate(sysHomeTemplate);
dao().update(ActivitySchool.class,
Chain.make("templateStatus", ActivitySchool.TEMPLATE_STATUS_SET),
Cnd.where("id", "=", id));
return true;
}
/**
* 删除首页工作模板并在同一事务内将活动恢复为未设置模板状态
*
* @param id 体育活动ID
*/
@Override
@Aop(TransAop.READ_COMMITTED)
public void cancelTemplate(String id) {
dao().delete(Sys_home_template.class, id);
dao().update(ActivitySchool.class,
Chain.make("templateStatus", ActivitySchool.TEMPLATE_STATUS_UNSET),
Cnd.where("id", "=", id));
}
@Override
public void exportXlsx(String id, String unionId, HttpServletResponse response) {
try {
@@ -93,6 +93,9 @@ public class TrainSignUpApplyController {
Cnd cnd = Cnd.NEW();
cnd.andEX("id", "=", id);
cnd.andEX("`year`", "=", year);
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
cnd.and(Cnd.likeEX("activityName", pageForm.getSearchKeyword()));
}
//查询报名中
if (activityType == 2) {
cnd.and(new Static("now() < activitySignUpEndTime"));
@@ -123,6 +126,7 @@ public class TrainSignUpApplyController {
@Param(value = "courseTypeId") String courseTypeId,
@Param(value = "activityId") String activityId,
@Param(value = "assortTypes") String[] assortTypes,
@Param(value = "searchKeyword") String searchKeyword,
@Param(value = "dataType") String dataType) {
Sql sql = Sqls.create("""
SELECT
@@ -156,6 +160,9 @@ public class TrainSignUpApplyController {
Cnd cnd = Cnd.NEW();
cnd.andEX("type.id", "=", courseTypeId);
cnd.and("tsuc.activityId", "=", activityId);
if (StrUtil.isNotBlank(searchKeyword)) {
cnd.and("tsuc.courseName", "like", "%" + searchKeyword.trim() + "%");
}
if (Lang.isNotEmpty(assortTypes)) {
cnd.and("tsuc.assort", "in", assortTypes);
@@ -6,7 +6,6 @@ import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result;
import com.budwk.app.flow.entity.ProcessInstance;
@@ -72,20 +71,15 @@ public class TrainSignUpManageController {
@SaCheckPermission("trainSignUp.manage")
public Result pageData(PageForm pageForm,
@Param(value = "year") Integer year,
@Param(value = "activityName") String activityName) {
@Param(value = "activityName") String activityName,
@Param(value = "templateStatus") Integer templateStatus) {
Cnd cnd = Cnd.NEW();
cnd.andEX("year", "=", year);
cnd.and(Cnd.likeEX("activityName", activityName));
// 具备模板管理角色时前端按页签传入状态普通用户不传时仍保持原列表范围
cnd.andEX("templateStatus", "=", templateStatus);
cnd.orderBy("createdAt", "desc");
Pagination<TrainSignUpActivity> pagination = trainSignUpActivityManageService.pageData(pageForm, cnd);
List<TrainSignUpActivity> list = pagination.getList(TrainSignUpActivity.class);
if (list != null && !list.isEmpty()) {
List<String> ids = list.stream().map(TrainSignUpActivity::getId).toList();
List<Sys_home_template> templateList = dao.query(Sys_home_template.class, Cnd.where("id", "in", ids));
List<String> templateIds = templateList.stream().map(Sys_home_template::getId).toList();
list.forEach(activity -> activity.setIsTemplate(templateIds.contains(activity.getId())));
}
return Result.success().addData(pagination);
return Result.success().addData(trainSignUpActivityManageService.pageData(pageForm, cnd));
}
@At
@@ -95,27 +89,9 @@ public class TrainSignUpManageController {
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
return Result.error("无权操作");
}
TrainSignUpActivity activity = trainSignUpActivityManageService.fetch(id);
if (activity == null) {
if (!trainSignUpActivityManageService.setTemplate(id)) {
return Result.error("活动不存在");
}
Sys_home_template oldHomeTemplate = dao.fetch(Sys_home_template.class, id);
Sys_home_template sysHomeTemplate = activity.covertToSysHomeTemplate();
if (oldHomeTemplate != null) {
sysHomeTemplate.setTop(oldHomeTemplate.getTop());
sysHomeTemplate.setPush(oldHomeTemplate.getPush());
sysHomeTemplate.setSortNo(oldHomeTemplate.getSortNo());
if (oldHomeTemplate.getTemplateName() != null) {
sysHomeTemplate.setTemplateName(oldHomeTemplate.getTemplateName());
}
if (oldHomeTemplate.getTemplateIcon() != null) {
sysHomeTemplate.setTemplateIcon(oldHomeTemplate.getTemplateIcon());
}
if (oldHomeTemplate.getTemplateFile() != null) {
sysHomeTemplate.setTemplateFile(oldHomeTemplate.getTemplateFile());
}
}
dao.insertOrUpdate(sysHomeTemplate);
return Result.success();
}
@@ -126,7 +102,7 @@ public class TrainSignUpManageController {
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
return Result.error("无权操作");
}
dao.delete(Sys_home_template.class, id);
trainSignUpActivityManageService.cancelTemplate(id);
return Result.success();
}
@@ -22,6 +22,12 @@ import java.util.List;
@EqualsAndHashCode(callSuper = false)
public class TrainSignUpActivity extends BaseModel implements Serializable, SysHomeConvert {
/** 未设置为活动模板。 */
public static final int TEMPLATE_STATUS_UNSET = 0;
/** 已设置为活动模板。 */
public static final int TEMPLATE_STATUS_SET = 1;
@Name
@PrevInsert(uu32 = true)
private String id;
@@ -112,6 +118,12 @@ public class TrainSignUpActivity extends BaseModel implements Serializable, SysH
private Boolean isTemplate;
@Column
@Comment("模板设置状态(0:未设置,1:已设置)")
@ColDefine(type = ColType.INT, width = 1)
@Default("0")
private Integer templateStatus;
@Column
@Comment("活动类型")
@ColDefine(type = ColType.VARCHAR, width = 20)
@@ -59,6 +59,21 @@ public interface TrainSignUpActivityService extends BaseService<TrainSignUpActiv
*/
Pagination pageData(PageForm pageForm, Cnd cnd);
/**
* 将品牌活动设置为工作模板并同步活动表中的模板状态
*
* @param id 活动ID
* @return true 表示活动存在且设置成功false 表示活动不存在
*/
boolean setTemplate(String id);
/**
* 取消品牌活动工作模板并同步活动表中的模板状态
*
* @param id 活动ID
*/
void cancelTemplate(String id);
/**
* 手机端分页查询
@@ -5,6 +5,7 @@ import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.sys.models.Sys_home_activity;
import com.budwk.app.sys.models.Sys_home_template;
import com.budwk.app.sys.views.View_user;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.activity.family.models.FamilyActivity;
@@ -53,7 +54,8 @@ public class TrainSignUpActivityServiceImpl extends BaseServiceImpl<TrainSignUpA
@Override
@Aop(TransAop.READ_COMMITTED)
public void add(TrainSignUpActivity activity, TrainSignUpCourse course) {
// 新建活动包括从模板另存统一归入活动列表不能继承来源活动的模板状态
activity.setTemplateStatus(TrainSignUpActivity.TEMPLATE_STATUS_UNSET);
dao().insert(activity);
//插入类型限制
@@ -289,6 +291,58 @@ public class TrainSignUpActivityServiceImpl extends BaseServiceImpl<TrainSignUpA
return pagination;
}
/**
* 将品牌活动转换为工作模板并原样保留模板中心已维护的展示配置
*
* @param id 活动ID
* @return true 表示活动存在且设置成功false 表示活动不存在
*/
@Override
@Aop(TransAop.READ_COMMITTED)
public boolean setTemplate(String id) {
TrainSignUpActivity activity = fetch(id);
if (activity == null) {
return false;
}
Sys_home_template oldHomeTemplate = dao().fetch(Sys_home_template.class, id);
Sys_home_template sysHomeTemplate = activity.covertToSysHomeTemplate();
if (oldHomeTemplate != null) {
// 重复设置时保留模板中心人工配置避免覆盖置顶推送排序及模板素材
sysHomeTemplate.setTop(oldHomeTemplate.getTop());
sysHomeTemplate.setPush(oldHomeTemplate.getPush());
sysHomeTemplate.setSortNo(oldHomeTemplate.getSortNo());
if (oldHomeTemplate.getTemplateName() != null) {
sysHomeTemplate.setTemplateName(oldHomeTemplate.getTemplateName());
}
if (oldHomeTemplate.getTemplateIcon() != null) {
sysHomeTemplate.setTemplateIcon(oldHomeTemplate.getTemplateIcon());
}
if (oldHomeTemplate.getTemplateFile() != null) {
sysHomeTemplate.setTemplateFile(oldHomeTemplate.getTemplateFile());
}
}
dao().insertOrUpdate(sysHomeTemplate);
dao().update(TrainSignUpActivity.class,
Chain.make("templateStatus", TrainSignUpActivity.TEMPLATE_STATUS_SET),
Cnd.where("id", "=", id));
return true;
}
/**
* 删除模板中心记录并将活动恢复为未设置模板状态
*
* @param id 活动ID
*/
@Override
@Aop(TransAop.READ_COMMITTED)
public void cancelTemplate(String id) {
dao().delete(Sys_home_template.class, id);
dao().update(TrainSignUpActivity.class,
Chain.make("templateStatus", TrainSignUpActivity.TEMPLATE_STATUS_UNSET),
Cnd.where("id", "=", id));
}
@Override
public Pagination mPageData(PageForm pageForm, Integer year, int activityStatus, Integer activityType) {
Cnd cnd = Cnd.NEW();
@@ -7,10 +7,8 @@ import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HtmlUtil;
import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.sys.models.Sys_home_activity;
import com.budwk.app.sys.models.Sys_home_template;
import com.budwk.app.sys.models.Sys_user;
@@ -53,8 +51,6 @@ public class ActivityWorksCollectionManageController {
@Inject
private ActivityWorksCollectionService activityWorksCollectionService;
@Inject
private BaseService baseService;
@Inject
private SysMsgService sysMsgService;
@Inject
private ActivityBasicScopeService activityBasicScopeService;
@@ -67,31 +63,8 @@ public class ActivityWorksCollectionManageController {
@At
@SaCheckPermission("activity.workscollection.manage")
public Result pageData(@Valid PageForm pageForm, Long year) {
Sql sql = Sqls.create("""
select
wc.id,
wc.name,
wc.createdAt,
wc.startDateTime,
wc.endDateTime,
wc.enable,
IF(sht.id IS NULL, 0, 1) isTemplate,
u.username as userName
from
activity_works_collection wc
LEFT JOIN vw_user u on u.id = wc.createdBy
LEFT JOIN sys_home_template sht ON sht.id = wc.id
$condition
""");
Cnd cnd = Cnd.NEW();
cnd.andEX("year(startDateTime)", "=", year);
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
cnd.where().andLike("name", pageForm.getSearchKeyword());
}
sql.setCondition(cnd);
Pagination pagination = baseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
return Result.success(pagination);
public Result pageData(@Valid PageForm pageForm, Long year, Integer templateStatus) {
return Result.success(activityWorksCollectionService.pageData(pageForm, year, templateStatus));
}
@At
@@ -100,27 +73,9 @@ public class ActivityWorksCollectionManageController {
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
return Result.error("无权操作");
}
Activity_works_collection worksCollection = dao.fetch(Activity_works_collection.class, id);
if (worksCollection == null) {
if (!activityWorksCollectionService.setTemplate(id)) {
return Result.error("活动不存在");
}
Sys_home_template oldHomeTemplate = dao.fetch(Sys_home_template.class, id);
Sys_home_template sysHomeTemplate = worksCollection.covertToSysHomeTemplate();
if (oldHomeTemplate != null) {
sysHomeTemplate.setTop(oldHomeTemplate.getTop());
sysHomeTemplate.setPush(oldHomeTemplate.getPush());
sysHomeTemplate.setSortNo(oldHomeTemplate.getSortNo());
if (oldHomeTemplate.getTemplateName() != null) {
sysHomeTemplate.setTemplateName(oldHomeTemplate.getTemplateName());
}
if (oldHomeTemplate.getTemplateIcon() != null) {
sysHomeTemplate.setTemplateIcon(oldHomeTemplate.getTemplateIcon());
}
if (oldHomeTemplate.getTemplateFile() != null) {
sysHomeTemplate.setTemplateFile(oldHomeTemplate.getTemplateFile());
}
}
dao.insertOrUpdate(sysHomeTemplate);
return Result.success();
}
@@ -130,7 +85,7 @@ public class ActivityWorksCollectionManageController {
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
return Result.error("无权操作");
}
dao.delete(Sys_home_template.class, id);
activityWorksCollectionService.cancelTemplate(id);
return Result.success();
}
@@ -165,6 +120,8 @@ public class ActivityWorksCollectionManageController {
if (worksCollection == null) {
return;
}
// 新建或从模板另存的活动必须进入活动列表不能继承来源活动的模板状态
worksCollection.setTemplateStatus(Activity_works_collection.TEMPLATE_STATUS_UNSET);
worksCollection.setId(null);
worksCollection.setCreatedBy(null);
worksCollection.setCreatedAt(null);
@@ -22,6 +22,12 @@ import java.util.List;
@Comment("作品征集活动")
public class Activity_works_collection extends BaseModel implements SysHomeConvert {
/** 未设置为活动模板。 */
public static final int TEMPLATE_STATUS_UNSET = 0;
/** 已设置为活动模板。 */
public static final int TEMPLATE_STATUS_SET = 1;
@Name
@Comment("ID")
@PrevInsert(uu32 = true)
@@ -110,6 +116,12 @@ public class Activity_works_collection extends BaseModel implements SysHomeConve
@Default(value = "1")
private Boolean isSubmit;
@Column
@Comment("模板设置状态(0:未设置,1:已设置)")
@ColDefine(type = ColType.INT, width = 1)
@Default("0")
private Integer templateStatus;
@Column
@Comment("主办单位")
@ColDefine(type = ColType.MYSQL_JSON)
@@ -1,11 +1,39 @@
package com.budwk.app.zhgh.activity.workscollection.service;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.zhgh.activity.workscollection.models.Activity_works_collection;
/**
* 作品征集活动配置服务
*/
public interface ActivityWorksCollectionService {
public interface ActivityWorksCollectionService extends BaseService<Activity_works_collection> {
/**
* 分页查询作品征集活动
*
* @param pageForm 分页及关键字参数
* @param year 活动年度
* @param templateStatus 模板设置状态为空时不限制
* @return 作品征集活动分页数据
*/
Pagination pageData(PageForm pageForm, Long year, Integer templateStatus);
/**
* 将作品征集活动设置为工作模板并同步模板状态
*
* @param id 活动ID
* @return true 表示设置成功false 表示活动不存在
*/
boolean setTemplate(String id);
/**
* 取消作品征集活动模板并同步模板状态
*
* @param id 活动ID
*/
void cancelTemplate(String id);
/**
* 校验编辑活动时删除的主题类型作品类型是否已被投稿引用
@@ -2,13 +2,22 @@ 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.base.page.Pagination;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.sys.models.Sys_home_template;
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.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 java.util.Collections;
@@ -20,14 +29,93 @@ import java.util.stream.Collectors;
* 作品征集活动配置服务实现
*/
@IocBean(args = {"refer:dao"})
public class ActivityWorksCollectionServiceImpl implements ActivityWorksCollectionService {
public class ActivityWorksCollectionServiceImpl extends BaseServiceImpl<Activity_works_collection> implements ActivityWorksCollectionService {
private final Dao dao;
public ActivityWorksCollectionServiceImpl(Dao dao) {
super(dao);
this.dao = dao;
}
/**
* 按年度关键字及模板状态分页查询作品征集活动
*/
@Override
public Pagination pageData(PageForm pageForm, Long year, Integer templateStatus) {
Sql sql = Sqls.create("""
select
wc.id,
wc.name,
wc.createdAt,
wc.startDateTime,
wc.endDateTime,
wc.enable,
wc.templateStatus,
wc.templateStatus isTemplate,
u.username as userName
from
activity_works_collection wc
LEFT JOIN vw_user u on u.id = wc.createdBy
$condition
""");
Cnd cnd = Cnd.NEW();
cnd.andEX("year(wc.startDateTime)", "=", year);
cnd.andEX("wc.templateStatus", "=", templateStatus);
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
cnd.where().andLike("wc.name", pageForm.getSearchKeyword());
}
cnd.desc("wc.createdAt");
sql.setCondition(cnd);
return listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
}
/**
* 将作品征集活动转换为工作模板并保留模板中心已维护的展示配置
*/
@Override
@Aop(TransAop.READ_COMMITTED)
public boolean setTemplate(String id) {
Activity_works_collection worksCollection = dao.fetch(Activity_works_collection.class, id);
if (worksCollection == null) {
return false;
}
Sys_home_template oldHomeTemplate = dao.fetch(Sys_home_template.class, id);
Sys_home_template sysHomeTemplate = worksCollection.covertToSysHomeTemplate();
if (oldHomeTemplate != null) {
// 重复设置时保留模板中心人工配置避免覆盖置顶推送排序及模板素材
sysHomeTemplate.setTop(oldHomeTemplate.getTop());
sysHomeTemplate.setPush(oldHomeTemplate.getPush());
sysHomeTemplate.setSortNo(oldHomeTemplate.getSortNo());
if (oldHomeTemplate.getTemplateName() != null) {
sysHomeTemplate.setTemplateName(oldHomeTemplate.getTemplateName());
}
if (oldHomeTemplate.getTemplateIcon() != null) {
sysHomeTemplate.setTemplateIcon(oldHomeTemplate.getTemplateIcon());
}
if (oldHomeTemplate.getTemplateFile() != null) {
sysHomeTemplate.setTemplateFile(oldHomeTemplate.getTemplateFile());
}
}
dao.insertOrUpdate(sysHomeTemplate);
dao.update(Activity_works_collection.class,
Chain.make("templateStatus", Activity_works_collection.TEMPLATE_STATUS_SET),
Cnd.where("id", "=", id));
return true;
}
/**
* 删除模板中心记录并将作品征集活动恢复为未设置模板状态
*/
@Override
@Aop(TransAop.READ_COMMITTED)
public void cancelTemplate(String id) {
dao.delete(Sys_home_template.class, id);
dao.update(Activity_works_collection.class,
Chain.make("templateStatus", Activity_works_collection.TEMPLATE_STATUS_UNSET),
Cnd.where("id", "=", id));
}
@Override
public String validateReferencedTypesBeforeUpdate(Activity_works_collection worksCollection) {
if (worksCollection == null || StrUtil.isBlank(worksCollection.getId())) {
@@ -76,7 +76,8 @@ public class ClubExamineApplyController {
if(year == null) {
return Result.error("年份信息为空,请核查");
}
List<SysClubExamineRegister> list = dao.query(SysClubExamineRegister.class, Cnd.where("clubId", "=", clubId).and("year(registerDate)", "=", year).andEX("id", "!=", id));
// 同一社团的年度重复申请校验以登记年度为准不能按申请时间判断
List<SysClubExamineRegister> list = dao.query(SysClubExamineRegister.class, Cnd.where("clubId", "=", clubId).and("year", "=", year).andEX("id", "!=", id));
List<ProcessInstance> instanceList = dao.query(
ProcessInstance.class,
Cnd.where(ProcessInstance::getBusinessNo, "in", list.stream().map(SysClubExamineRegister::getId).toList())
@@ -146,8 +147,9 @@ public class ClubExamineApplyController {
if(StrUtil.isBlank(clubId)) {
return Result.error("社团信息为空,请核查");
}
// 上年度结余按登记年度查询避免申请时间跨年导致取错数据
SysClubExamineRegister register = dao.fetch(SysClubExamineRegister.class, Cnd.where("clubId", "=", clubId)
.and("YEAR(registerDate)", "=", DateUtil.thisYear() - 1));
.and("year", "=", DateUtil.thisYear() - 1));
if (Lang.isNotEmpty(register)) {
List<JSONObject> list = register.getIncomeCensus();
float surplus = list.get(0).getFloat("surplus");
@@ -87,7 +87,8 @@ public class ClubExamineMineController {
nutMap.setv("clubName", register.getClubName());
nutMap.setv("create_time", register.getFoundTime());
nutMap.setv("dues_standard", register.getDue());
nutMap.setv("year", register.getRegisterDate().substring(0, 4));
// 生成材料中的年度与列表展示的登记年度保持一致
nutMap.setv("year", register.getYear());
nutMap.setv("registerDate", register.getRegisterDate());
nutMap.setv("incomeCensus", incomeCensus);
nutMap.setv("jgUser", jgUser);
@@ -90,10 +90,12 @@ public class ClubAuditManagerController {
cnd.andEX("year(info.creatTime)", "=", pageForm.getYear());
cnd.and("t.taskName", "=", "ef81777f-22fb-4fe4-9800-909e6c681210");
cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId()));
if (approval) {
// 已审核是全量历史不能因历史工作流参与人不同而遗漏参考库迁移记录
cnd.and("t.taskState", "in", List.of(ProcessTaskStateEnum.FINISHED.getCode(), ProcessTaskStateEnum.INTERRUPT.getCode()));
} else {
// 未审核只展示当前登录人实际可以处理的待办任务
cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId()));
cnd.and("t.taskState", "=", ProcessTaskStateEnum.DOING.getCode());
}
@@ -2,10 +2,14 @@ package com.budwk.app.zhgh.club.controller.infoManage;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.json.JSONObject;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.result.Result;
import com.budwk.app.base.utils.PageUtil;
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
import com.budwk.app.sys.models.Sys_file;
import com.budwk.app.sys.utils.SysFileMinIoUtil;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.club.param.ClubUserPageForm;
import com.budwk.app.zhgh.club.service.SysClubInfoManageService;
@@ -14,12 +18,24 @@ import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* @Author: JyuHsin
@@ -32,6 +48,8 @@ import java.util.List;
@At("/platform/club/infoManage/schoolAuditReport")
public class ClubSchoolAuditReportController {
private static final Logger log = LoggerFactory.getLogger(ClubSchoolAuditReportController.class);
@Inject
private SysClubInfoManageService clubInfoManageService;
@@ -44,6 +62,71 @@ public class ClubSchoolAuditReportController {
@SaCheckPermission("club.infoManage.schoolAuditReport")
public Result pageData(@Valid ClubUserPageForm pageForm,
@Param(value = "approval") Boolean approval) {
Sql sql = buildPageDataSql(pageForm, approval);
Pagination pagination = clubInfoManageService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
return Result.success(pagination);
}
/**
* 导出当前筛选范围内的换届报告附件压缩包
*
* @param pageForm 页面查询条件
* @param approval 审核状态与列表页保持一致
* @param response HTTP 下载响应
*/
@At
@Ok("void")
@SaCheckPermission("club.infoManage.schoolAuditReport")
public void exportRefreshReportZip(@Valid ClubUserPageForm pageForm,
@Param(value = "approval") Boolean approval,
HttpServletResponse response) throws IOException {
List<NutMap> reportList = clubInfoManageService.listMap(buildPageDataSql(pageForm, approval));
response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachment;filename=" + URLUtil.encode("换届报告.zip"));
// 显式指定 UTF-8确保压缩包内中文目录和文件名正常显示
try (ZipOutputStream zipOutputStream = new ZipOutputStream(new BufferedOutputStream(response.getOutputStream()), StandardCharsets.UTF_8)) {
Set<String> entryNames = new HashSet<>();
for (NutMap report : reportList) {
String filesJson = report.getString("files");
if (StrUtil.isBlank(filesJson)) {
continue;
}
List<JSONObject> files = Json.fromJsonAsList(JSONObject.class, filesJson);
String folderName = buildFolderName(report);
for (int index = 0; index < files.size(); index++) {
JSONObject fileInfo = files.get(index);
Sys_file sysFile = findSysFile(fileInfo);
if (sysFile == null) {
log.warn("换届报告附件不存在,报告ID:{},附件:{}", report.getString("id"), fileInfo);
continue;
}
byte[] fileBytes = SysFileMinIoUtil.getFileBytes(sysFile.getBucket(), sysFile.getStoragePath());
if (fileBytes == null || fileBytes.length == 0) {
log.warn("换届报告附件内容为空,报告ID:{},附件ID:{}", report.getString("id"), sysFile.getId());
continue;
}
String fileName = StrUtil.blankToDefault(fileInfo.getStr("name"), fileInfo.getStr("filename"));
if (StrUtil.isBlank(fileName)) {
fileName = sysFile.getName();
}
String entryName = buildUniqueEntryName(folderName + "/" + sanitizeFileName(fileName), entryNames);
zipOutputStream.putNextEntry(new ZipEntry(entryName));
zipOutputStream.write(fileBytes);
zipOutputStream.closeEntry();
}
}
}
}
/**
* 构建列表与导出共用的换届报告查询确保查什么导什么
*
* @param pageForm 页面查询条件
* @param approval 审核状态
* @return 已绑定筛选条件的查询对象
*/
private Sql buildPageDataSql(ClubUserPageForm pageForm, Boolean approval) {
Sql sql = Sqls.create("""
SELECT
info.*,
@@ -79,7 +162,7 @@ public class ClubSchoolAuditReportController {
cnd.and("t.taskName", "=", "d4323546-8d09-419e-88d4-7b15862ca29d");
cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId()));
if (approval) {
if (Boolean.TRUE.equals(approval)) {
cnd.and("t.taskState", "in", List.of(ProcessTaskStateEnum.FINISHED.getCode(), ProcessTaskStateEnum.INTERRUPT.getCode()));
} else {
cnd.and("t.taskState", "=", ProcessTaskStateEnum.DOING.getCode());
@@ -96,8 +179,67 @@ public class ClubSchoolAuditReportController {
cnd.groupBy("t.id");
sql.setCondition(cnd);
return sql;
}
Pagination pagination = clubInfoManageService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
return Result.success(pagination);
/**
* 兼容新旧附件 JSON 结构按附件 ID 或下载地址查找文件元数据
*
* @param fileInfo 附件 JSON 信息
* @return 系统文件记录未找到时返回 null
*/
private Sys_file findSysFile(JSONObject fileInfo) {
String fileId = fileInfo.getStr("id");
if (StrUtil.isNotBlank(fileId)) {
return clubInfoManageService.dao().fetch(Sys_file.class, fileId);
}
String fileUrl = fileInfo.getStr("url");
if (StrUtil.isBlank(fileUrl)) {
return null;
}
return clubInfoManageService.dao().fetch(Sys_file.class, Cnd.where(Sys_file::getDownloadPath, "=", fileUrl));
}
/**
* 使用社团名称建立目录方便按换届报告来源查阅
*
* @param report 换届报告记录
* @return Zip 内目录名称
*/
private String buildFolderName(NutMap report) {
return sanitizeFileName(report.getString("clubName"));
}
/**
* 保留附件原始文件名同一社团目录存在同名文件时追加序号避免覆盖
*
* @param entryName 原始 Zip 条目名称
* @param entryNames 已写入的 Zip 条目名称
* @return 唯一的 Zip 条目名称
*/
private String buildUniqueEntryName(String entryName, Set<String> entryNames) {
if (entryNames.add(entryName)) {
return entryName;
}
int extensionIndex = entryName.lastIndexOf('.');
String name = extensionIndex > entryName.lastIndexOf('/') ? entryName.substring(0, extensionIndex) : entryName;
String extension = extensionIndex > entryName.lastIndexOf('/') ? entryName.substring(extensionIndex) : "";
int index = 2;
String uniqueEntryName;
do {
uniqueEntryName = name + "(" + index + ")" + extension;
index++;
} while (!entryNames.add(uniqueEntryName));
return uniqueEntryName;
}
/**
* 去除 Zip 条目路径分隔符避免附件名影响压缩包目录结构
*
* @param fileName 原始文件名
* @return 可安全写入 Zip 的文件名
*/
private String sanitizeFileName(String fileName) {
return StrUtil.blankToDefault(fileName, "未命名文件").replace("/", "_").replace("\\", "_");
}
}
@@ -95,6 +95,14 @@ public class SysClubExamineRegister extends BaseModel {
@ColDefine(type = ColType.MYSQL_JSON)
private List<JSONObject> yearActivityList;
/**
* 旧版年审表保存的年度活动明细保留该字段用于查看迁移历史数据
*/
@Column
@Comment("旧版年度活动明细")
@ColDefine(type = ColType.MYSQL_JSON)
private List<JSONObject> yearActivitys;
@Column
@Comment("财务收支情况统计json")
@ColDefine(type = ColType.MYSQL_JSON)
@@ -24,6 +24,10 @@ public class ClubUserPageForm extends PageForm {
private Integer auditType;
private Integer source;
private Integer year;
/** 社团评优申报开始年度筛选条件。 */
private String applyStartYear;
/** 社团评优申报结束年度筛选条件。 */
private String applyEndYear;
private Boolean giveMoney;
private Integer radioType;
}
@@ -71,7 +71,9 @@ public class SysClubEvaluateServiceImpl extends BaseServiceImpl<SysClubEvaluate>
Cnd cnd = Cnd.NEW();
cnd.andEX("info.clubId", "=", pageForm.getClubId());
cnd.andEX("year(info.applyTime)", "=", pageForm.getYear());
// 评优年度以申报填写的起止年度为准不能使用申请提交时间所在年份代替
cnd.andEX("info.applyStartYear", "=", pageForm.getApplyStartYear());
cnd.andEX("info.applyEndYear", "=", pageForm.getApplyEndYear());
cnd.and("info.userId", "=", SecurityUtil.getUserId());
cnd.groupBy("info.id");
@@ -144,7 +146,9 @@ public class SysClubEvaluateServiceImpl extends BaseServiceImpl<SysClubEvaluate>
""");
cnd.andEX("ce.clubId", "=", pageForm.getClubId());
cnd.andEX("year(ce.applyTime)", "=", pageForm.getYear());
// 审核列表与参考项目保持一致分别按申报开始年度和申报结束年度筛选
cnd.andEX("ce.applyStartYear", "=", pageForm.getApplyStartYear());
cnd.andEX("ce.applyEndYear", "=", pageForm.getApplyEndYear());
if (pageForm.getAudit()) {
cnd.and("t.taskState", "in", List.of(ProcessTaskStateEnum.FINISHED.getCode(), ProcessTaskStateEnum.INTERRUPT.getCode()));
@@ -8,6 +8,7 @@ import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.base.utils.PageUtil;
import com.budwk.app.flow.entity.ProcessInstance;
import com.budwk.app.flow.enums.ProcessInstanceStateEnum;
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
import com.budwk.app.web.commons.auth.utils.AuthUtil;
@@ -33,8 +34,10 @@ import org.nutz.lang.util.NutMap;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
@IocBean(args = {"refer:dao"})
@@ -119,6 +122,7 @@ public class SysClubExamineServiceImpl extends BaseServiceImpl<SysClubExamineReg
Sql applySql = Sqls.create("""
SELECT
cu.userId,
cu.id,
cu.mode,
cu.applyDate,
cu.joinTime,
@@ -129,17 +133,25 @@ public class SysClubExamineServiceImpl extends BaseServiceImpl<SysClubExamineReg
LEFT JOIN sys_user u ON u.id = cu.userId
WHERE cu.clubId = @clubId
AND COALESCE(cu.delFlag, 0) = 0
AND EXISTS (
SELECT 1
FROM wf_process_instance ins
WHERE ins.businessNo = cu.id
AND ins.state = @finishedState
)
ORDER BY cu.applyDate, cu.mode
""")
.setParam("clubId", clubId)
.setParam("finishedState", ProcessInstanceStateEnum.FINISHED.getCode());
.setParam("clubId", clubId);
List<NutMap> applications = listMap(applySql);
if (!applications.isEmpty()) {
// 流程状态改为按当前社团申请批量查询避免相关子查询对流程实例表重复扫描
List<String> applicationIds = applications.stream()
.map(application -> application.getString("id"))
.filter(StrUtil::isNotBlank)
.collect(Collectors.toList());
List<ProcessInstance> finishedInstances = applicationIds.isEmpty() ? new ArrayList<>()
: dao().query(ProcessInstance.class, Cnd.where(ProcessInstance::getBusinessNo, "in", applicationIds)
.and(ProcessInstance::getState, "=", ProcessInstanceStateEnum.FINISHED.getCode()));
Set<String> finishedBusinessNos = finishedInstances.stream()
.map(ProcessInstance::getBusinessNo)
.filter(StrUtil::isNotBlank)
.collect(Collectors.toCollection(HashSet::new));
applications.removeIf(application -> !finishedBusinessNos.contains(application.getString("id")));
}
applications.sort(Comparator.comparing(row -> row.getTime("applyDate"), Comparator.nullsLast(Date::compareTo)));
for (NutMap application : applications) {
@@ -259,6 +271,10 @@ public class SysClubExamineServiceImpl extends BaseServiceImpl<SysClubExamineReg
}
private String normalizeUserState(String userState) {
// 历史成员数据可能未同步人员状态空值不参与在职退休人数统计
if (StrUtil.isBlank(userState)) {
return null;
}
if (List.of("在职", "在岗").contains(userState)) {
return "在职";
}
@@ -476,6 +492,8 @@ public class SysClubExamineServiceImpl extends BaseServiceImpl<SysClubExamineReg
// 查询主表数据并关联明细数据
ClubExamineVo clubExamineVo = fetchVO(sql, ClubExamineVo.class);
if (Lang.isNotEmpty(clubExamineVo)) {
// 详情页统一使用V4字段兼容尚未改写JSON内容的V3年审记录
normalizeActivityData(clubExamineVo);
List<SysClubExamineRegisterDetailed> detailedList = dao().query(SysClubExamineRegisterDetailed.class,
Cnd.where("registerId", "=", id).asc("location"));
clubExamineVo.setDetailedList(detailedList);
@@ -512,6 +530,116 @@ public class SysClubExamineServiceImpl extends BaseServiceImpl<SysClubExamineReg
return clubExamineVo;
}
/**
* 将旧版年审活动和计划字段转换为查看页统一使用的V4字段避免历史数据在页面中显示为空
*
* @param examineVo 年审详情
*/
private void normalizeActivityData(ClubExamineVo examineVo) {
examineVo.setSummaryFiles(normalizeSummaryFiles(examineVo.getSummaryFiles()));
examineVo.setChangeUserNum(normalizeChangeUserNum(examineVo.getChangeUserNum()));
List<JSONObject> yearActivitySource = examineVo.getYearActivityList();
if (yearActivitySource == null || yearActivitySource.isEmpty()) {
yearActivitySource = examineVo.getYearActivitys();
}
examineVo.setYearActivityList(yearActivitySource == null ? new ArrayList<>()
: yearActivitySource.stream()
.map(item -> normalizeActivityItem(item, true))
.collect(Collectors.toList()));
List<JSONObject> planSource = examineVo.getPlans();
examineVo.setPlans(planSource == null ? new ArrayList<>()
: planSource.stream()
.map(item -> normalizeActivityItem(item, false))
.collect(Collectors.toList()));
}
/**
* 将V3年审记录中的年度减少字段转换为查看页统一使用的V4字段
* 历史年审必须展示申请时保存的数据不能按当前会员状态重新统计
*
* @param changeUserNum 年审记录保存的成员变化数据
* @return 兼容V3V4字段的成员变化数据
*/
private List<JSONObject> normalizeChangeUserNum(List<JSONObject> changeUserNum) {
if (changeUserNum == null || changeUserNum.isEmpty()) {
return new ArrayList<>();
}
return changeUserNum.stream()
.filter(Objects::nonNull)
.peek(item -> {
if (!item.containsKey("yearReduceNum") && item.containsKey("yearEditNum")) {
item.set("yearReduceNum", item.get("yearEditNum"));
}
})
.collect(Collectors.toList());
}
/**
* 将V3工作总结附件的文件主键包装为V4文件预览组件所需的response.data格式
*
* @param summaryFiles 原始工作总结附件
* @return 可供文件预览组件读取的附件数据
*/
private List<JSONObject> normalizeSummaryFiles(List<JSONObject> summaryFiles) {
if (summaryFiles == null || summaryFiles.isEmpty()) {
return new ArrayList<>();
}
return summaryFiles.stream()
.filter(Objects::nonNull)
.map(file -> {
JSONObject response = file.getJSONObject("response");
if (response != null && StrUtil.isNotBlank(response.getStr("data"))) {
return file;
}
String fileId = file.getStr("id");
if (StrUtil.isBlank(fileId)) {
return null;
}
JSONObject normalizedFile = new JSONObject();
normalizedFile.set("response", new JSONObject().set("data", fileId));
return normalizedFile;
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
/**
* 兼容V3活动字段hdsjmczbdwhdddcjrshjqk和V4活动字段
*
* @param source 原始活动或计划数据
* @param includeResult 是否包含本年度活动的参加人数和获奖情况
* @return 供查看页使用的统一字段数据
*/
private JSONObject normalizeActivityItem(JSONObject source, boolean includeResult) {
JSONObject item = new JSONObject();
item.set("activityName", getActivityValue(source, "activityName", "mc"));
item.set("activityUnit", getActivityValue(source, "activityUnit", "zbdw"));
item.set("activityAddress", getActivityValue(source, "activityAddress", "hddd"));
if (includeResult) {
item.set("activityTime", getActivityValue(source, "activityTime", "hdsj"));
item.set("joinNum", getActivityValue(source, "joinNum", "cjrs"));
item.set("prize", getActivityValue(source, "prize", "hjqk"));
}
return item;
}
/**
* 优先读取V4字段历史记录没有该字段时回退读取对应的V3字段
*
* @param source 原始JSON数据
* @param currentField V4字段名
* @param legacyField V3字段名
* @return 兼容后的字段值
*/
private String getActivityValue(JSONObject source, String currentField, String legacyField) {
if (source == null) {
return null;
}
String currentValue = source.getStr(currentField);
return StrUtil.isNotBlank(currentValue) ? currentValue : source.getStr(legacyField);
}
@Override
public List<NutMap> getYearActivityExportData(String id) {
ClubExamineVo examineVo = this.findOne(id);
@@ -619,7 +747,8 @@ public class SysClubExamineServiceImpl extends BaseServiceImpl<SysClubExamineReg
*/
private void buildPageBaseCondition(Cnd cnd, ClubUserPageForm pageForm, String tableAlias) {
if (pageForm.getYear() != null) {
cnd.andEX("YEAR(" + tableAlias + ".registerDate)", "=", pageForm.getYear());
// 年度查询应与列表展示的登记年度保持一致不能使用申请时间推算年度
cnd.andEX(tableAlias + ".year", "=", pageForm.getYear());
}
if (StrUtil.isNotBlank(pageForm.getClubId())) {
cnd.andEX(tableAlias + ".clubId", "=", pageForm.getClubId());
@@ -17,6 +17,10 @@ public class ClubEvaluatePageVo {
private String foundTime;
private String typeName;
private Date applyTime;
/** 社团评优申报开始年度。 */
private String applyStartYear;
/** 社团评优申报结束年度。 */
private String applyEndYear;
private String instanceId;
private String businessNo;
@@ -11,6 +11,7 @@ import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.nutz.dao.Cnd;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.util.NutMap;
@@ -43,22 +44,26 @@ public class ArticleAnalysisController {
@At
@SaCheckPermission("article.analysis")
@ApiOperation(value = "统计分析")
public Result overview() {
public Result overview(Date startDate, Date endDate, String unionId, String clubId) {
List<ArticleAnalysisOverviewVO> list = new ArrayList<>();
// 获取总投稿量
list.add(ArticleAnalysisOverviewVO.builder()
.label("总投稿量")
.value(articleService.count())
.value(articleService.count(buildStatisticsCondition(startDate, endDate, unionId, clubId)))
.icon("el-icon-document")
.bgColor("rgba(24, 103, 176, 0.1)")
.trend(null)
.build());
// 获取本月投稿量
long monthlyCount = articleService.count(Cnd.where("MONTH(submitTime)", "=", DateUtil.thisMonth() + 1));
Cnd monthlyCondition = buildStatisticsCondition(startDate, endDate, unionId, clubId);
monthlyCondition.and("MONTH(submitTime)", "=", DateUtil.thisMonth() + 1);
long monthlyCount = articleService.count(monthlyCondition);
//上月投稿量
long lastMonthCount = articleService.count(Cnd.where("MONTH(submitTime)", "=", DateUtil.offsetMonth(new Date(), -1)));
Cnd lastMonthCondition = buildStatisticsCondition(startDate, endDate, unionId, clubId);
lastMonthCondition.and("MONTH(submitTime)", "=", DateUtil.month(DateUtil.offsetMonth(new Date(), -1)) + 1);
long lastMonthCount = articleService.count(lastMonthCondition);
list.add(ArticleAnalysisOverviewVO.builder()
.label("本月投稿")
@@ -70,7 +75,9 @@ public class ArticleAnalysisController {
// 获取活跃投稿人数
DateTime dateTime = DateUtil.offsetMonth(new Date(), -1);
long activeUsers = Math.max(articleService.count(Cnd.where("submitTime", ">=", dateTime).groupBy("userId")), 0L);
Cnd activeUserCondition = buildStatisticsCondition(startDate, endDate, unionId, clubId);
activeUserCondition.and("submitTime", ">=", dateTime).groupBy("userId");
long activeUsers = Math.max(articleService.count(activeUserCondition), 0L);
list.add(ArticleAnalysisOverviewVO.builder()
.label("活跃投稿人")
.value(activeUsers)
@@ -81,7 +88,11 @@ public class ArticleAnalysisController {
// 获取参与分工会数量
long unionCount = articleService.count(Sqls.create("SELECT COUNT(distinct unionId) FROM article WHERE unionId IS NOT NULL"));
Sql unionCountSql = Sqls.create("SELECT COUNT(distinct unionId) FROM article $condition");
Cnd unionCountCondition = buildStatisticsCondition(startDate, endDate, unionId, clubId);
unionCountCondition.and("unionId", "IS NOT", null);
unionCountSql.setCondition(unionCountCondition);
long unionCount = articleService.count(unionCountSql);
list.add(ArticleAnalysisOverviewVO.builder()
.label("参与分工会")
.value(unionCount)
@@ -91,7 +102,11 @@ public class ArticleAnalysisController {
.build());
// 获取参与社团数量
long clubCount = articleService.count(Sqls.create("SELECT COUNT(distinct clubId) FROM article WHERE clubId IS NOT NULL"));
Sql clubCountSql = Sqls.create("SELECT COUNT(distinct clubId) FROM article $condition");
Cnd clubCountCondition = buildStatisticsCondition(startDate, endDate, unionId, clubId);
clubCountCondition.and("clubId", "IS NOT", null);
clubCountSql.setCondition(clubCountCondition);
long clubCount = articleService.count(clubCountSql);
list.add(ArticleAnalysisOverviewVO.builder()
.label("参与社团")
.value(clubCount)
@@ -102,22 +117,43 @@ public class ArticleAnalysisController {
return Result.success(list);
}
/**
* 构建概览统计的筛选条件与图表接口保持相同的时间范围分工会和社团口径
*/
private Cnd buildStatisticsCondition(Date startDate, Date endDate, String unionId, String clubId) {
Cnd cnd = Cnd.NEW();
if (startDate != null && endDate != null) {
cnd.and(Cnd.cri().where().andBetween("submitTime", startDate, endDate));
}
cnd.andEX("unionId", "=", unionId);
cnd.andEX("clubId", "=", clubId);
return cnd;
}
@At
@SaCheckPermission("article.analysis")
@ApiOperation(value = "投稿趋势")
public Result trend(@Valid String type, Date startDate, Date endDate) {
List<NutMap> submissionTrend = articleAnalysisService.getSubmissionTrend(type, startDate, endDate);
public Result trend(@Valid String type, Date startDate, Date endDate, String unionId, String clubId) {
List<NutMap> submissionTrend = articleAnalysisService.getSubmissionTrend(type, startDate, endDate, unionId, clubId);
return Result.success(submissionTrend);
}
@At
@SaCheckPermission("article.analysis")
@ApiOperation(value = "分工会投稿分布")
public Result distribution(Date startDate, Date endDate) {
List<NutMap> unionDistribution = articleAnalysisService.getUnionDistribution(startDate, endDate);
public Result distribution(Date startDate, Date endDate, String unionId, String clubId) {
List<NutMap> unionDistribution = articleAnalysisService.getUnionDistribution(startDate, endDate, unionId, clubId);
return Result.success(unionDistribution);
}
@At
@SaCheckPermission("article.analysis")
@ApiOperation(value = "社团投稿分布")
public Result clubDistribution(Date startDate, Date endDate, String unionId, String clubId) {
List<NutMap> clubDistribution = articleAnalysisService.getClubDistribution(startDate, endDate, unionId, clubId);
return Result.success(clubDistribution);
}
@At
@SaCheckPermission("article.analysis")
@ApiOperation(value = "投稿排名")
@@ -52,6 +52,7 @@ public class ArticleMineController {
@SaCheckPermission("article.mine")
@ApiOperation("分页查询")
public Result pageData(@Valid ArticleInfoPageParam pageForm) {
// 每篇投稿仅关联最新的一条待办任务避免多办理人或并行待办将同一投稿重复展示
Sql sql = Sqls.create("""
SELECT
info.id,
@@ -79,8 +80,11 @@ public class ArticleMineController {
FROM
article info
LEFT JOIN `wf_process_instance` ins ON ins.businessNo = info.id
LEFT JOIN wf_process_task t ON t.processInstanceId = ins.id AND t.taskState = 10
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = t.id
LEFT JOIN wf_process_task t ON t.id = (
SELECT MAX(currentTask.id)
FROM wf_process_task currentTask
WHERE currentTask.processInstanceId = ins.id AND currentTask.taskState = 10
)
$condition
""");
Cnd cnd = Cnd.NEW();
@@ -13,12 +13,17 @@ public interface ArticleAnalysisService extends BaseService<Article> {
/**
* 获取投稿趋势数据
*/
List<NutMap> getSubmissionTrend(String type, Date startDate, Date endDate);
List<NutMap> getSubmissionTrend(String type, Date startDate, Date endDate, String unionId, String clubId);
/**
* 获取分工会投稿分布
*/
List<NutMap> getUnionDistribution(Date startDate, Date endDate);
List<NutMap> getUnionDistribution(Date startDate, Date endDate, String unionId, String clubId);
/**
* 获取社团投稿分布
*/
List<NutMap> getClubDistribution(Date startDate, Date endDate, String unionId, String clubId);
/**
* 获取排行榜数据
@@ -22,7 +22,7 @@ public class ArticleAnalysisServiceImpl extends BaseServiceImpl<Article> impleme
}
@Override
public List<NutMap> getSubmissionTrend(String type, Date startDate, Date endDate) {
public List<NutMap> getSubmissionTrend(String type, Date startDate, Date endDate, String unionId, String clubId) {
String groupFormat = switch (type) {
case "week" -> "%Y-%u"; // 按周分组
case "month" -> "%Y-%m"; // 按月分组
@@ -40,10 +40,8 @@ public class ArticleAnalysisServiceImpl extends BaseServiceImpl<Article> impleme
""");
sql.setParam("groupFormat",groupFormat);
Cnd cnd = Cnd.NEW();
if(ObjectUtil.isAllNotEmpty(startDate,endDate)){
cnd.and(Cnd.cri().where().andBetween("submitTime", startDate, endDate));
}
Cnd cnd = buildStatisticsCondition(startDate, endDate, unionId, clubId);
cnd.groupBy("DATE_FORMAT(submitTime, @groupFormat)");
sql.setCondition(cnd);
return listMap(sql);
@@ -53,7 +51,7 @@ public class ArticleAnalysisServiceImpl extends BaseServiceImpl<Article> impleme
* 获取分工会投稿分布
*/
@Override
public List<NutMap> getUnionDistribution(Date startDate, Date endDate) {
public List<NutMap> getUnionDistribution(Date startDate, Date endDate, String unionId, String clubId) {
Sql sql = Sqls.create("""
SELECT
unionName AS type,
@@ -62,10 +60,7 @@ public class ArticleAnalysisServiceImpl extends BaseServiceImpl<Article> impleme
article
$condition
""");
Cnd cnd = Cnd.NEW();
if(ObjectUtil.isAllNotEmpty(startDate,endDate)){
cnd.and(Cnd.cri().where().andBetween("submitTime", startDate, endDate));
}
Cnd cnd = buildStatisticsCondition(startDate, endDate, unionId, clubId);
cnd.groupBy("unionId","unionName");
cnd.desc("value");
sql.setCondition(cnd);
@@ -73,6 +68,47 @@ public class ArticleAnalysisServiceImpl extends BaseServiceImpl<Article> impleme
return listMap(sql);
}
/**
* 获取社团投稿分布
*/
@Override
public List<NutMap> getClubDistribution(Date startDate, Date endDate, String unionId, String clubId) {
Sql sql = Sqls.create("""
SELECT
clubName AS type,
COUNT(*) AS value
FROM
article
$condition
""");
Cnd cnd = buildStatisticsCondition(startDate, endDate, unionId, clubId);
cnd.and("clubId", "IS NOT", null);
cnd.groupBy("clubId", "clubName");
cnd.desc("value");
sql.setCondition(cnd);
return listMap(sql);
}
/**
* 为统计图表统一拼接时间范围和分工会筛选条件保证各图表的查询口径一致
*
* @param startDate 查询开始日期为空时不限制开始时间
* @param endDate 查询结束日期为空时不限制结束时间
* @param unionId 分工会 ID为空时查询全部分工会
* @param clubId 社团 ID为空时查询全部社团
* @return 可直接设置到统计 SQL 的查询条件
*/
private Cnd buildStatisticsCondition(Date startDate, Date endDate, String unionId, String clubId) {
Cnd cnd = Cnd.NEW();
if (ObjectUtil.isAllNotEmpty(startDate, endDate)) {
cnd.and(Cnd.cri().where().andBetween("submitTime", startDate, endDate));
}
cnd.andEX("unionId", "=", unionId);
cnd.andEX("clubId", "=", clubId);
return cnd;
}
/**
* 获取排行榜数据
*/
@@ -9,9 +9,11 @@ import cn.dev33.satoken.annotation.SaMode;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.result.Result;
import com.budwk.app.base.utils.CommonDownloadUtil;
import com.budwk.app.web.commons.auth.utils.AuthUtil;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.dayofficework.asset.model.Asset;
import com.budwk.app.zhgh.dayofficework.asset.model.AssetDepreciationRecord;
@@ -27,6 +29,7 @@ import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.cri.SqlExpressionGroup;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
@@ -157,9 +160,16 @@ public class AssetManageController {
@SaCheckPermission(value = {"asset.manage", "asset.stocktaking", "h5.asset.stocktaking"}, mode = SaMode.OR)
public Result searchAssetUseUser(String query) {
Cnd cnd = Cnd.NEW();
cnd.where().orLike("username", query);
cnd.where().orLike("loginname", query);
cnd.where().orLike("id", query);
// 三个关键词条件必须整体分组避免 OR 条件绕过分工会数据范围
SqlExpressionGroup searchGroup = new SqlExpressionGroup();
searchGroup.orLike("username", query);
searchGroup.orLike("loginname", query);
searchGroup.orLike("id", query);
cnd.and(searchGroup);
// 分工会侧盘点人员只能选择本分工会成员校工会和系统管理员保留全校查询范围
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
cnd.and("unionId", "=", SecurityUtil.getUnionId());
}
Sql sql = Sqls.create("""
SELECT
id,
@@ -1,12 +1,8 @@
package com.budwk.app.zhgh.dayofficework.birthdayWishes.task;
import cn.hutool.core.date.DateUtil;
import com.budwk.app.sys.models.Sys_msg;
import com.budwk.app.sys.services.SysMsgService;
import com.budwk.app.zhgh.staffmanage.birthday.service.UserBirthdayService;
import lombok.extern.slf4j.Slf4j;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
@@ -15,16 +11,12 @@ import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.util.List;
@IocBean
@Slf4j
public class BirthdayWishesTask implements Job {
@Inject
protected SysMsgService sysMsgService;
@Inject
protected Dao dao;
private UserBirthdayService userBirthdayService;
@Override
@@ -34,28 +26,12 @@ public class BirthdayWishesTask implements Job {
log.info("=================================参数:{}", Json.toJson(dataMap));
String planName = dataMap.getString("name");
String today = DateUtil.today();
String title = planName + today;
String content = dataMap.getString("template");
Sys_msg msg = new Sys_msg();
msg.setTitle(planName + today);
msg.setType("user");
msg.setSendType("show");
msg.setSendAt(DateUtil.current());
msg.setNote(dataMap.getString("template"));
// 查询今天生日的会员用户
Sql sql = Sqls.create("SELECT loginname FROM sys_user WHERE member = 1 AND MONTH(birthday) = MONTH(CURRENT_DATE) AND DAY(birthday) = DAY(CURRENT_DATE)");
sql.setCallback(Sqls.callback.strList());
dao.execute(sql);
List<String> users = sql.getList(String.class);
// 转为数组
String[] userArray = users.toArray(String[]::new);
log.info("=================================查询今天生日会员用户:{}", users);
if(userArray.length > 0){
log.info("=================================发送消息:{}", msg);
sysMsgService.saveMsg(msg, userArray, true);
}
// 统一由生日服务查询当天生日会员生成移动端链接并记录系统推送日志
int receiverCount = userBirthdayService.sendTodayBirthdayMessages(title, content);
log.info("=================================当天生日通知进入发送队列人数:{}", receiverCount);
}
}
@@ -58,6 +58,10 @@ public class BuildHomeKpiWriteDynamicTableRenderPolicy extends DynamicTableRende
// 处理合并
if(ObjectUtil.isNotEmpty(dataList)){
for (int[] value : groupRanges.values()) {
// 单条明细无需合并POI 不支持对同一行进行纵向合并
if (value[0] == value[1]) {
continue;
}
TableTools.mergeCellsVertically(xwpfTable, 0, value[0] + 1, value[1] + 1);
TableTools.mergeCellsVertically(xwpfTable, 1, value[0] + 1, value[1] + 1);
TableTools.mergeCellsVertically(xwpfTable, 4, value[0] + 1, value[1] + 1);
@@ -94,7 +94,7 @@ public class BuildHomeKpiWriteController {
buildHomeKpiWriteService.exportDocx(id, os);
// 下载生成的文件
CommonDownloadUtil.download(
"南京邮电大学分工会教职工之家建设考核评议自评表.docx",
"中国地质大学分工会教职工之家建设考核评议自评表.docx",
os.toByteArray(),
response
);
@@ -136,7 +136,7 @@ public class BuildHomeLogBookController {
template.render(map).writeAndClose(os);
// 下载生成的文件
CommonDownloadUtil.download(
"南京邮电大学分工会建家记录册.docx",
"中国地质大学分工会建家记录册.docx",
os.toByteArray(),
response
);
@@ -2,6 +2,7 @@ package com.budwk.app.zhgh.dayofficework.buildHome.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result;
@@ -104,8 +105,13 @@ public class BuildHomeMaterialQueryController {
}
@At
@Ok("void")
@SaCheckPermission("buildHome.material.query")
public void exportZip(String actId, HttpServletResponse response) throws IOException {
BuildHomeAct act = buildHomeActService.fetch(actId);
if (act == null) {
throw new IllegalArgumentException("未找到评比事项");
}
Sql sql = Sqls.create("""
SELECT
t1.id,
@@ -123,7 +129,6 @@ public class BuildHomeMaterialQueryController {
AND t2.actId = @actId
LEFT JOIN build_home_act t3 ON t3.id = t2.actId
AND t3.id = @actId
WHERE t1.id = '3742a919fb6847f7a8dbe051a2ef0025'
GROUP BY
t1.id,
t2.unionId
@@ -135,7 +140,9 @@ public class BuildHomeMaterialQueryController {
// 2. 设置响应头
response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachment; filename=\"工会文件汇总.zip\"");
// 使用评比事项名称作为压缩包名称避免下载文件无法区分来源
String zipFileName = sanitizeFileName(act.getName()) + "汇总材料.zip";
response.setHeader("Content-Disposition", "attachment; filename=" + URLUtil.encode(zipFileName));
// 3. 使用try-with-resources创建ZIP输出流
try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) {
@@ -164,6 +171,18 @@ public class BuildHomeMaterialQueryController {
}
/**
* 清理评比事项名称中的 Windows 文件名非法字符确保浏览器可正常保存压缩包
*
* @param fileName 原始评比事项名称
* @return 可用于下载文件名的评比事项名称
*/
private String sanitizeFileName(String fileName) {
String sanitizedFileName = StrUtil.blankToDefault(fileName, "评比事项");
return sanitizedFileName.replaceAll("[\\\\/:*?\"<>|]", "_");
}
private void processFileList(ZipOutputStream zos, String unionName, String fileType, String filesJson) throws IOException {
if (StrUtil.isNotBlank(filesJson)) {
List<NutMap> files = Json.fromJsonAsList(NutMap.class, filesJson);
@@ -110,7 +110,9 @@ public class CadreTrainingMineController {
cnd.where().andLike(CadreTrainingAct::getName, pageForm.getSearchKeyword());
}
cnd.desc("info.applyTime");
cnd.and("info.userId", "=", SecurityUtil.getUserId());
// 本人报名和本人代他人报名的记录都应在我的报名中展示
cnd.and(Cnd.exps("info.userId", "=", SecurityUtil.getUserId())
.or("info.applyUserId", "=", SecurityUtil.getUserId()));
sql.setCondition(cnd);
Pagination<NutMap> pagination = cadreTrainingSignUpService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
return Result.success(pagination);
@@ -67,8 +67,9 @@ public class CadreTrainingSignUpController {
@SaCheckPermission("cadreTraining.branchUnionSignUp")
@ApiOperation("分页查询")
public Result pageData(@Valid PageForm pageForm,Integer year, boolean isEnrolled) {
// 同一活动存在多条代报名记录时活动列表仅展示一次
Sql sql = Sqls.create("""
SELECT
SELECT DISTINCT
info.*,
CASE WHEN cts.id IS NOT NULL THEN 1 ELSE 0 END AS isEnrolled
FROM
@@ -101,6 +102,9 @@ public class CadreTrainingSignUpController {
List<ProcessInstance> instances = new ArrayList<>();
for (CadreTrainingSignUp signUp : cadreTrainingSignUps) {
// 代报名记录必须以当前登录人为报名操作人已报名我的报名按操作人查询
signUp.setApplyUserId(SecurityUtil.getUserId());
signUp.setApplyUserUserName(SecurityUtil.getUserUsername());
if (StrUtil.isBlank(signUp.getId())) {
signUp.setApplyTime(new Date());
}
@@ -79,21 +79,27 @@ public class HonorSummaryController {
@At
@SaCheckPermission("honor.honorLevel.Summary")
public Result honorLevelData(HonorPageForm pageForm) {
List<HonorBasicSettings> query = dao.query(HonorBasicSettings.class, Cnd.where("queryTypeCode", "in",
List.of(HonorTypeOrigin.HONOR_SCHOOL_LEVEL.name(), HonorTypeOrigin.HONOR_PROVINCIAL_LEVEL.name(), HonorTypeOrigin.HONOR_NATIONAL_LEVEL.name())));
String schoolHonorId = query.stream().filter(v->v.getQueryTypeCode().equals(HonorTypeOrigin.HONOR_SCHOOL_LEVEL.name())).findFirst().orElse(new HonorBasicSettings()).getId();
String provincialHonorId = query.stream().filter(v->v.getQueryTypeCode().equals(HonorTypeOrigin.HONOR_PROVINCIAL_LEVEL.name())).findFirst().orElse(new HonorBasicSettings()).getId();
String nationalHonorId = query.stream().filter(v->v.getQueryTypeCode().equals(HonorTypeOrigin.HONOR_NATIONAL_LEVEL.name())).findFirst().orElse(new HonorBasicSettings()).getId();
HonorBasicSettings levelRoot = dao.fetch(HonorBasicSettings.class,
Cnd.where("queryTypeCode", "=", HonorTypeOrigin.HONOR_LEVEL.name()));
List<HonorBasicSettings> levelList = levelRoot == null ? List.of() : dao.query(HonorBasicSettings.class,
Cnd.where("parentId", "=", levelRoot.getId()));
String schoolHonorId = levelList.stream().filter(item -> "校内".equals(item.getName()))
.findFirst().orElse(new HonorBasicSettings()).getId();
String provincialHonorId = levelList.stream().filter(item -> "省部级".equals(item.getName()))
.findFirst().orElse(new HonorBasicSettings()).getId();
String nationalHonorId = levelList.stream().filter(item -> "国家级".equals(item.getName()))
.findFirst().orElse(new HonorBasicSettings()).getId();
Cnd cnd = Cnd.NEW();
// honor.honorLevel 直接保存荣誉等级项 ID荣誉等级下的具体等级项统计
// 历史荣誉记录可能未保存 unionId统计时仅在 unionId 为空时按 unionName 回退关联
Sql sql = Sqls.create("""
SELECT
id,
name as unionname,
( SELECT COUNT( 1 ) FROM honor h WHERE h.honorLevel = @nationalLevel AND h.unionId = un.id $cnd) nationalLevelNum,
( SELECT COUNT( 1 ) FROM honor h WHERE h.honorLevel = @provincial AND h.unionId = un.id $cnd) provincialNum ,
( SELECT COUNT( 1 ) FROM honor h WHERE h.honorLevel = @schoolLevel AND h.unionId = un.id $cnd) schoolLevelNum
( SELECT COUNT( 1 ) FROM honor h WHERE h.honorLevel = @nationalLevel AND (h.unionId = un.id OR ((h.unionId IS NULL OR h.unionId = '') AND h.unionName = un.name)) $cnd) nationalLevelNum,
( SELECT COUNT( 1 ) FROM honor h WHERE h.honorLevel = @provincial AND (h.unionId = un.id OR ((h.unionId IS NULL OR h.unionId = '') AND h.unionName = un.name)) $cnd) provincialNum ,
( SELECT COUNT( 1 ) FROM honor h WHERE h.honorLevel = @schoolLevel AND (h.unionId = un.id OR ((h.unionId IS NULL OR h.unionId = '') AND h.unionName = un.name)) $cnd) schoolLevelNum
FROM
sys_union un $condition
""").setParam("nationalLevel", nationalHonorId).setParam("provincial", provincialHonorId).setParam("schoolLevel", schoolHonorId);
@@ -163,17 +163,17 @@ public class MeetingManageController {
cnd.andEX("u.unitId", "=", unitId);
cnd.and(Cnd.likeEX("u.sex", sex));
if (StrUtil.isNotBlank(roleId)) {
cnd.and(new Static("u.id in (select userId from sys_user_role where roleId = '%s')".formatted(roleId)));
cnd.and(new Static("u.id in (select userId from sys_user_role where roleId = '%s' and enable='1')".formatted(roleId)));
}
// 选择届次但未选择角色时按届次筛选全部相关人员同时选择角色时限定为同一角色关联记录
if (StrUtil.isBlank(roleId) && StrUtil.isNotBlank(teacherCongressSessionId)) {
cnd.and(new Static("u.id in (select userId from sys_user_role where tcSessionId = '%s')".formatted(teacherCongressSessionId)));
cnd.and(new Static("u.id in (select userId from sys_user_role where enable='1' and tcSessionId = '%s')".formatted(teacherCongressSessionId)));
}
if (StrUtil.isNotBlank(roleId) && StrUtil.isNotBlank(teacherCongressSessionId)) {
cnd.and(new Static("u.id in (select userId from sys_user_role where roleId = '%s' and tcSessionId = '%s')".formatted(roleId, teacherCongressSessionId)));
cnd.and(new Static("u.id in (select userId from sys_user_role where roleId = '%s' and enable='1' and tcSessionId = '%s')".formatted(roleId, teacherCongressSessionId)));
}
if (StrUtil.isNotBlank(roleId) && StrUtil.isNotBlank(workerCongressSessionId)) {
cnd.and(new Static("u.id in (select userId from sys_user_role where roleId = '%s' and wcSessionId = '%s')".formatted(roleId, workerCongressSessionId)));
cnd.and(new Static("u.id in (select userId from sys_user_role where roleId = '%s' and enable='1' and wcSessionId = '%s')".formatted(roleId, workerCongressSessionId)));
}
if (Strings.isNotBlank(pageForm.getSearchName()) && Strings.isNotBlank(pageForm.getSearchKeyword())) {
cnd.and(pageForm.getSearchName(), "like", "%" + pageForm.getSearchKeyword() + "%");
@@ -115,8 +115,10 @@ public class MeetingOnlineController {
@At("/getRealTimeData/?")
@Ok("json:full")
@SaCheckLogin
public Result getRealTimeData(String timePeriodId) {
List<MeetingTimePeriodUser> signInUser = onlineService.getSignInUser(timePeriodId);
public Result getRealTimeData(String timePeriodId,
@Param(value = "signRankOrder") String signRankOrder) {
// 签到人员排序统一交由Service处理控制器只负责接收前端排序方向并返回实时数据
List<MeetingTimePeriodUser> signInUser = onlineService.getSignInUser(timePeriodId, signRankOrder);
List<Map<String, Object>> countData = onlineService.getRealTimeData(timePeriodId);
return Result.success(Map.of("countData", countData, "userData", signInUser));
}
@@ -18,6 +18,15 @@ import java.util.Map;
public interface MeetingOnlineService extends BaseService<MeetingInfo> {
List<MeetingTimePeriodUser> exportSignature(String timePeriodId);
List<MeetingTimePeriodUser> getSignInUser(String timePeriodId);
/**
* 查询指定会议时段的签到人员并根据签到名次要求排序
*
* @param timePeriodId 会议时段ID
* @param signRankOrder 签到名次排序方向ascending为升序其他值按降序处理
* @return 已签到人员列表
*/
List<MeetingTimePeriodUser> getSignInUser(String timePeriodId, String signRankOrder);
List<Map<String, Object>> getRealTimeData(String timePeriodId);
}
@@ -70,13 +70,16 @@ public class MeetingOnlineServiceImpl extends BaseServiceImpl<MeetingInfo> imple
}
@Override
public List<MeetingTimePeriodUser> getSignInUser(String timePeriodId) {
return dao().query(
MeetingTimePeriodUser.class,
Cnd.where(MeetingTimePeriodUser::getTimePeriodId, "=", timePeriodId)
.and(MeetingTimePeriodUser::getSignStatus, "=", true)
.desc("signTime")
);
public List<MeetingTimePeriodUser> getSignInUser(String timePeriodId, String signRankOrder) {
Cnd cnd = Cnd.where(MeetingTimePeriodUser::getTimePeriodId, "=", timePeriodId)
.and(MeetingTimePeriodUser::getSignStatus, "=", true);
// 签到名次由签到时间确定只识别固定方向参数禁止将前端排序内容直接拼接到SQL中
if ("ascending".equals(signRankOrder)) {
cnd.asc("signTime");
} else {
cnd.desc("signTime");
}
return dao().query(MeetingTimePeriodUser.class, cnd);
}
@Override
@@ -133,7 +136,8 @@ public class MeetingOnlineServiceImpl extends BaseServiceImpl<MeetingInfo> imple
Sys_role formalRole = roleService.getByCode(formalRoleCode);
Sys_role attendanceRole = roleService.getByCode(attendanceRoleCode);
List<String> signedInUserIds = getSignInUser(timePeriodId).stream()
// 代表签到统计只关心已签到人员集合使用默认降序查询即可
List<String> signedInUserIds = getSignInUser(timePeriodId, "descending").stream()
.map(MeetingTimePeriodUser::getUserId)
.filter(Objects::nonNull)
.toList();
@@ -0,0 +1,31 @@
package com.budwk.app.zhgh.dayofficework.outlay.outlayManage.service;
import com.budwk.app.base.service.BaseService;
import org.nutz.lang.util.NutMap;
/**
* 分工会预算统计服务
*
* <p>统一封装分工会预算使用情况和经费收支情况的全量汇总查询
* 汇总口径与列表查询保持一致不受分页参数影响</p>
*/
public interface OutlayManageUnionStatisticsService extends BaseService {
/**
* 查询分工会预算使用情况的全量合计
*
* @param year 统计年度
* @param unionId 分工会主键管理员可为空查询全部
* @return 包含 totalQuotausedQuotasurplusQuota 的合计数据
*/
NutMap queryUseDetailSummary(Integer year, String unionId);
/**
* 查询分工会经费收支使用情况的全量合计
*
* @param year 统计年度
* @param unionId 分工会主键管理员可为空查询全部
* @return 包含各项收入支出和余额字段的合计数据
*/
NutMap queryIncomeExpenseSummary(Integer year, String unionId);
}
@@ -0,0 +1,104 @@
package com.budwk.app.zhgh.dayofficework.outlay.outlayManage.service.impl;
import cn.hutool.core.date.DateUtil;
import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.web.commons.auth.utils.AuthUtil;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.service.OutlayManageUnionStatisticsService;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.util.NutMap;
/**
* 分工会预算统计服务实现
*
* <p>汇总查询在数据库端完成避免只汇总当前分页数据
* 同时复用列表的年度分工会和权限过滤条件</p>
*/
@IocBean(args = {"refer:dao"})
public class OutlayManageUnionStatisticsServiceImpl extends BaseServiceImpl implements OutlayManageUnionStatisticsService {
public OutlayManageUnionStatisticsServiceImpl(Dao dao) {
super(dao);
}
@Override
public NutMap queryUseDetailSummary(Integer year, String unionId) {
Cnd cnd = buildUnionManageCondition(year, unionId, false);
Sql sql = Sqls.create("""
SELECT
COALESCE(SUM(totalQuota), 0) AS totalQuota,
COALESCE(SUM(usedQuota), 0) AS usedQuota,
COALESCE(SUM(COALESCE(totalQuota, 0) - COALESCE(usedQuota, 0)), 0) AS surplusQuota
FROM outlay_manage_union mu $condition
""");
sql.setCondition(cnd);
return executeMap(sql);
}
@Override
public NutMap queryIncomeExpenseSummary(Integer year, String unionId) {
Cnd cnd = buildUnionManageCondition(year, unionId, true);
Sql sql = Sqls.create("""
SELECT
COALESCE(SUM(t.beginMoney), 0) AS beginMoney,
COALESCE(SUM(t.feeJanApr), 0) AS feeJanApr,
COALESCE(SUM(t.feeMayAug), 0) AS feeMayAug,
COALESCE(SUM(t.feeSepDec), 0) AS feeSepDec,
COALESCE(SUM(t.awardMoney), 0) AS awardMoney,
COALESCE(SUM(t.usedMoney), 0) AS usedMoney,
COALESCE(SUM(t.remainMoney), 0) AS remainMoney
FROM (
SELECT
mu.unionId,
COALESCE(SUM(CASE WHEN au.quarterly = 1 THEN au.allocateHeadMoney ELSE 0 END), 0) AS beginMoney,
COALESCE(SUM(CASE WHEN au.quarterly = 1 THEN au.allocateMoney ELSE 0 END), 0) AS feeJanApr,
COALESCE(SUM(CASE WHEN au.quarterly = 2 THEN au.allocateMoney ELSE 0 END), 0) AS feeMayAug,
COALESCE(SUM(CASE WHEN au.quarterly = 3 THEN au.allocateMoney ELSE 0 END), 0) AS feeSepDec,
COALESCE(SUM(CASE WHEN au.quarterly = 4 THEN au.allocateMoney ELSE 0 END), 0) AS awardMoney,
COALESCE(mu.usedQuota, 0) AS usedMoney,
COALESCE(mu.totalQuota, 0) - COALESCE(mu.usedQuota, 0) AS remainMoney
FROM outlay_manage_union mu
LEFT JOIN outlay_allocate_union au ON au.year = mu.year
AND au.unionId = mu.unionId
AND au.delFlag = 0
LEFT JOIN sys_union su ON su.id = mu.unionId
$condition
GROUP BY mu.year, mu.unionId, mu.usedQuota, mu.totalQuota
) t
""");
sql.setCondition(cnd);
return executeMap(sql);
}
/**
* 构造两个列表共用的预算主表过滤条件保证汇总和分页列表权限口径一致
*/
private Cnd buildUnionManageCondition(Integer year, String unionId, boolean includeDelFlag) {
Cnd cnd = Cnd.NEW();
if (includeDelFlag) {
cnd.and("mu.delFlag", "=", false);
}
cnd.and("mu.year", "=", year == null ? DateUtil.thisYear() : year);
cnd.and("mu.totalQuota", "IS NOT", null);
cnd.andEX("mu.unionId", "=", unionId);
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
cnd.and("mu.unionId", "=", SecurityUtil.getUnionId());
}
return cnd;
}
/**
* 执行单行统计查询并在无数据时返回各字段为零的结果方便前端直接展示
*/
private NutMap executeMap(Sql sql) {
sql.setCallback(Sqls.callback.map());
dao().execute(sql);
NutMap result = (NutMap) sql.getResult();
return result == null ? NutMap.NEW() : result;
}
}
@@ -14,6 +14,7 @@ import com.budwk.app.base.service.BaseService;
import com.budwk.app.base.utils.CommonDownloadUtil;
import com.budwk.app.web.commons.auth.utils.AuthUtil;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.service.OutlayManageUnionStatisticsService;
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.union.vo.OutlayUnionIncomeExpenseVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@@ -44,6 +45,8 @@ public class OutlayManageUnionIncomeExpenseController {
@Inject
private BaseService baseService;
@Inject
private OutlayManageUnionStatisticsService outlayManageUnionStatisticsService;
@At("")
@Ok("beetl:/platform/zhgh/dayofficework/outlay/outlayManage/union/incomeExpense/index.html")
@@ -60,6 +63,16 @@ public class OutlayManageUnionIncomeExpenseController {
return Result.success(pagination);
}
/**
* 查询当前筛选范围内全部分工会经费收支合计不受分页参数影响
*/
@At
@ApiOperation("查询经费收支合计")
@SaCheckPermission("outlay.outlayManage.union.incomeExpense")
public Result summary(Integer year, String unionId) {
return Result.success(outlayManageUnionStatisticsService.queryIncomeExpenseSummary(year, unionId));
}
@At
@Ok("void")
@ApiOperation("导出")
@@ -12,6 +12,7 @@ import com.budwk.app.web.commons.auth.utils.AuthUtil;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.model.OutlayUseDetail;
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.service.OutlayUseDetailService;
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.service.OutlayManageUnionStatisticsService;
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.union.model.OutLayAllocateUnion;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@@ -46,6 +47,8 @@ public class OutlayManageUnionUseDetailController {
private BaseService baseService;
@Inject
private OutlayUseDetailService outlayUseDetailService;
@Inject
private OutlayManageUnionStatisticsService outlayManageUnionStatisticsService;
@At("")
@Ok("beetl:/platform/zhgh/dayofficework/outlay/outlayManage/union/useDetail/index.html")
@@ -81,6 +84,16 @@ public class OutlayManageUnionUseDetailController {
return Result.success(pagination);
}
/**
* 查询当前筛选范围内全部分工会预算使用情况合计不受分页参数影响
*/
@At
@ApiOperation("查询预算使用情况合计")
@SaCheckPermission("outlay.outlayManage.union.useDetail")
public Result summary(Integer year, String unionId) {
return Result.success(outlayManageUnionStatisticsService.queryUseDetailSummary(year, unionId));
}
@At
@ApiOperation("某个分工会预算使用详情")
@@ -85,9 +85,12 @@ public class UnionReimburseCollectController {
@Param(value = "reimburseProject") String reimburseProject) {
Sql sql = Sqls.create("""
SELECT
info.*
info.*,
ins.id AS instanceId,
ins.processDefineId AS instanceProcessDefineId
FROM
union_reimburse info
LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id
$condition
""");
Cnd cnd = Cnd.NEW();
@@ -84,12 +84,26 @@ public class ProposalConfigUnitController {
u2.username AS unitLeader
FROM
proposal_undertake t1
LEFT JOIN sys_user_role sur1 ON sur1.underTakeId = t1.id
AND sur1.roleId = ( SELECT r.id FROM sys_role r WHERE r.CODE = @PROPOSAL_BRANCH_SCHOOL_LEADER )
LEFT JOIN sys_user u1 ON u1.id = sur1.userId
LEFT JOIN sys_user_role sur2 ON sur2.underTakeId = t1.id
AND sur2.roleId = ( SELECT r.id FROM sys_role r WHERE r.CODE = @PROPOSAL_UNIT_LEADER)
LEFT JOIN sys_user u2 ON u2.id = sur2.userId
LEFT JOIN (
SELECT
sur.underTakeId,
GROUP_CONCAT(DISTINCT u.username ORDER BY u.username SEPARATOR '、') AS username,
GROUP_CONCAT(DISTINCT u.loginname ORDER BY u.loginname SEPARATOR ',') AS loginname
FROM sys_user_role sur
LEFT JOIN sys_user u ON u.id = sur.userId
WHERE sur.roleId = (SELECT r.id FROM sys_role r WHERE r.CODE = @PROPOSAL_BRANCH_SCHOOL_LEADER)
GROUP BY sur.underTakeId
) u1 ON u1.underTakeId = t1.id
LEFT JOIN (
SELECT
sur.underTakeId,
GROUP_CONCAT(DISTINCT u.username ORDER BY u.username SEPARATOR '、') AS username,
GROUP_CONCAT(DISTINCT u.loginname ORDER BY u.loginname SEPARATOR ',') AS loginname
FROM sys_user_role sur
LEFT JOIN sys_user u ON u.id = sur.userId
WHERE sur.roleId = (SELECT r.id FROM sys_role r WHERE r.CODE = @PROPOSAL_UNIT_LEADER)
GROUP BY sur.underTakeId
) u2 ON u2.underTakeId = t1.id
$condition
""");
sql.setParam("PROPOSAL_BRANCH_SCHOOL_LEADER", RoleConstant.PROPOSAL_BRANCH_SCHOOL_LEADER.name());
@@ -121,7 +135,9 @@ public class ProposalConfigUnitController {
@SLog(tag = "提案", msg = "承办单位同步系统单位")
public Result syncSysUnit() {
Sql sql = Sqls.create("select code from proposal_undertake");
List<Sys_unit> sysUnits = dao.query(Sys_unit.class, Cnd.where(Sys_unit::getUnitcode, "not in", sql).and(Sys_unit::getUnitTypeCode, "=", 1));
// 三位单位编号即提案业务使用的二级单位不再叠加系统单位层级条件
List<Sys_unit> sysUnits = dao.query(Sys_unit.class, Cnd.where(Sys_unit::getUnitcode, "not in", sql)
.and("CHAR_LENGTH(TRIM(unitcode))", "=", 3));
List<ProposalUndertake> proposalUndertakes = sysUnits.stream().map(unit -> {
ProposalUndertake proposalUndertake = new ProposalUndertake();
proposalUndertake.setId(unit.getId());
@@ -1,6 +1,7 @@
package com.budwk.app.zhgh.democratic.proposal.controller.query;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.budwk.app.base.param.ExportTableColumns;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.result.Result;
import com.budwk.app.zhgh.democratic.proposal.param.ProposalQueryComprehensiveParam;
@@ -15,6 +16,7 @@ import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;
@@ -51,6 +53,23 @@ public class ProposalQueryCollectProgressController {
return Result.success(pagination);
}
/**
* 按征集进度页面筛选条件及当前可见字段导出 Excel
*
* @param pageForm 页面筛选和排序参数
* @param tableColumns 当前可见字段顺序即导出列顺序
* @param response HTTP 响应返回 XSSF Excel
*/
@At
@Ok("void")
@SaCheckPermission("proposal.query.collectProgress")
@ApiOperation(value = "自定义导出征集进度")
public void exportCustomAsExcel(@Valid @Param("pageForm") ProposalQueryComprehensiveParam pageForm,
@Param("tableColumns") ExportTableColumns[] tableColumns,
HttpServletResponse response) {
proposalCommonService.exportCollectProgressAsExcel(pageForm, tableColumns, response);
}
@At
@ApiOperation(value = "获取征集状态")
@SaCheckPermission("proposal.query.collectProgress")
@@ -1,21 +1,13 @@
package com.budwk.app.zhgh.democratic.proposal.controller.query;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.ExportTableColumns;
import com.budwk.app.base.result.Result;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.zhgh.democratic.proposal.controller.vo.ProposalInfoPageVO;
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.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.mvc.annotation.At;
@@ -24,9 +16,6 @@ import org.nutz.mvc.annotation.Param;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.util.Arrays;
import java.util.Map;
@IocBean
@At("/platform/proposal/query/comprehensive")
@Slf4j
@@ -34,25 +23,6 @@ import java.util.Map;
@Api(tags = "提案综合查询")
public class ProposalQueryComprehensiveController {
/**
* 综合查询表格允许排序的字段映射值为查询中的真实字段或安全别名
*/
private static final Map<String, String> COMPREHENSIVE_ORDER_COLUMNS = Map.ofEntries(
Map.entry("code", "info.code"),
Map.entry("name", "info.name"),
Map.entry("createUserName", "info.createUserName"),
Map.entry("typeName", "typeName"),
Map.entry("delegationName", "delegationName"),
Map.entry("caseFilingResult", "info.caseFilingResult"),
Map.entry("caseFilingType", "info.caseFilingType"),
Map.entry("merge", "merge"),
Map.entry("undertakeUnits", "undertakeUnitsOrder"),
Map.entry("curTaskName", "curTaskName"),
Map.entry("instanceState", "instanceState")
);
@Inject
private BaseService baseService;
@Inject
private ProposalCommonService proposalCommonService;
@@ -66,84 +36,24 @@ public class ProposalQueryComprehensiveController {
@SaCheckPermission("proposal.query.comprehensive")
@ApiOperation(value = "分页列表")
public Result pageData(@Valid @Param("pageForm") ProposalQueryComprehensiveParam pageForm) {
Sql sql = Sqls.create("""
SELECT
info.*,
IF(mer.proposalId IS NOT NULL, 1, 0) AS merge,
type.name AS typeName,
tcs.fullName AS sessionName,
tcd.`name` AS delegationName,
ins.id AS instanceId,
ins.businessNo,
ins.state instanceState,
ins.variable instanceVariable,
ins.processDefineId instanceProcessDefineId,
t.displayName curTaskName,
GROUP_CONCAT(DISTINCT CASE WHEN pru.isMaster = 1 THEN pru.unitName END) AS masterUnitName,
GROUP_CONCAT(DISTINCT CASE WHEN pru.isMaster = 0 THEN pru.unitName END) AS slaveUnitNames,
GROUP_CONCAT(DISTINCT pru.unitName ORDER BY pru.isMaster DESC, pru.unitName) AS undertakeUnitsOrder
FROM
proposal_info info
LEFT JOIN proposal_type type on type.id = info.typeId
LEFT JOIN proposal_merge mer ON mer.proposalId = info.id
LEFT JOIN teacher_congress_session tcs on tcs.id = info.sessionId
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 proposal_reply_unit pru ON pru.proposalId = info.id
LEFT JOIN wf_process_task replyTask on replyTask.processInstanceId = ins.id
$condition
""");
// AND replyTask.taskState = 20 AND replyTask.taskName in ('master_reply','slave_reply','opinion_master_reply')
Cnd cnd = Cnd.NEW();
if (ArrayUtil.isNotEmpty(pageForm.getOrigins()) && StrUtil.isNotBlank(pageForm.getCommonKeyword())) {
SqlExpressionGroup seg = new SqlExpressionGroup();
return Result.success(proposalCommonService.queryComprehensive(pageForm));
}
// 案名
if (ArrayUtil.contains(pageForm.getOrigins(), "name")) {
for (String keyword : pageForm.getCommonKeyword().split(" ")) {
seg.orLike("info.name", keyword);
}
}
// 案由
if (ArrayUtil.contains(pageForm.getOrigins(), "brief")) {
for (String keyword : pageForm.getCommonKeyword().split(" ")) {
seg.orLike("info.brief", keyword);
}
}
// 提案人
if (ArrayUtil.contains(pageForm.getOrigins(), "createUserName")) {
for (String keyword : pageForm.getCommonKeyword().split(" ")) {
seg.orLike("info.createUserName", keyword);
seg.orLike("info.createUserLoginName", keyword);
}
}
// 答复内容
if (ArrayUtil.contains(pageForm.getOrigins(), "answer")) {
for (String keyword : pageForm.getCommonKeyword().split(" ")) {
seg.orLike("JSON_EXTRACT(replyTask.variable,'$.tf_opinion')", keyword);
}
}
if (!seg.isEmpty()) {
cnd.and(seg);
}
}
if (StrUtil.isNotBlank(pageForm.getUnderTakeUnitId())) {
cnd.andEX("pru.unitId", "=", pageForm.getUnderTakeUnitId());
}
ProposalQueryComprehensiveParam.buildSearch(cnd, pageForm);
cnd.groupBy("info.id");
// 综合查询包含多表字段及聚合别名只允许白名单字段进入排序条件
proposalCommonService.applySafePageOrder(cnd, pageForm, COMPREHENSIVE_ORDER_COLUMNS);
sql.setCondition(cnd);
Pagination pagination = baseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
return Result.success(pagination);
/**
* 按综合查询页面当前筛选条件和列设置导出 Excel
*
* @param pageForm 页面筛选及排序参数
* @param tableColumns 列设置中当前可见的字段顺序即 Excel 列顺序
* @param response HTTP 响应返回 XSSF 格式的 Excel 文件
*/
@At
@Ok("void")
@SaCheckPermission("proposal.query.comprehensive")
@ApiOperation(value = "自定义导出综合查询列表")
public void exportCustomAsExcel(@Valid @Param("pageForm") ProposalQueryComprehensiveParam pageForm,
@Param("tableColumns") ExportTableColumns[] tableColumns,
HttpServletResponse response) {
proposalCommonService.exportComprehensiveAsExcel(pageForm, tableColumns, response);
}
@At
@@ -1,14 +1,11 @@
package com.budwk.app.zhgh.democratic.proposal.controller.query;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.ExportTableColumns;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.sys.models.Sys_dict;
import com.budwk.app.sys.services.SysDictService;
import com.budwk.app.web.commons.auth.utils.AuthUtil;
import com.budwk.app.zhgh.democratic.proposal.param.ProposalSearchParam;
import com.budwk.app.zhgh.democratic.proposal.service.common.ProposalCommonService;
import io.swagger.annotations.Api;
@@ -21,10 +18,10 @@ import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.util.Map;
@IocBean
@@ -34,15 +31,6 @@ import java.util.Map;
@Api(tags = "代表团提案统计")
public class ProposalQueryDelegationController {
/**
* 代表团汇总表固定列的安全排序映射动态立案结果列在查询时追加
*/
private static final Map<String, String> DELEGATION_SUMMARY_ORDER_COLUMNS = Map.of(
"dbtName", "dbt.name",
"TOTAL", "TOTAL",
"caseRate", "caseRateOrder"
);
/**
* 代表团提案明细表允许排序的字段映射
*/
@@ -62,10 +50,6 @@ public class ProposalQueryDelegationController {
@Inject
private ProposalCommonService proposalCommonService;
@Inject
private SysDictService sysDictService;
@At("")
@Ok("beetl:/platform/zhgh/democratic/proposal/query/delegation/index.html")
@SaCheckPermission("proposal.query.delegation")
@@ -77,48 +61,26 @@ 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
dbt.id,
dbt.`name` AS dbtName,
(select count(1) from proposal_info info where info.delegationId = dbt.id and info.sessionId = dbt.sessionId ) as TOTAL,
(select count(1) from proposal_info info where info.delegationId = dbt.id and info.sessionId = dbt.sessionId and info.isSubmit = 1 ) as SUBMIT_COUNT
$resultSql,
(select count(1) from proposal_info info where info.delegationId = dbt.id and info.sessionId = dbt.sessionId and info.caseFilingResult = @confirmFiling)
/ NULLIF((select count(1) from proposal_info info where info.delegationId = dbt.id and info.sessionId = dbt.sessionId), 0) AS caseRateOrder
FROM
teacher_congress_delegation dbt
$condition
""");
Map<String, String> summaryOrderColumns = new HashMap<>(DELEGATION_SUMMARY_ORDER_COLUMNS);
List<String> resultSqlParts = new ArrayList<>();
for (Sys_dict dict : dictList) {
String resultCode = dict.getCode();
// 动态别名和立案结果编码仅允许字母数字和下划线变量替换后新增的 @ 参数不会被 Nutz 再次解析
// 因此这里使用已校验的字典编码字面量确保统计条件能正确传递给数据库
if (StrUtil.isBlank(resultCode) || !resultCode.matches("[A-Za-z0-9_]+")) {
continue;
}
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));
sql.setParam("confirmFiling", "CONFIRM_FILING");
Cnd cnd = Cnd.NEW();
cnd.andEX("dbt.sessionId", "=", sessionId);
if (!AuthUtil.hasRoleOr("SYSADMIN", "SCHOOL_UNION_ADMIN")) {
}
// 未选择排序时保留原有代表团编码升序选择后仅应用白名单字段
if (!proposalCommonService.applySafePageOrder(cnd, pageForm, summaryOrderColumns)) {
cnd.asc("dbt.`code`");
}
sql.setCondition(cnd);
return Result.success(baseService.listMap(sql));
return Result.success(proposalCommonService.queryDelegationStatistics(pageForm, sessionId));
}
/**
* 按当前届次排序及页面可见字段导出代表团统计
*
* @param pageForm 页面排序参数
* @param sessionId 教代会届次ID
* @param tableColumns 当前可见字段
* @param response HTTP 响应返回 XSSF Excel
*/
@At
@Ok("void")
@ApiOperation("自定义导出代表团提案统计")
@SaCheckPermission("proposal.query.delegation")
public void exportCustomAsExcel(@Valid @Param("pageForm") PageForm pageForm,
@Param("sessionId") String sessionId,
@Param("tableColumns") ExportTableColumns[] tableColumns,
HttpServletResponse response) {
proposalCommonService.exportDelegationStatisticsAsExcel(pageForm, sessionId, tableColumns, response);
}
@@ -1,28 +1,19 @@
package com.budwk.app.zhgh.democratic.proposal.controller.query;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.budwk.app.base.param.ExportTableColumns;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result;
import com.budwk.app.flow.engine.util.FlowUtil;
import com.budwk.app.flow.entity.ProcessTask;
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
import com.budwk.app.zhgh.democratic.proposal.models.ProposalConfig;
import com.budwk.app.zhgh.democratic.proposal.models.ProposalInfo;
import com.budwk.app.zhgh.democratic.proposal.models.ProposalReplyUnit;
import com.budwk.app.zhgh.democratic.proposal.service.common.ProposalCommonService;
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.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import java.util.*;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
/**
* 承办单位办理统计
@@ -33,16 +24,6 @@ import java.util.stream.Collectors;
@Ok("json:full")
public class ProposalQueryUnitReplyController {
/**
* 承办单位办理统计允许排序的字段白名单
*/
private static final Set<String> UNIT_REPLY_ORDER_COLUMNS = Set.of(
"unitName", "sum", "masterSum", "masterReplySum", "masterNoReplySum",
"slaveSum", "slaveReplySum", "slaveNoReplySum"
);
@Inject
private Dao dao;
@Inject
private ProposalCommonService proposalCommonService;
@@ -64,94 +45,30 @@ public class ProposalQueryUnitReplyController {
* caseFilingResult立案结果字典值对应 proposal_info.caseFilingResult为空时不限制立案结果
* 返回值Result.data 中包含 tableData 统计行列表以及 slaveNeedReply 协办单位是否需要答复配置
*/
// 提案配置 协办是否需要答复
ProposalConfig proposalConfig = dao.fetch(ProposalConfig.class, Cnd.NEW());
boolean slaveNeedReply = proposalConfig.getSlaveUnitNeedReply();
return Result.success().addData(proposalCommonService.queryUnitReplyStatistics(
pageForm, sessionId, undertakeUnitId, caseFilingResult));
}
// 当前届次所有的提案ID
Cnd proposalCnd = Cnd.where(ProposalInfo::getSessionId, "=", sessionId);
proposalCnd.andEX(ProposalInfo::getCaseFilingResult, "=", caseFilingResult);
List<String> proposalIds = dao.query(ProposalInfo.class, proposalCnd)
.stream()
.map(ProposalInfo::getId)
.collect(Collectors.toList());
if(proposalIds.isEmpty()){
return Result.success().addData(Map.of("tableData", Collections.EMPTY_LIST, "slaveNeedReply", slaveNeedReply));
}
// 关联所有的实例ID
Sql instSql = Sqls.create("select id from wf_process_instance where businessNo in (@proposalIds)");
instSql.setParam("proposalIds", proposalIds);
instSql.setCallback(Sqls.callback.strList());
dao.execute(instSql);
List<String> instIds = instSql.getList(String.class);
// 提案委员会立案分配的承办单位
Cnd cnd = Cnd.where(ProposalReplyUnit::getProposalId, "in", proposalIds);
cnd.andEX(ProposalReplyUnit::getUnitId, "=", undertakeUnitId);
List<ProposalReplyUnit> replyUnits = dao.query(ProposalReplyUnit.class, cnd);
// 承办单位答复记录
List<ProcessTask> replyTasks = dao.query(ProcessTask.class, Cnd.where(ProcessTask::getProcessInstanceId, "in", instIds).and(ProcessTask::getTaskName, "in", List.of("two_unit_reply","unit_reply","master_reply", "slave_reply", "opinion_master_reply")).and(ProcessTask::getTaskState, "in", List.of(ProcessTaskStateEnum.FINISHED.getCode(), ProcessTaskStateEnum.DOING.getCode())));
// 承办单位
List<NutMap> tableData = new ArrayList<>();
replyUnits.stream().collect(Collectors.groupingBy(ProposalReplyUnit::getUnitCode)).forEach((k, v) -> {
NutMap tableRow = NutMap.NEW();
tableRow.put("id", k);
v.stream().findAny().ifPresent(item -> {
tableRow.put("unitName", item.getUnitName());
tableRow.put("unitCode", item.getUnitCode());
});
// 提案总数
tableRow.put("sum", v.size());
// 主办提案数
tableRow.put("masterSum", v.stream().filter(unit -> Objects.equals(unit.getUnitCode(), k) && unit.getIsMaster()).count());
// 协办提案数
tableRow.put("slaveSum", v.stream().filter(unit -> Objects.equals(unit.getUnitCode(), k) && !unit.getIsMaster()).count());
// 主办提案已答复数
long masterReplySum = replyTasks.stream().filter(x ->
FlowUtil.variableToNutMap(x.getVariable()).getString("underTakeId", "").equals(k)
&& FlowUtil.variableToNutMap(x.getVariable()).getBoolean("underTakeIsMaster")
&& x.getTaskState().equals(ProcessTaskStateEnum.FINISHED.getCode())
).map(ProcessTask::getProcessInstanceId).distinct().count();
// 主办提案未答复数
long masterNoReplySum = replyTasks.stream().filter(x ->
FlowUtil.variableToNutMap(x.getVariable()).getString("underTakeId", "").equals(k)
&& FlowUtil.variableToNutMap(x.getVariable()).getBoolean("underTakeIsMaster")
&& x.getTaskState().equals(ProcessTaskStateEnum.DOING.getCode())
).map(ProcessTask::getProcessInstanceId).distinct().count();
// 协办提案已答复数
long slaveReplySum = replyTasks.stream().filter(x ->
FlowUtil.variableToNutMap(x.getVariable()).getString("underTakeId", "").equals(k)
&& !FlowUtil.variableToNutMap(x.getVariable()).getBoolean("underTakeIsMaster")
&& x.getTaskState().equals(ProcessTaskStateEnum.FINISHED.getCode())
).map(ProcessTask::getProcessInstanceId).distinct().count();
// 协办提案未答复数
long slaveNoReplySum = replyTasks.stream().filter(x ->
FlowUtil.variableToNutMap(x.getVariable()).getString("underTakeId", "").equals(k)
&& !FlowUtil.variableToNutMap(x.getVariable()).getBoolean("underTakeIsMaster")
&& x.getTaskState().equals(ProcessTaskStateEnum.DOING.getCode())
).map(ProcessTask::getProcessInstanceId).distinct().count();
tableRow.put("masterReplySum", masterReplySum);
tableRow.put("masterNoReplySum", masterNoReplySum);
tableRow.put("slaveReplySum", slaveReplySum);
tableRow.put("slaveNoReplySum", slaveNoReplySum);
tableData.add(tableRow);
});
// 统计结果生成后在服务层按白名单字段排序避免前端字段参与任意业务处理
proposalCommonService.sortStatisticsRows(tableData, pageForm, UNIT_REPLY_ORDER_COLUMNS);
return Result.success().addData(Map.of("tableData", tableData, "slaveNeedReply", slaveNeedReply));
/**
* 按当前筛选条件及页面可见字段导出承办单位办理统计
*
* @param pageForm 页面排序参数
* @param sessionId 教代会届次ID
* @param undertakeUnitId 承办单位ID
* @param caseFilingResult 立案结果编码
* @param tableColumns 当前可见字段
* @param response HTTP 响应返回 XSSF Excel
*/
@At
@Ok("void")
@SaCheckPermission("proposal.query.unitReply")
public void exportCustomAsExcel(@Valid @Param("pageForm") PageForm pageForm,
@Param("sessionId") String sessionId,
@Param("undertakeUnitId") String undertakeUnitId,
@Param("caseFilingResult") String caseFilingResult,
@Param("tableColumns") ExportTableColumns[] tableColumns,
HttpServletResponse response) {
proposalCommonService.exportUnitReplyStatisticsAsExcel(pageForm, sessionId, undertakeUnitId,
caseFilingResult, tableColumns, response);
}
}
@@ -35,6 +35,7 @@ public class ProposalQueryYearReportController {
*/
private static final Map<String, String> YEAR_REPORT_ORDER_COLUMNS = Map.ofEntries(
Map.entry("code", "info.code"),
Map.entry("caseFilingCode", "info.caseFilingCode"),
Map.entry("name", "info.name"),
Map.entry("createUserName", "info.createUserName"),
Map.entry("typeName", "typeName"),
@@ -1,31 +1,19 @@
package com.budwk.app.zhgh.democratic.proposal.controller.query;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.param.ExportTableColumns;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result;
import com.budwk.app.flow.engine.util.FlowUtil;
import com.budwk.app.flow.entity.ProcessInstance;
import com.budwk.app.flow.entity.ProcessTask;
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
import com.budwk.app.sys.models.Sys_dict;
import com.budwk.app.sys.services.SysDictService;
import com.budwk.app.zhgh.democratic.proposal.models.ProposalConfig;
import com.budwk.app.zhgh.democratic.proposal.models.ProposalReplyUnit;
import com.budwk.app.zhgh.democratic.proposal.service.common.ProposalCommonService;
import io.swagger.annotations.Api;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import java.util.*;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
@IocBean
@At("/platform/proposal/query/underTake/satisfaction")
@@ -33,17 +21,6 @@ import java.util.stream.Collectors;
@Api(tags = "提案承办单位满意度")
public class ProposalUnderTakeSatisfactionController {
/**
* 满意度统计固定列的排序白名单动态满意度列在查询时追加
*/
private static final Set<String> SATISFACTION_ORDER_COLUMNS = Set.of(
"unitName", "sum", "masterSum", "slaveSum"
);
@Inject
private Dao dao;
@Inject
private SysDictService sysDictService;
@Inject
private ProposalCommonService proposalCommonService;
@@ -65,80 +42,28 @@ public class ProposalUnderTakeSatisfactionController {
@At
@SaCheckPermission("proposal.query.underTake.satisfaction")
public Result data(PageForm pageForm, String sessionId, String undertakeUnitId) {
List<Sys_dict> feedbackCodes = sysDictService.getSubListByCode("PROPOSAL_FEEDBACK");
Set<String> orderColumns = new HashSet<>(SATISFACTION_ORDER_COLUMNS);
// 动态满意度列仅从后端字典加入白名单不接受前端自行扩展字段
feedbackCodes.stream()
.map(Sys_dict::getCode)
.filter(StrUtil::isNotBlank)
.forEach(orderColumns::add);
// 当前届次所有的提案ID
Sql sql = Sqls.create("select id from proposal_info where sessionId = @sessionId").setParam("sessionId", sessionId);
sql.setCallback(Sqls.callback.strList());
dao.execute(sql);
List<String> proposalIds = sql.getList(String.class);
if (proposalIds.isEmpty()) {
return Result.success(Collections.EMPTY_LIST);
}
// 关联所有的实例ID
Sql instSql = Sqls.create("select id from wf_process_instance where businessNo in (@proposalIds)");
instSql.setParam("proposalIds", proposalIds);
instSql.setCallback(Sqls.callback.strList());
dao.execute(instSql);
List<String> instIds = instSql.getList(String.class);
// 提案委员会立案分配的承办单位
Cnd cnd = Cnd.where(ProposalReplyUnit::getProposalId, "in", proposalIds);
cnd.andEX(ProposalReplyUnit::getUnitId, "=", undertakeUnitId);
List<ProposalReplyUnit> replyUnits = dao.query(ProposalReplyUnit.class, cnd);
// 反馈评分记录
// List<ProcessTask> feedbackTasks = dao.query(ProcessTask.class, Cnd.where(ProcessTask::getProcessInstanceId, "in", instIds)
// .and(ProcessTask::getTaskName, "=", "feedback")
// .and(ProcessTask::getTaskState, "=", ProcessTaskStateEnum.FINISHED.getCode()));
// 承办单位
List<NutMap> tableData = new ArrayList<>();
replyUnits.stream().collect(Collectors.groupingBy(ProposalReplyUnit::getUnitCode)).forEach((k, v) -> {
NutMap tableRow = NutMap.NEW();
tableRow.put("id", k);
v.stream().findAny().ifPresent(item -> {
tableRow.put("unitName", item.getUnitName());
tableRow.put("unitCode", item.getUnitCode());
});
// 提案总数
tableRow.put("sum", v.size());
// 主办提案数
tableRow.put("masterSum", v.stream().filter(unit -> Objects.equals(unit.getUnitCode(), k) && unit.getIsMaster()).count());
// 协办提案数
tableRow.put("slaveSum", v.stream().filter(unit -> Objects.equals(unit.getUnitCode(), k) && !unit.getIsMaster()).count());
// 该单位负责的提案
List<String> thisUnitProposalIds = v.stream().map(ProposalReplyUnit::getProposalId).toList();
List<ProcessInstance> instances = dao.query(ProcessInstance.class, Cnd.where(ProcessInstance::getBusinessNo, "in", thisUnitProposalIds));
List<Long> thisUnitInstIds = instances.stream().map(ProcessInstance::getId).toList();
// 反馈评分记录
List<ProcessTask> feedbackTasks = dao.query(ProcessTask.class, Cnd.where(ProcessTask::getProcessInstanceId, "in", thisUnitInstIds)
.and(ProcessTask::getTaskName, "=", "feedback")
.and(ProcessTask::getTaskState, "=", ProcessTaskStateEnum.FINISHED.getCode()));
for (Sys_dict code : feedbackCodes) {
long count = feedbackTasks.stream().filter(task -> FlowUtil.variableToNutMap(task.getVariable()).getString("tf_feedback", "").equals(code.getCode())).map(ProcessTask::getProcessInstanceId).distinct().count();
tableRow.put(code.getCode(), count);
}
tableData.add(tableRow);
});
// 汇总完成后在服务层执行白名单排序数字列按数值顺序处理
proposalCommonService.sortStatisticsRows(tableData, pageForm, orderColumns);
return Result.success(tableData);
return Result.success(proposalCommonService.queryUnderTakeSatisfactionStatistics(
pageForm, sessionId, undertakeUnitId));
}
/**
* 按当前届次承办单位和页面可见字段导出满意度统计
*
* @param pageForm 页面排序参数
* @param sessionId 教代会届次ID
* @param undertakeUnitId 承办单位ID
* @param tableColumns 当前可见字段
* @param response HTTP 响应返回 XSSF Excel
*/
@At
@Ok("void")
@SaCheckPermission("proposal.query.underTake.satisfaction")
public void exportCustomAsExcel(@Valid @Param("pageForm") PageForm pageForm,
@Param("sessionId") String sessionId,
@Param("undertakeUnitId") String undertakeUnitId,
@Param("tableColumns") ExportTableColumns[] tableColumns,
HttpServletResponse response) {
proposalCommonService.exportUnderTakeSatisfactionAsExcel(
pageForm, sessionId, undertakeUnitId, tableColumns, response);
}
}
@@ -101,7 +101,8 @@ public class ProposalExpeditingController {
$condition
""");
Cnd cnd = Cnd.NEW();
cnd.and("t.taskName", "in", List.of("master_reply", "slave_reply", "opinion_master_reply"));
// 催办列表只展示现行 WF 承办答复环节中尚未完成的主办二次答复及意见答复任务
cnd.and("t.taskName", "in", List.of("unit_reply", "two_unit_reply", "opinion_unit_reply"));
if (!AuthUtil.hasRole(RoleConstant.SYSADMIN.name()) && !AuthUtil.hasRole(RoleConstant.SCHOOL_UNION_ADMIN.name())) {
cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId()));
@@ -1,6 +1,7 @@
package com.budwk.app.zhgh.democratic.proposal.controller.transact;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaMode;
import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.ExportTableColumns;
@@ -55,8 +56,17 @@ public class ProposalCaseCheckController {
public void index() {
}
/**
* 打开提案委员会审查手机端列表页
*/
@At("/h5")
@Ok("beetl:/platform/zhghh5/democratic/proposal/transact/caseCheck/index.html")
@SaCheckPermission("h5.proposal.caseCheck")
public void h5Index() {
}
@At
@SaCheckPermission("proposal.caseCheck")
@SaCheckPermission(value = {"proposal.caseCheck", "h5.proposal.caseCheck"}, mode = SaMode.OR)
@ApiOperation("分页列表")
public Result pageData(@Valid ProposalSearchParam pageForm, boolean approval) {
Sql sql = Sqls.create("""
@@ -129,7 +139,7 @@ public class ProposalCaseCheckController {
}
@At
@SaCheckPermission("proposal.caseCheck")
@SaCheckPermission(value = {"proposal.caseCheck", "h5.proposal.caseCheck"}, mode = SaMode.OR)
@ApiOperation("查询当前提案承办单位")
public Result listReplyUnits(String proposalId) {
return Result.success(proposalCaseCheckService.listReplyUnits(proposalId));
@@ -49,7 +49,6 @@ public class ProposalCommissionerController {
public void h5Index() {
}
@At
@SaCheckPermission("proposal.commissioner")
public Result pageData(@Valid ProposalSearchParam pageForm, boolean approval) {
@@ -125,6 +125,17 @@ public class ProposalCommitteeFilingController {
proposalCommonService.exportWorkflowList("committeeFiling", pageForm, approval, tableColumns, response);
}
@At
@SaCheckPermission("proposal.committeeFiling")
@ApiOperation("执行单案立案审核任务")
@Aop(TransAop.READ_COMMITTED)
public Result executeTask(@Param("data") String data) {
// data 包含流程任务ID提交类型立案结果及主协办单位Service 校验负责人后执行 WF成功返回统一 Result
Dict args = Json.fromJson(Dict.class, data);
proposalCommitteeFilingService.executeFlowTask(args);
return Result.success();
}
@At
@SaCheckPermission("proposal.committeeFiling")
@ApiOperation("并案审核")
@@ -47,6 +47,7 @@ public class ProposalControlController {
@SaCheckPermission("proposal.control")
@ApiOperation("分页列表")
public Result pageData(@Valid ProposalSearchParam pageForm) {
// 状态调整属于提案业务只保留能够关联到 proposal_info WF 任务排除其他业务流程产生的空白行
Sql sql = Sqls.create("""
SELECT
info.*,
@@ -72,7 +73,7 @@ public class ProposalControlController {
LEFT JOIN wf_process_instance ins ON ins.id = t.processInstanceId
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = t.id
LEFT JOIN wf_process_task nt ON nt.processInstanceId = ins.id AND nt.taskState = 10
LEFT JOIN proposal_info info ON info.id = ins.businessNo
INNER JOIN proposal_info info ON info.id = ins.businessNo
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
@@ -4,7 +4,6 @@ import cn.dev33.satoken.annotation.SaCheckPermission;
import com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.ExportTableColumns;
import com.budwk.app.base.result.Result;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.bpm.enums.BpmProcessTaskStatusEnum;
@@ -30,10 +29,8 @@ import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import javax.validation.Valid;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
@@ -67,7 +64,6 @@ public class ProposalDelegationController {
public void h5Index() {
}
@At
@SaCheckPermission("proposal.delegation")
@ApiOperation("分页列表")
@@ -129,13 +125,4 @@ public class ProposalDelegationController {
return Result.success(pagination);
}
@At
@Ok("void")
@SaCheckPermission("proposal.delegation")
@ApiOperation("导出列表")
public void exportList(@Valid @Param("pageForm") ProposalSearchParam pageForm, boolean approval,
@Param("tableColumns") ExportTableColumns[] tableColumns, HttpServletResponse response) {
proposalCommonService.exportWorkflowList("delegation", pageForm, approval, tableColumns, response);
}
}
@@ -5,7 +5,6 @@ import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.ExportTableColumns;
import com.budwk.app.base.result.Result;
import com.budwk.app.flow.entity.ProcessTask;
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
@@ -27,7 +26,6 @@ import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import javax.validation.Valid;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
@IocBean
@@ -54,7 +52,6 @@ public class ProposalFeedbackEvaluationController {
public void h5Index() {
}
@At
@SaCheckPermission("proposal.feedbackEvaluation")
@ApiOperation("分页列表")
@@ -118,15 +115,6 @@ public class ProposalFeedbackEvaluationController {
return Result.success(pagination);
}
@At
@Ok("void")
@SaCheckPermission("proposal.feedbackEvaluation")
@ApiOperation("导出列表")
public void exportList(@Valid @Param("pageForm") ProposalSearchParam pageForm, boolean approval,
@Param("tableColumns") ExportTableColumns[] tableColumns, HttpServletResponse response) {
proposalCommonService.exportWorkflowList("feedbackEvaluation", pageForm, approval, tableColumns, response);
}
@At
@SaCheckPermission("proposal.feedbackEvaluation")
@ApiOperation("获取立案信息")
@@ -52,6 +52,11 @@ public class ProposalPreAuditController {
public void index() {
}
@At("/h5")
@Ok("beetl:/platform/zhghh5/democratic/proposal/transact/preAudit/index.html")
@SaCheckPermission("proposal.preAudit")
public void h5Index() {
}
@At
@SaCheckPermission("proposal.preAudit")
@@ -74,7 +74,6 @@ public class ProposalSchoolLeaderApprovalController {
public void h5Index() {
}
@At
@SaCheckPermission("proposal.schoolLeaderApproval")
@ApiOperation("分页列表")
@@ -134,6 +134,9 @@ public class ProposalSecondedController {
LEFT JOIN wf_process_instance ins ON ins.id = t.processInstanceId
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = t.id
LEFT JOIN wf_process_task nt ON nt.processInstanceId = ins.id AND nt.taskState = 10
LEFT JOIN wf_process_task dt ON dt.processInstanceId = ins.id
AND dt.taskName = 'delegation' AND dt.taskState = 20
AND (dt.variable ->> '$.submitType') IN ('1', '2')
LEFT JOIN wf_process_task rt ON rt.processInstanceId = ins.id AND rt.taskParentId = t.id AND rt.taskState = 10
LEFT JOIN proposal_info info ON info.id = ins.businessNo
LEFT JOIN proposal_second ps ON ps.proposalId = info.id AND ps.seconderId = @seconderId
@@ -157,6 +160,8 @@ public class ProposalSecondedController {
} else {
// 未附议页签只展示当前登录附议人尚未处理的记录
cnd.and("ps.isAgree", "is", null);
// 团长选择同意或不同意后均截止附议退回提案人不视为最终审核结果
cnd.and("dt.id", "is", null);
// 待附议列表只展示两类任务
// 1. invite / second 节点任务
// 2. delegation / committee 节点且任务状态必须是已废弃(99)
@@ -216,6 +221,9 @@ public class ProposalSecondedController {
if (Strings.isBlank(proposalId) || Strings.isBlank(taskActorUserId) || taskId == null || submitType == null) {
return Result.error("参数错误");
}
if (proposalSecondedService.isDelegationReviewed(proposalId)) {
return Result.error("团长已完成审核,当前提案不能继续附议");
}
// 先定位 wf_process_task确保本次请求能准确命中需要完成的附议任务再更新两张业务表
ProcessTask processTask = this.getSecondTask(taskId, taskActorUserId);
@@ -294,6 +302,9 @@ public class ProposalSecondedController {
if (args.getLong("processTaskId") == null || Strings.isBlank(proposalId) || Strings.isBlank(taskActorUserId) || submitType == null) {
return Result.error("参数错误");
}
if (proposalSecondedService.isDelegationReviewed(proposalId)) {
return Result.error("团长已完成审核,当前提案不能继续附议");
}
flowCommonService.executeTask(args);
proposalSecondedService.updateSecondRecord(proposalId, taskActorUserId, opinion, submitType);
return Result.success();
@@ -5,7 +5,6 @@ import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ObjectUtil;
import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.ExportTableColumns;
import com.budwk.app.base.result.Result;
import com.budwk.app.flow.entity.ProcessTask;
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
@@ -38,7 +37,6 @@ import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import javax.validation.Valid;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.List;
@@ -172,15 +170,6 @@ public class ProposalUnderTakeReplyController {
return Result.success(pagination);
}
@At
@Ok("void")
@SaCheckPermission("proposal.unitReply")
@ApiOperation("导出列表")
public void exportList(@Valid @Param("pageForm") ProposalSearchParam pageForm, boolean approval,
@Param("tableColumns") ExportTableColumns[] tableColumns, HttpServletResponse response) {
proposalCommonService.exportWorkflowList("unitReply", pageForm, approval, tableColumns, response);
}
/**
* 承办单位答复节点撤回需要基于整组当前节点判断
* 只有当前流程正在办理的节点这条列表记录所属节点完全一致时才允许撤回
@@ -73,6 +73,10 @@ public class ProposalCaseFilingInterceptor implements FlowInterceptor {
Dict dict = JSONUtil.toBean(processTask.getVariable(), Dict.class);
dict.set(FlowConst.TASK_FORM_DATA_PREFIX + "helpunitreply", helpUnitReply);
processTask.setVariable(JSONUtil.toJsonStr(dict));
dao.update(processTask);
/*
* 当前任务对象是在任务完成前加载的其中 finishTimeoperator 仍为空
* 这里只更新拦截器实际修改的流程变量避免整行更新覆盖 WF 已写入的办理时间和办理人
*/
dao.update(processTask, "variable");
}
}
@@ -12,6 +12,9 @@ import org.nutz.dao.interceptor.annotation.PrevInsert;
@Accessors(chain = true)
@Table("proposal_reply_unit")
@TableMeta("{'mysql-charset':'utf8mb4'}")
@TableIndexes({
@Index(name = "INDEX_PROPOSAL_REPLY_UNIT_PROPOSAL_UNIT", fields = {"proposalId", "unitId"}, unique = false)
})
@Comment("提案信息")
public class ProposalReplyUnit extends BaseModel {
@@ -19,6 +19,8 @@ public class ProposalQueryComprehensiveParam extends PageForm {
private String name;
@ApiModelProperty(name = "提案编号")
private String code;
@ApiModelProperty(name = "立案编号")
private String caseFilingCode;
@ApiModelProperty(name = "教代会ID")
private String sessionId;
@ApiModelProperty(name = "search session id")
@@ -61,15 +63,22 @@ public class ProposalQueryComprehensiveParam extends PageForm {
@ApiModelProperty(name = "通用关键字")
private String commonKeyword;
@ApiModelProperty(name = "提案名称或编号搜索字段,仅支持name、code、caseFilingCode")
private String proposalSearchField;
@ApiModelProperty(name = "提案名称或编号搜索内容")
private String proposalKeyword;
@ApiModelProperty(name = "搜索关键字")
private String createUserKeyword;
/**
* 构建通用查询参数
* 将综合查询参数追加到查询条件中无返回值处理结果直接写入 cnd
*
* @param cnd cnd
* @param searchParam searchParam
* @param cnd 查询条件容器用于接收届次名称/编号提案人组织及立案条件
* @param searchParam 页面查询参数proposalSearchField namecode caseFilingCode
* proposalKeyword 传对应字段的模糊搜索内容
*/
public static void buildSearch(Cnd cnd, ProposalQueryComprehensiveParam searchParam) {
if (cnd == null) {
@@ -84,6 +93,19 @@ public class ProposalQueryComprehensiveParam extends PageForm {
// Isolated single-session filter for pages that should not reuse sessionId semantics.
cnd.andEX("info.sessionId", "=", searchParam.getSearchSessionId());
// 名称/编号组合搜索仅允许三个固定字段前端提交值不能直接作为SQL字段使用
if (StrUtil.isNotBlank(searchParam.getProposalKeyword())) {
String proposalSearchColumn = switch (StrUtil.blankToDefault(searchParam.getProposalSearchField(), "name")) {
case "name" -> "info.name";
case "code" -> "info.code";
case "caseFilingCode" -> "info.caseFilingCode";
default -> null;
};
if (proposalSearchColumn != null) {
cnd.where().andLike(proposalSearchColumn, searchParam.getProposalKeyword());
}
}
//提案名称
if (StrUtil.isNotBlank(searchParam.getName())) {
cnd.where().andLike("info.name", searchParam.getName());
@@ -92,6 +114,10 @@ public class ProposalQueryComprehensiveParam extends PageForm {
if (StrUtil.isNotBlank(searchParam.getCode())) {
cnd.where().andLike("info.code", searchParam.getCode());
}
// 立案编号由立案环节生成支持按已生成编号进行模糊检索
if (StrUtil.isNotBlank(searchParam.getCaseFilingCode())) {
cnd.where().andLike("info.caseFilingCode", searchParam.getCaseFilingCode());
}
//代表团ID
cnd.andEX("info.delegationId", "=", searchParam.getDelegationId());
if (StrUtil.isNotBlank(searchParam.getCreateUserName())) {

Some files were not shown because too many files have changed in this diff Show More