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:
+2
@@ -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);
|
||||
|
||||
+10
-30
@@ -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)
|
||||
|
||||
+27
-1
@@ -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);
|
||||
|
||||
|
||||
+63
-3
@@ -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("""
|
||||
|
||||
+7
@@ -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);
|
||||
}
|
||||
|
||||
+9
-31
@@ -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);
|
||||
|
||||
|
||||
/**
|
||||
* 手机端分页查询
|
||||
|
||||
+54
-1
@@ -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();
|
||||
|
||||
+7
-23
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -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)
|
||||
|
||||
+1
@@ -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;
|
||||
|
||||
+11
@@ -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);
|
||||
}
|
||||
|
||||
+21
@@ -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"));
|
||||
|
||||
+56
@@ -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 {
|
||||
|
||||
+7
@@ -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);
|
||||
|
||||
+7
-31
@@ -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)
|
||||
|
||||
+15
@@ -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);
|
||||
|
||||
|
||||
/**
|
||||
* 手机端分页查询
|
||||
|
||||
+55
-1
@@ -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();
|
||||
|
||||
+6
-49
@@ -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);
|
||||
|
||||
+12
@@ -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)
|
||||
|
||||
+29
-1
@@ -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);
|
||||
|
||||
/**
|
||||
* 校验编辑活动时删除的主题类型、作品类型是否已被投稿引用。
|
||||
|
||||
+89
-1
@@ -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())) {
|
||||
|
||||
+4
-2
@@ -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");
|
||||
|
||||
+2
-1
@@ -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);
|
||||
|
||||
+3
-1
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
+145
-3
@@ -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 兼容V3、V4字段的成员变化数据
|
||||
*/
|
||||
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活动字段(hdsj、mc、zbdw、hddd、cjrs、hjqk)和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;
|
||||
|
||||
+47
-11
@@ -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 = "投稿排名")
|
||||
|
||||
+6
-2
@@ -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();
|
||||
|
||||
+7
-2
@@ -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);
|
||||
|
||||
/**
|
||||
* 获取排行榜数据
|
||||
|
||||
+46
-10
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取排行榜数据
|
||||
*/
|
||||
|
||||
+13
-3
@@ -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,
|
||||
|
||||
+7
-31
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+4
@@ -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);
|
||||
|
||||
+1
-1
@@ -94,7 +94,7 @@ public class BuildHomeKpiWriteController {
|
||||
buildHomeKpiWriteService.exportDocx(id, os);
|
||||
// 下载生成的文件
|
||||
CommonDownloadUtil.download(
|
||||
"南京邮电大学分工会教职工之家建设考核评议自评表.docx",
|
||||
"中国地质大学分工会教职工之家建设考核评议自评表.docx",
|
||||
os.toByteArray(),
|
||||
response
|
||||
);
|
||||
|
||||
+1
-1
@@ -136,7 +136,7 @@ public class BuildHomeLogBookController {
|
||||
template.render(map).writeAndClose(os);
|
||||
// 下载生成的文件
|
||||
CommonDownloadUtil.download(
|
||||
"南京邮电大学分工会建家记录册.docx",
|
||||
"中国地质大学分工会建家记录册.docx",
|
||||
os.toByteArray(),
|
||||
response
|
||||
);
|
||||
|
||||
+21
-2
@@ -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);
|
||||
|
||||
+3
-1
@@ -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);
|
||||
|
||||
+5
-1
@@ -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());
|
||||
}
|
||||
|
||||
+15
-9
@@ -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);
|
||||
|
||||
+4
-4
@@ -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() + "%");
|
||||
|
||||
+4
-2
@@ -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));
|
||||
}
|
||||
|
||||
+10
-1
@@ -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);
|
||||
}
|
||||
|
||||
+12
-8
@@ -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();
|
||||
|
||||
+31
@@ -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 包含 totalQuota、usedQuota、surplusQuota 的合计数据
|
||||
*/
|
||||
NutMap queryUseDetailSummary(Integer year, String unionId);
|
||||
|
||||
/**
|
||||
* 查询分工会经费收支使用情况的全量合计。
|
||||
*
|
||||
* @param year 统计年度
|
||||
* @param unionId 分工会主键,管理员可为空查询全部
|
||||
* @return 包含各项收入、支出和余额字段的合计数据
|
||||
*/
|
||||
NutMap queryIncomeExpenseSummary(Integer year, String unionId);
|
||||
}
|
||||
+104
@@ -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;
|
||||
}
|
||||
}
|
||||
+13
@@ -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("导出")
|
||||
|
||||
+13
@@ -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("某个分工会预算使用详情")
|
||||
|
||||
+4
-1
@@ -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();
|
||||
|
||||
+23
-7
@@ -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());
|
||||
|
||||
+19
@@ -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")
|
||||
|
||||
+18
-108
@@ -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
|
||||
|
||||
+24
-62
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+28
-111
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -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"),
|
||||
|
||||
+26
-101
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -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()));
|
||||
|
||||
+12
-2
@@ -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));
|
||||
|
||||
-1
@@ -49,7 +49,6 @@ public class ProposalCommissionerController {
|
||||
public void h5Index() {
|
||||
}
|
||||
|
||||
|
||||
@At
|
||||
@SaCheckPermission("proposal.commissioner")
|
||||
public Result pageData(@Valid ProposalSearchParam pageForm, boolean approval) {
|
||||
|
||||
+11
@@ -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("并案审核")
|
||||
|
||||
+2
-1
@@ -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
|
||||
|
||||
-13
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-12
@@ -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("获取立案信息")
|
||||
|
||||
+5
@@ -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")
|
||||
|
||||
-1
@@ -74,7 +74,6 @@ public class ProposalSchoolLeaderApprovalController {
|
||||
public void h5Index() {
|
||||
}
|
||||
|
||||
|
||||
@At
|
||||
@SaCheckPermission("proposal.schoolLeaderApproval")
|
||||
@ApiOperation("分页列表")
|
||||
|
||||
+11
@@ -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();
|
||||
|
||||
-11
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 承办单位答复节点撤回需要基于整组当前节点判断。
|
||||
* 只有“当前流程正在办理的节点”和“这条列表记录所属节点”完全一致时,才允许撤回;
|
||||
|
||||
+5
-1
@@ -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);
|
||||
/*
|
||||
* 当前任务对象是在任务完成前加载的,其中 finishTime、operator 仍为空。
|
||||
* 这里只更新拦截器实际修改的流程变量,避免整行更新覆盖 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 {
|
||||
|
||||
|
||||
+29
-3
@@ -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 传 name、code 或 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())) {
|
||||
|
||||
+20
-3
@@ -24,17 +24,34 @@ public class ProposalSearchParam extends PageForm {
|
||||
private String createUserLoginName;
|
||||
private String createUserKeyword;
|
||||
private String caseFilingResult;
|
||||
/** 名称/编号组合搜索字段,仅支持 name、code、caseFilingCode。 */
|
||||
private String proposalSearchField;
|
||||
/** 名称/编号组合搜索内容。 */
|
||||
private String proposalKeyword;
|
||||
|
||||
/**
|
||||
* 构建通用查询参数
|
||||
* 将提案列表参数追加到查询条件中,无返回值,处理结果直接写入 cnd。
|
||||
*
|
||||
* @param cnd cnd
|
||||
* @param searchParam searchParam
|
||||
* @param cnd 查询条件容器,用于接收名称/编号、届次、提案人及立案结果条件
|
||||
* @param searchParam 页面查询参数;proposalSearchField 传 name、code 或 caseFilingCode,
|
||||
* proposalKeyword 传对应字段的模糊搜索内容
|
||||
*/
|
||||
public static void buildSearch(Cnd cnd, ProposalSearchParam searchParam) {
|
||||
if (cnd == null) {
|
||||
cnd = Cnd.NEW();
|
||||
}
|
||||
// 搜索字段通过固定白名单转换,禁止把前端字段名直接用于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());
|
||||
}
|
||||
|
||||
+9
@@ -6,6 +6,15 @@ import com.budwk.app.zhgh.democratic.proposal.models.ProposalInfo;
|
||||
|
||||
public interface ProposalCommitteeFilingService extends BaseService<ProposalInfo> {
|
||||
|
||||
/**
|
||||
* 提案委员会单案立案审核。
|
||||
* 正常提交确认立案或工作建议时,先校验所选承办单位是否均已配置负责人,再执行 WF 流程任务。
|
||||
*
|
||||
* @param args 页面提交的流程参数,包括 processTaskId、submitType、tf_caseFilingResult、
|
||||
* tf_masterUnitIds、tf_slaveUnitIds 等字段;方法无返回值,校验失败时抛出业务异常
|
||||
*/
|
||||
void executeFlowTask(Dict args);
|
||||
|
||||
/**
|
||||
* 提案委员会并案审核。
|
||||
*
|
||||
|
||||
+8
@@ -5,6 +5,14 @@ import com.budwk.app.zhgh.democratic.proposal.models.ProposalSecond;
|
||||
|
||||
public interface ProposalSecondedService extends BaseService<ProposalSecond> {
|
||||
|
||||
/**
|
||||
* 判断团长是否已经对当前提案作出同意或不同意的审核结果。
|
||||
*
|
||||
* @param proposalId 提案ID,用于定位当前提案对应的最新工作流实例
|
||||
* @return true 表示团长已同意或不同意,不能继续附议;false 表示仍可按原流程附议
|
||||
*/
|
||||
boolean isDelegationReviewed(String proposalId);
|
||||
|
||||
/**
|
||||
* 仅更新附议表 proposal_second 中当前附议人的附议结果。
|
||||
* 参数说明:
|
||||
|
||||
+98
@@ -174,6 +174,25 @@ public interface ProposalCommonService extends BaseService<ProposalInfo> {
|
||||
*/
|
||||
void updateStateCode(String id, Integer stateCode);
|
||||
|
||||
/**
|
||||
* 分页查询提案综合列表。
|
||||
*
|
||||
* @param pageForm 综合查询页面提交的筛选、排序和分页参数;origins 指定通用关键字的检索范围,
|
||||
* commonKeyword 为通用关键字,其余字段对应页面各独立筛选项
|
||||
* @return Pagination 分页结果,list 中每项包含提案、流程状态、当前节点及承办单位汇总字段
|
||||
*/
|
||||
Pagination queryComprehensive(ProposalQueryComprehensiveParam pageForm);
|
||||
|
||||
/**
|
||||
* 按综合查询页面当前筛选条件和可见字段导出 Excel。
|
||||
*
|
||||
* @param pageForm 综合查询页面提交的筛选和排序参数;导出全部匹配记录,不受当前分页限制
|
||||
* @param tableColumns 列设置中当前可见的字段,数组顺序即 Excel 列顺序
|
||||
* @param response HTTP 响应,方法直接输出 XSSF 格式的 Excel 文件
|
||||
*/
|
||||
void exportComprehensiveAsExcel(ProposalQueryComprehensiveParam pageForm,
|
||||
ExportTableColumns[] tableColumns, HttpServletResponse response);
|
||||
|
||||
/**
|
||||
* 查询提案征集进度列表。
|
||||
* 查询结果与页面既有筛选、排序语义保持一致,内部使用聚合关联避免逐行执行统计子查询。
|
||||
@@ -183,6 +202,85 @@ public interface ProposalCommonService extends BaseService<ProposalInfo> {
|
||||
*/
|
||||
Pagination queryCollectProgress(ProposalQueryComprehensiveParam pageForm);
|
||||
|
||||
/**
|
||||
* 按征集进度页面当前筛选条件和可见字段导出 Excel。
|
||||
*
|
||||
* @param pageForm 征集进度页面筛选及排序参数,导出全部匹配记录
|
||||
* @param tableColumns 列设置中当前可见字段,数组顺序即 Excel 列顺序
|
||||
* @param response HTTP 响应,方法直接输出 XSSF Excel
|
||||
*/
|
||||
void exportCollectProgressAsExcel(ProposalQueryComprehensiveParam pageForm,
|
||||
ExportTableColumns[] tableColumns, HttpServletResponse response);
|
||||
|
||||
/**
|
||||
* 查询指定届次的代表团提案统计。
|
||||
*
|
||||
* @param pageForm 排序参数
|
||||
* @param sessionId 教代会届次ID
|
||||
* @return 代表团统计行,包含动态立案结果数量和立案率计算字段
|
||||
*/
|
||||
List<NutMap> queryDelegationStatistics(PageForm pageForm, String sessionId);
|
||||
|
||||
/**
|
||||
* 导出代表团提案统计。
|
||||
*
|
||||
* @param pageForm 当前排序参数
|
||||
* @param sessionId 教代会届次ID
|
||||
* @param tableColumns 当前可见统计字段
|
||||
* @param response HTTP 响应,方法直接输出 XSSF Excel
|
||||
*/
|
||||
void exportDelegationStatisticsAsExcel(PageForm pageForm, String sessionId,
|
||||
ExportTableColumns[] tableColumns, HttpServletResponse response);
|
||||
|
||||
/**
|
||||
* 查询承办单位办理统计。
|
||||
*
|
||||
* @param pageForm 排序参数
|
||||
* @param sessionId 教代会届次ID
|
||||
* @param undertakeUnitId 承办单位ID,为空时统计全部单位
|
||||
* @param caseFilingResult 立案结果编码,为空时不限制
|
||||
* @return NutMap,tableData 为统计行,slaveNeedReply 表示协办单位是否需要答复
|
||||
*/
|
||||
NutMap queryUnitReplyStatistics(PageForm pageForm, String sessionId,
|
||||
String undertakeUnitId, String caseFilingResult);
|
||||
|
||||
/**
|
||||
* 导出承办单位办理统计。
|
||||
*
|
||||
* @param pageForm 当前排序参数
|
||||
* @param sessionId 教代会届次ID
|
||||
* @param undertakeUnitId 承办单位ID
|
||||
* @param caseFilingResult 立案结果编码
|
||||
* @param tableColumns 当前可见统计字段
|
||||
* @param response HTTP 响应,方法直接输出 XSSF Excel
|
||||
*/
|
||||
void exportUnitReplyStatisticsAsExcel(PageForm pageForm, String sessionId, String undertakeUnitId,
|
||||
String caseFilingResult, ExportTableColumns[] tableColumns,
|
||||
HttpServletResponse response);
|
||||
|
||||
/**
|
||||
* 查询承办单位满意度统计。
|
||||
*
|
||||
* @param pageForm 排序参数
|
||||
* @param sessionId 教代会届次ID
|
||||
* @param undertakeUnitId 承办单位ID,为空时统计全部单位
|
||||
* @return 满意度统计行,动态满意度字段使用字典编码作为键
|
||||
*/
|
||||
List<NutMap> queryUnderTakeSatisfactionStatistics(PageForm pageForm, String sessionId,
|
||||
String undertakeUnitId);
|
||||
|
||||
/**
|
||||
* 导出承办单位满意度统计。
|
||||
*
|
||||
* @param pageForm 当前排序参数
|
||||
* @param sessionId 教代会届次ID
|
||||
* @param undertakeUnitId 承办单位ID
|
||||
* @param tableColumns 当前可见统计字段
|
||||
* @param response HTTP 响应,方法直接输出 XSSF Excel
|
||||
*/
|
||||
void exportUnderTakeSatisfactionAsExcel(PageForm pageForm, String sessionId, String undertakeUnitId,
|
||||
ExportTableColumns[] tableColumns, HttpServletResponse response);
|
||||
|
||||
/**
|
||||
* 按提案去重统计指定届次各流程节点的待办和已办数量。
|
||||
*
|
||||
|
||||
+705
-24
@@ -82,6 +82,18 @@ import java.util.stream.Collectors;
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class ProposalCommonServiceImpl extends BaseServiceImpl<ProposalInfo> implements ProposalCommonService {
|
||||
|
||||
/** 确定立案提案的 Word 模板编码。 */
|
||||
private static final String PROPOSAL_CONFIRM_FILING_TEMPLATE_CODE = "proposal_confirm_filing";
|
||||
|
||||
/** 工作建议提案的 Word 模板编码。 */
|
||||
private static final String PROPOSAL_SUGGESTION_TEMPLATE_CODE = "proposal_suggestion";
|
||||
|
||||
/** 不予立案提案的 Word 模板编码。 */
|
||||
private static final String PROPOSAL_NOT_TEMPLATE_CODE = "proposal_not";
|
||||
|
||||
/** 历史提案立案结果为空或无法识别时使用的原 Word 模板编码。 */
|
||||
private static final String PROPOSAL_DEFAULT_TEMPLATE_CODE = "proposal";
|
||||
|
||||
/** PC端提案列表页面的排序字段白名单,页面代码由对应Controller固定传入。 */
|
||||
private static final Map<String, Map<String, String>> PROPOSAL_LIST_ORDER_COLUMNS = createProposalListOrderColumns();
|
||||
|
||||
@@ -91,6 +103,7 @@ public class ProposalCommonServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
/** 征集进度页面允许排序的字段,避免排序参数直接拼接到SQL。 */
|
||||
private static final Map<String, String> COLLECT_PROGRESS_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("delegationName", "delegationName"),
|
||||
@@ -100,6 +113,68 @@ public class ProposalCommonServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
Map.entry("instanceState", "instanceState")
|
||||
);
|
||||
|
||||
/** 征集进度页面允许自定义导出的字段及固定表头。 */
|
||||
private static final Map<String, String> COLLECT_PROGRESS_EXPORT_COLUMNS = Map.ofEntries(
|
||||
Map.entry("code", "提案编号"),
|
||||
Map.entry("caseFilingCode", "立案编号"),
|
||||
Map.entry("name", "提案名称"),
|
||||
Map.entry("createUserName", "提案人"),
|
||||
Map.entry("delegationName", "代表团"),
|
||||
Map.entry("inviteCount", "邀请附议人数"),
|
||||
Map.entry("finishCount", "已附议人数"),
|
||||
Map.entry("curTaskName", "当前节点"),
|
||||
Map.entry("instanceState", "流程状态")
|
||||
);
|
||||
|
||||
/** 代表团统计固定字段的安全排序映射,动态立案结果字段由后端字典追加。 */
|
||||
private static final Map<String, String> DELEGATION_SUMMARY_ORDER_COLUMNS = Map.of(
|
||||
"dbtName", "dbt.name",
|
||||
"TOTAL", "TOTAL",
|
||||
"caseRate", "caseRateOrder"
|
||||
);
|
||||
|
||||
/** 承办单位办理统计允许排序的字段白名单。 */
|
||||
private static final Set<String> UNIT_REPLY_ORDER_COLUMNS = Set.of(
|
||||
"unitName", "sum", "masterSum", "masterReplySum", "masterNoReplySum",
|
||||
"slaveSum", "slaveReplySum", "slaveNoReplySum"
|
||||
);
|
||||
|
||||
/** 满意度统计固定字段的排序白名单,动态满意度字段由后端字典追加。 */
|
||||
private static final Set<String> SATISFACTION_ORDER_COLUMNS = Set.of(
|
||||
"unitName", "sum", "masterSum", "slaveSum"
|
||||
);
|
||||
|
||||
/** 综合查询页面允许排序的字段,避免前端排序参数直接进入SQL。 */
|
||||
private static final Map<String, String> COMPREHENSIVE_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"),
|
||||
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")
|
||||
);
|
||||
|
||||
/** 综合查询页面允许自定义导出的字段及固定表头,防止请求伪造页面外字段。 */
|
||||
private static final Map<String, String> COMPREHENSIVE_EXPORT_COLUMNS = Map.ofEntries(
|
||||
Map.entry("code", "提案编号"),
|
||||
Map.entry("caseFilingCode", "立案编号"),
|
||||
Map.entry("name", "提案名称"),
|
||||
Map.entry("createUserName", "提案人"),
|
||||
Map.entry("typeName", "提案类别"),
|
||||
Map.entry("delegationName", "代表团"),
|
||||
Map.entry("caseFilingResult", "立案结果"),
|
||||
Map.entry("merge", "是否并案"),
|
||||
Map.entry("undertakeUnits", "承办单位"),
|
||||
Map.entry("curTaskName", "当前节点"),
|
||||
Map.entry("instanceState", "流程状态")
|
||||
);
|
||||
|
||||
//找出富文本里面上传的图片
|
||||
static String IMG_SRC_REGEX = "<img\\s+[^>]*src\\s*=\\s*([\"'])(/platform/sys/file/download\\?id=.*?)\\1[^>]*>";
|
||||
|
||||
@@ -122,6 +197,227 @@ public class ProposalCommonServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
super(dao);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询提案综合列表。
|
||||
* 普通查询不关联历史任务表;仅在 origins 包含 answer 且 commonKeyword 非空时,
|
||||
* 才关联答复任务变量,避免每条提案与全部历史任务产生大量中间结果。
|
||||
*
|
||||
* @param pageForm 综合查询页面的筛选、排序和分页参数
|
||||
* @return 包含提案基本信息、流程状态和承办单位汇总字段的分页结果
|
||||
*/
|
||||
@Override
|
||||
public Pagination queryComprehensive(ProposalQueryComprehensiveParam pageForm) {
|
||||
boolean searchAnswer = ArrayUtil.contains(pageForm.getOrigins(), "answer")
|
||||
&& StrUtil.isNotBlank(pageForm.getCommonKeyword());
|
||||
String answerTaskJoin = searchAnswer
|
||||
? "LEFT JOIN wf_process_task replyTask ON replyTask.processInstanceId = ins.id"
|
||||
: "";
|
||||
|
||||
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 AS instanceState,
|
||||
ins.variable AS instanceVariable,
|
||||
ins.processDefineId AS instanceProcessDefineId,
|
||||
t.displayName AS 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 AND tcde.sessionId = info.sessionId
|
||||
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
|
||||
%s
|
||||
$condition
|
||||
""".formatted(answerTaskJoin));
|
||||
Cnd dataCnd = buildComprehensiveCondition(pageForm, searchAnswer);
|
||||
dataCnd.groupBy("info.id");
|
||||
applySafePageOrder(dataCnd, pageForm, COMPREHENSIVE_ORDER_COLUMNS);
|
||||
sql.setCondition(dataCnd);
|
||||
|
||||
// 总数查询只保留筛选需要的表,不重复执行列表字段聚合和排序。
|
||||
String countDelegateJoin = StrUtil.isNotBlank(pageForm.getUnionId()) || StrUtil.isNotBlank(pageForm.getUnitId())
|
||||
? "LEFT JOIN teacher_congress_delegate tcde ON tcde.loginName = info.createUserLoginName AND tcde.sessionId = info.sessionId"
|
||||
: "";
|
||||
String countInstanceJoin = searchAnswer
|
||||
? "LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id"
|
||||
: "";
|
||||
String countReplyUnitJoin = StrUtil.isNotBlank(pageForm.getUnderTakeUnitId())
|
||||
? "LEFT JOIN proposal_reply_unit pru ON pru.proposalId = info.id"
|
||||
: "";
|
||||
Sql countSql = Sqls.create("""
|
||||
SELECT COUNT(DISTINCT info.id)
|
||||
FROM proposal_info info
|
||||
%s
|
||||
%s
|
||||
%s
|
||||
%s
|
||||
$condition
|
||||
""".formatted(countDelegateJoin, countInstanceJoin, countReplyUnitJoin, answerTaskJoin));
|
||||
countSql.setCondition(buildComprehensiveCondition(pageForm, searchAnswer));
|
||||
return listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql, countSql);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按综合查询页面当前筛选条件和列设置导出 Excel。
|
||||
* 查询条件与分页列表共用 buildComprehensiveCondition,确保届次、组织及万能搜索口径一致;
|
||||
* tableColumns 只决定导出字段和顺序,不参与 SQL 字段拼接。
|
||||
*
|
||||
* @param pageForm 综合查询页面筛选及排序参数,导出不受分页参数限制
|
||||
* @param tableColumns 列设置中当前可见字段,数组顺序即 Excel 列顺序
|
||||
* @param response HTTP 响应,返回 XSSF 格式的 Excel 文件
|
||||
*/
|
||||
@Override
|
||||
public void exportComprehensiveAsExcel(ProposalQueryComprehensiveParam pageForm,
|
||||
ExportTableColumns[] tableColumns, HttpServletResponse response) {
|
||||
List<ExportTableColumns> exportColumns = getComprehensiveExportColumns(tableColumns);
|
||||
if (exportColumns.isEmpty()) {
|
||||
throw new BaseException("请至少选择一个导出字段");
|
||||
}
|
||||
|
||||
boolean searchAnswer = ArrayUtil.contains(pageForm.getOrigins(), "answer")
|
||||
&& StrUtil.isNotBlank(pageForm.getCommonKeyword());
|
||||
String answerTaskJoin = searchAnswer
|
||||
? "LEFT JOIN wf_process_task replyTask ON replyTask.processInstanceId = ins.id"
|
||||
: "";
|
||||
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.state AS instanceState,
|
||||
t.displayName AS 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 AND tcde.sessionId = info.sessionId
|
||||
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
|
||||
%s
|
||||
$condition
|
||||
""".formatted(answerTaskJoin));
|
||||
Cnd cnd = buildComprehensiveCondition(pageForm, searchAnswer);
|
||||
cnd.groupBy("info.id");
|
||||
applySafePageOrder(cnd, pageForm, COMPREHENSIVE_ORDER_COLUMNS);
|
||||
sql.setCondition(cnd);
|
||||
List<NutMap> rows = listMap(sql);
|
||||
if (rows.isEmpty()) {
|
||||
throw new BaseException("当前筛选条件下没有可导出的提案数据");
|
||||
}
|
||||
convertComprehensiveExportValues(rows);
|
||||
|
||||
List<ExcelExportEntity> excelColumns = exportColumns.stream()
|
||||
.map(column -> new ExcelExportEntity(column.getLabel(), column.getProp(), 20))
|
||||
.collect(Collectors.toList());
|
||||
ExportParams exportParams = new ExportParams();
|
||||
exportParams.setType(ExcelType.XSSF);
|
||||
exportParams.setTitle("提案综合查询");
|
||||
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, excelColumns, rows);
|
||||
CommonDownloadUtil.download("提案综合查询.xlsx", workbook, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按页面字段白名单过滤导出列,并使用后端固定表头,避免伪造字段或重复字段进入 Excel。
|
||||
*
|
||||
* @param tableColumns 页面提交的当前可见列
|
||||
* @return 校验后的导出列,保持页面列设置顺序
|
||||
*/
|
||||
private List<ExportTableColumns> getComprehensiveExportColumns(ExportTableColumns[] tableColumns) {
|
||||
if (ArrayUtil.isEmpty(tableColumns)) {
|
||||
return List.of();
|
||||
}
|
||||
List<ExportTableColumns> exportColumns = new ArrayList<>();
|
||||
Set<String> selectedProps = new HashSet<>();
|
||||
for (ExportTableColumns column : tableColumns) {
|
||||
if (column == null || !COMPREHENSIVE_EXPORT_COLUMNS.containsKey(column.getProp())
|
||||
|| !selectedProps.add(column.getProp())) {
|
||||
continue;
|
||||
}
|
||||
ExportTableColumns safeColumn = new ExportTableColumns();
|
||||
safeColumn.setProp(column.getProp());
|
||||
safeColumn.setLabel(COMPREHENSIVE_EXPORT_COLUMNS.get(column.getProp()));
|
||||
exportColumns.add(safeColumn);
|
||||
}
|
||||
return exportColumns;
|
||||
}
|
||||
|
||||
/** 将字典、枚举及组合字段转换为与综合查询列表一致的展示文本。 */
|
||||
private void convertComprehensiveExportValues(List<NutMap> rows) {
|
||||
Map<String, String> caseFilingResultMap = sysDictService.getSubListByCode("PROPOSAL_CASE_FILING_RESULT")
|
||||
.stream().collect(Collectors.toMap(Sys_dict::getCode, Sys_dict::getName));
|
||||
Map<Integer, String> processStateMap = Arrays.stream(ProcessInstanceStateEnum.values())
|
||||
.collect(Collectors.toMap(ProcessInstanceStateEnum::getCode, ProcessInstanceStateEnum::getMessage));
|
||||
for (NutMap row : rows) {
|
||||
// 承办单位必须在立案结果转换为中文前拼接,否则无法判断立案与建议两种展示口径。
|
||||
row.put("undertakeUnits", formatUndertakeUnits(row));
|
||||
row.put("merge", row.getInt("merge", 0) == 1 ? "是" : "否");
|
||||
String caseFilingResult = row.getString("caseFilingResult");
|
||||
row.put("caseFilingResult", caseFilingResultMap.getOrDefault(caseFilingResult, caseFilingResult));
|
||||
Integer instanceState = row.getInt("instanceState");
|
||||
row.put("instanceState", processStateMap.getOrDefault(instanceState, row.getString("instanceState")));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建综合列表和总数查询共用的筛选条件,保证分页总数与列表数据范围一致。
|
||||
* 通用关键字中的多个词沿用原页面的 OR 关系;未选择检索范围或关键字为空时不追加条件。
|
||||
*
|
||||
* @param pageForm 综合查询页面筛选参数
|
||||
* @param searchAnswer 是否需要检索工作流任务变量中的答复内容
|
||||
* @return 不包含分组和排序的查询条件
|
||||
*/
|
||||
private Cnd buildComprehensiveCondition(ProposalQueryComprehensiveParam pageForm, boolean searchAnswer) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
if (ArrayUtil.isNotEmpty(pageForm.getOrigins()) && StrUtil.isNotBlank(pageForm.getCommonKeyword())) {
|
||||
SqlExpressionGroup keywordCondition = new SqlExpressionGroup();
|
||||
for (String keyword : pageForm.getCommonKeyword().split(" ")) {
|
||||
if (ArrayUtil.contains(pageForm.getOrigins(), "name")) {
|
||||
keywordCondition.orLike("info.name", keyword);
|
||||
}
|
||||
if (ArrayUtil.contains(pageForm.getOrigins(), "brief")) {
|
||||
keywordCondition.orLike("info.brief", keyword);
|
||||
}
|
||||
if (ArrayUtil.contains(pageForm.getOrigins(), "createUserName")) {
|
||||
keywordCondition.orLike("info.createUserName", keyword);
|
||||
keywordCondition.orLike("info.createUserLoginName", keyword);
|
||||
}
|
||||
// 立案编号由立案环节生成,选中该搜索来源时按编号进行模糊匹配。
|
||||
if (ArrayUtil.contains(pageForm.getOrigins(), "caseFilingCode")) {
|
||||
keywordCondition.orLike("info.caseFilingCode", keyword);
|
||||
}
|
||||
if (searchAnswer) {
|
||||
keywordCondition.orLike("JSON_EXTRACT(replyTask.variable,'$.tf_opinion')", keyword);
|
||||
}
|
||||
}
|
||||
if (!keywordCondition.isEmpty()) {
|
||||
cnd.and(keywordCondition);
|
||||
}
|
||||
}
|
||||
ProposalQueryComprehensiveParam.buildSearch(cnd, pageForm);
|
||||
return cnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询提案征集进度。
|
||||
* 附议人数和已附议人数使用分组结果关联,避免原查询对每一条提案重复执行统计子查询;
|
||||
@@ -132,11 +428,48 @@ public class ProposalCommonServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
*/
|
||||
@Override
|
||||
public Pagination queryCollectProgress(ProposalQueryComprehensiveParam pageForm) {
|
||||
Sql sql = buildCollectProgressListSql(pageForm);
|
||||
|
||||
Sql countSql = Sqls.create("""
|
||||
SELECT COUNT(DISTINCT info.id)
|
||||
FROM proposal_info info
|
||||
LEFT JOIN teacher_congress_delegate tcde ON tcde.loginName = info.createUserLoginName
|
||||
LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id
|
||||
LEFT JOIN wf_process_task t ON t.processInstanceId = ins.id AND t.taskState = 10
|
||||
$condition
|
||||
""");
|
||||
countSql.setCondition(buildCollectProgressCondition(pageForm));
|
||||
return listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql, countSql);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按征集进度页面当前筛选条件和可见字段导出全部匹配数据。
|
||||
*
|
||||
* @param pageForm 页面筛选及排序参数
|
||||
* @param tableColumns 当前可见字段,顺序即 Excel 列顺序
|
||||
* @param response HTTP 响应,直接输出 XSSF Excel
|
||||
*/
|
||||
@Override
|
||||
public void exportCollectProgressAsExcel(ProposalQueryComprehensiveParam pageForm,
|
||||
ExportTableColumns[] tableColumns, HttpServletResponse response) {
|
||||
List<NutMap> rows = listMap(buildCollectProgressListSql(pageForm));
|
||||
Map<Integer, String> processStateMap = Arrays.stream(ProcessInstanceStateEnum.values())
|
||||
.collect(Collectors.toMap(ProcessInstanceStateEnum::getCode, ProcessInstanceStateEnum::getMessage));
|
||||
for (NutMap row : rows) {
|
||||
Integer instanceState = row.getInt("instanceState");
|
||||
row.put("instanceState", processStateMap.getOrDefault(instanceState, row.getString("instanceState")));
|
||||
}
|
||||
exportRowsAsExcel("提案征集进度", rows, tableColumns, COLLECT_PROGRESS_EXPORT_COLUMNS, response);
|
||||
}
|
||||
|
||||
/** 构建征集进度分页和导出共用的数据查询,保证两处筛选、分组及排序口径一致。 */
|
||||
private Sql buildCollectProgressListSql(ProposalQueryComprehensiveParam pageForm) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
info.id,
|
||||
info.name,
|
||||
info.code,
|
||||
info.caseFilingCode,
|
||||
info.createUserName,
|
||||
type.NAME AS typeName,
|
||||
tcs.fullName AS sessionName,
|
||||
@@ -170,17 +503,7 @@ public class ProposalCommonServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
dataCnd.groupBy("info.id");
|
||||
applySafePageOrder(dataCnd, pageForm, COLLECT_PROGRESS_ORDER_COLUMNS);
|
||||
sql.setCondition(dataCnd);
|
||||
|
||||
Sql countSql = Sqls.create("""
|
||||
SELECT COUNT(DISTINCT info.id)
|
||||
FROM proposal_info info
|
||||
LEFT JOIN teacher_congress_delegate tcde ON tcde.loginName = info.createUserLoginName
|
||||
LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id
|
||||
LEFT JOIN wf_process_task t ON t.processInstanceId = ins.id AND t.taskState = 10
|
||||
$condition
|
||||
""");
|
||||
countSql.setCondition(buildCollectProgressCondition(pageForm));
|
||||
return listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql, countSql);
|
||||
return sql;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -244,6 +567,301 @@ public class ProposalCommonServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
return cnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询指定届次的代表团提案统计,动态立案结果字段仅使用已校验的后端字典编码。
|
||||
*
|
||||
* @param pageForm 排序参数
|
||||
* @param sessionId 教代会届次ID;为空时返回空列表,避免跨届次统计
|
||||
* @return 代表团统计行,包含各立案结果数量和立案率排序值
|
||||
*/
|
||||
@Override
|
||||
public List<NutMap> queryDelegationStatistics(PageForm pageForm, String sessionId) {
|
||||
if (StrUtil.isBlank(sessionId)) {
|
||||
return 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> orderColumns = new HashMap<>(DELEGATION_SUMMARY_ORDER_COLUMNS);
|
||||
List<String> resultSqlParts = new ArrayList<>();
|
||||
for (Sys_dict dict : dictList) {
|
||||
String resultCode = dict.getCode();
|
||||
// 动态 SQL 别名和字面量只接受字母、数字、下划线,避免字典异常值进入 SQL 结构。
|
||||
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 + "`");
|
||||
orderColumns.put(resultCode, "`" + resultCode + "`");
|
||||
}
|
||||
sql.setVar("resultSql", String.join("", resultSqlParts));
|
||||
sql.setParam("confirmFiling", "CONFIRM_FILING");
|
||||
Cnd cnd = Cnd.where("dbt.sessionId", "=", sessionId);
|
||||
if (!applySafePageOrder(cnd, pageForm, orderColumns)) {
|
||||
cnd.asc("dbt.`code`");
|
||||
}
|
||||
sql.setCondition(cnd);
|
||||
return listMap(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出代表团统计,导出字段由页面当前可见列决定,字段名称以服务端字典为准。
|
||||
*
|
||||
* @param pageForm 排序参数
|
||||
* @param sessionId 教代会届次ID
|
||||
* @param tableColumns 当前可见字段
|
||||
* @param response HTTP 响应,直接输出 XSSF Excel
|
||||
*/
|
||||
@Override
|
||||
public void exportDelegationStatisticsAsExcel(PageForm pageForm, String sessionId,
|
||||
ExportTableColumns[] tableColumns, HttpServletResponse response) {
|
||||
List<NutMap> rows = queryDelegationStatistics(pageForm, sessionId);
|
||||
for (NutMap row : rows) {
|
||||
int total = row.getInt("TOTAL", 0);
|
||||
int confirmFiling = row.getInt("CONFIRM_FILING", 0);
|
||||
row.put("caseRate", total == 0 ? "" : String.format(Locale.ROOT, "%.2f%%", confirmFiling * 100.0 / total));
|
||||
}
|
||||
Map<String, String> allowedColumns = new LinkedHashMap<>();
|
||||
allowedColumns.put("dbtName", "代表团名称");
|
||||
allowedColumns.put("TOTAL", "提案总数");
|
||||
for (Sys_dict dict : sysDictService.getSubListByCode("PROPOSAL_CASE_FILING_RESULT")) {
|
||||
if (StrUtil.isNotBlank(dict.getCode()) && dict.getCode().matches("[A-Za-z0-9_]+")) {
|
||||
allowedColumns.put(dict.getCode(), dict.getName());
|
||||
}
|
||||
}
|
||||
allowedColumns.put("caseRate", "立案率");
|
||||
exportRowsAsExcel("代表团提案统计", rows, tableColumns, allowedColumns, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询承办单位办理统计,返回统计行及协办单位是否需要答复的配置。
|
||||
*
|
||||
* @param pageForm 排序参数
|
||||
* @param sessionId 教代会届次ID
|
||||
* @param undertakeUnitId 承办单位ID,为空时统计全部单位
|
||||
* @param caseFilingResult 立案结果编码,为空时不限制
|
||||
* @return tableData 为统计行,slaveNeedReply 为协办答复配置
|
||||
*/
|
||||
@Override
|
||||
public NutMap queryUnitReplyStatistics(PageForm pageForm, String sessionId,
|
||||
String undertakeUnitId, String caseFilingResult) {
|
||||
ProposalConfig proposalConfig = dao().fetch(ProposalConfig.class, Cnd.NEW());
|
||||
boolean slaveNeedReply = proposalConfig != null && Boolean.TRUE.equals(proposalConfig.getSlaveUnitNeedReply());
|
||||
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 NutMap.NEW().addv("tableData", List.of()).addv("slaveNeedReply", slaveNeedReply);
|
||||
}
|
||||
|
||||
Sql instanceSql = Sqls.create("SELECT id FROM wf_process_instance WHERE businessNo IN (@proposalIds)");
|
||||
instanceSql.setParam("proposalIds", proposalIds);
|
||||
instanceSql.setCallback(Sqls.callback.strList());
|
||||
dao().execute(instanceSql);
|
||||
List<String> instanceIds = instanceSql.getList(String.class);
|
||||
|
||||
Cnd replyUnitCnd = Cnd.where(ProposalReplyUnit::getProposalId, "in", proposalIds);
|
||||
replyUnitCnd.andEX(ProposalReplyUnit::getUnitId, "=", undertakeUnitId);
|
||||
List<ProposalReplyUnit> replyUnits = dao().query(ProposalReplyUnit.class, replyUnitCnd);
|
||||
List<ProcessTask> replyTasks = instanceIds.isEmpty() ? List.of() : dao().query(ProcessTask.class,
|
||||
Cnd.where(ProcessTask::getProcessInstanceId, "in", instanceIds)
|
||||
.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((unitCode, units) -> {
|
||||
NutMap tableRow = NutMap.NEW().addv("id", unitCode);
|
||||
units.stream().findAny().ifPresent(item -> {
|
||||
tableRow.put("unitName", item.getUnitName());
|
||||
tableRow.put("unitCode", item.getUnitCode());
|
||||
});
|
||||
tableRow.put("sum", units.size());
|
||||
tableRow.put("masterSum", units.stream().filter(unit -> Boolean.TRUE.equals(unit.getIsMaster())).count());
|
||||
tableRow.put("slaveSum", units.stream().filter(unit -> !Boolean.TRUE.equals(unit.getIsMaster())).count());
|
||||
|
||||
long masterReplySum = countUnitReplyTasks(replyTasks, unitCode, true, ProcessTaskStateEnum.FINISHED.getCode());
|
||||
long masterNoReplySum = countUnitReplyTasks(replyTasks, unitCode, true, ProcessTaskStateEnum.DOING.getCode());
|
||||
long slaveReplySum = countUnitReplyTasks(replyTasks, unitCode, false, ProcessTaskStateEnum.FINISHED.getCode());
|
||||
long slaveNoReplySum = countUnitReplyTasks(replyTasks, unitCode, false, ProcessTaskStateEnum.DOING.getCode());
|
||||
tableRow.put("masterReplySum", masterReplySum);
|
||||
tableRow.put("masterNoReplySum", masterNoReplySum);
|
||||
tableRow.put("slaveReplySum", slaveReplySum);
|
||||
tableRow.put("slaveNoReplySum", slaveNoReplySum);
|
||||
tableData.add(tableRow);
|
||||
});
|
||||
sortStatisticsRows(tableData, pageForm, UNIT_REPLY_ORDER_COLUMNS);
|
||||
return NutMap.NEW().addv("tableData", tableData).addv("slaveNeedReply", slaveNeedReply);
|
||||
}
|
||||
|
||||
/** 按承办单位、主协办标识和任务状态,对流程实例去重统计答复数量。 */
|
||||
private long countUnitReplyTasks(List<ProcessTask> replyTasks, String unitCode, boolean master, int taskState) {
|
||||
return replyTasks.stream().filter(task -> {
|
||||
NutMap variables = FlowUtil.variableToNutMap(task.getVariable());
|
||||
return Objects.equals(unitCode, variables.getString("underTakeId", ""))
|
||||
&& master == Boolean.TRUE.equals(variables.getBoolean("underTakeIsMaster"))
|
||||
&& Objects.equals(task.getTaskState(), taskState);
|
||||
}).map(ProcessTask::getProcessInstanceId).distinct().count();
|
||||
}
|
||||
|
||||
/** 按承办单位办理统计页面当前可见字段导出全部统计行。 */
|
||||
@Override
|
||||
public void exportUnitReplyStatisticsAsExcel(PageForm pageForm, String sessionId, String undertakeUnitId,
|
||||
String caseFilingResult, ExportTableColumns[] tableColumns,
|
||||
HttpServletResponse response) {
|
||||
NutMap statistics = queryUnitReplyStatistics(pageForm, sessionId, undertakeUnitId, caseFilingResult);
|
||||
List<NutMap> rows = statistics.getList("tableData", NutMap.class);
|
||||
Map<String, String> allowedColumns = new LinkedHashMap<>();
|
||||
allowedColumns.put("unitName", "单位名称");
|
||||
allowedColumns.put("sum", "提案总数");
|
||||
allowedColumns.put("masterSum", "主办提案数量");
|
||||
allowedColumns.put("masterReplySum", "主办已答复");
|
||||
allowedColumns.put("masterNoReplySum", "主办未答复");
|
||||
allowedColumns.put("slaveSum", "协办提案数量");
|
||||
if (statistics.getBoolean("slaveNeedReply", false)) {
|
||||
allowedColumns.put("slaveReplySum", "协办已答复");
|
||||
allowedColumns.put("slaveNoReplySum", "协办未答复");
|
||||
}
|
||||
exportRowsAsExcel("承办单位办理统计", rows, tableColumns, allowedColumns, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询承办单位满意度统计,动态满意度字段来自 PROPOSAL_FEEDBACK 字典。
|
||||
*
|
||||
* @param pageForm 排序参数
|
||||
* @param sessionId 教代会届次ID
|
||||
* @param undertakeUnitId 承办单位ID,为空时统计全部单位
|
||||
* @return 各承办单位的主协办数量及满意度计数
|
||||
*/
|
||||
@Override
|
||||
public List<NutMap> queryUnderTakeSatisfactionStatistics(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);
|
||||
|
||||
Sql proposalSql = Sqls.create("SELECT id FROM proposal_info WHERE sessionId = @sessionId");
|
||||
proposalSql.setParam("sessionId", sessionId);
|
||||
proposalSql.setCallback(Sqls.callback.strList());
|
||||
dao().execute(proposalSql);
|
||||
List<String> proposalIds = proposalSql.getList(String.class);
|
||||
if (proposalIds.isEmpty()) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
Cnd replyUnitCnd = Cnd.where(ProposalReplyUnit::getProposalId, "in", proposalIds);
|
||||
replyUnitCnd.andEX(ProposalReplyUnit::getUnitId, "=", undertakeUnitId);
|
||||
List<ProposalReplyUnit> replyUnits = dao().query(ProposalReplyUnit.class, replyUnitCnd);
|
||||
List<NutMap> tableData = new ArrayList<>();
|
||||
replyUnits.stream().collect(Collectors.groupingBy(ProposalReplyUnit::getUnitCode)).forEach((unitCode, units) -> {
|
||||
NutMap tableRow = NutMap.NEW().addv("id", unitCode);
|
||||
units.stream().findAny().ifPresent(item -> {
|
||||
tableRow.put("unitName", item.getUnitName());
|
||||
tableRow.put("unitCode", item.getUnitCode());
|
||||
});
|
||||
tableRow.put("sum", units.size());
|
||||
tableRow.put("masterSum", units.stream().filter(unit -> Boolean.TRUE.equals(unit.getIsMaster())).count());
|
||||
tableRow.put("slaveSum", units.stream().filter(unit -> !Boolean.TRUE.equals(unit.getIsMaster())).count());
|
||||
|
||||
List<String> unitProposalIds = units.stream().map(ProposalReplyUnit::getProposalId).toList();
|
||||
List<Long> unitInstanceIds = dao().query(ProcessInstance.class,
|
||||
Cnd.where(ProcessInstance::getBusinessNo, "in", unitProposalIds)).stream()
|
||||
.map(ProcessInstance::getId).toList();
|
||||
List<ProcessTask> feedbackTasks = unitInstanceIds.isEmpty() ? List.of() : dao().query(ProcessTask.class,
|
||||
Cnd.where(ProcessTask::getProcessInstanceId, "in", unitInstanceIds)
|
||||
.and(ProcessTask::getTaskName, "=", "feedback")
|
||||
.and(ProcessTask::getTaskState, "=", ProcessTaskStateEnum.FINISHED.getCode()));
|
||||
for (Sys_dict feedbackCode : feedbackCodes) {
|
||||
if (StrUtil.isBlank(feedbackCode.getCode())) {
|
||||
continue;
|
||||
}
|
||||
long count = feedbackTasks.stream().filter(task -> Objects.equals(feedbackCode.getCode(),
|
||||
FlowUtil.variableToNutMap(task.getVariable()).getString("tf_feedback", "")))
|
||||
.map(ProcessTask::getProcessInstanceId).distinct().count();
|
||||
tableRow.put(feedbackCode.getCode(), count);
|
||||
}
|
||||
tableData.add(tableRow);
|
||||
});
|
||||
sortStatisticsRows(tableData, pageForm, orderColumns);
|
||||
return tableData;
|
||||
}
|
||||
|
||||
/** 按满意度统计页面当前可见字段导出全部统计行。 */
|
||||
@Override
|
||||
public void exportUnderTakeSatisfactionAsExcel(PageForm pageForm, String sessionId, String undertakeUnitId,
|
||||
ExportTableColumns[] tableColumns, HttpServletResponse response) {
|
||||
List<NutMap> rows = queryUnderTakeSatisfactionStatistics(pageForm, sessionId, undertakeUnitId);
|
||||
Map<String, String> allowedColumns = new LinkedHashMap<>();
|
||||
allowedColumns.put("unitName", "单位名称");
|
||||
allowedColumns.put("sum", "提案总数");
|
||||
allowedColumns.put("masterSum", "主办提案数");
|
||||
allowedColumns.put("slaveSum", "协办提案数");
|
||||
for (Sys_dict feedbackCode : sysDictService.getSubListByCode("PROPOSAL_FEEDBACK")) {
|
||||
if (StrUtil.isNotBlank(feedbackCode.getCode())) {
|
||||
allowedColumns.put(feedbackCode.getCode(), feedbackCode.getName());
|
||||
}
|
||||
}
|
||||
exportRowsAsExcel("承办单位满意度统计", rows, tableColumns, allowedColumns, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按页面字段白名单校验列定义并输出 Excel,所有统计导出统一使用 XSSF 格式。
|
||||
*
|
||||
* @param title 文件名及工作表标题
|
||||
* @param rows 待导出的全部匹配数据
|
||||
* @param tableColumns 页面当前可见字段及顺序
|
||||
* @param allowedColumns 后端允许字段及规范表头
|
||||
* @param response HTTP 响应
|
||||
*/
|
||||
private void exportRowsAsExcel(String title, List<NutMap> rows, ExportTableColumns[] tableColumns,
|
||||
Map<String, String> allowedColumns, HttpServletResponse response) {
|
||||
List<ExportTableColumns> exportColumns = getSafeExportColumns(tableColumns, allowedColumns);
|
||||
if (exportColumns.isEmpty()) {
|
||||
throw new BaseException("请至少选择一个导出字段");
|
||||
}
|
||||
if (rows == null || rows.isEmpty()) {
|
||||
throw new BaseException("当前筛选条件下没有可导出的数据");
|
||||
}
|
||||
List<ExcelExportEntity> excelColumns = exportColumns.stream()
|
||||
.map(column -> new ExcelExportEntity(column.getLabel(), column.getProp(), 20))
|
||||
.collect(Collectors.toList());
|
||||
ExportParams exportParams = new ExportParams();
|
||||
exportParams.setType(ExcelType.XSSF);
|
||||
exportParams.setTitle(title);
|
||||
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, excelColumns, rows);
|
||||
CommonDownloadUtil.download(title + ".xlsx", workbook, response);
|
||||
}
|
||||
|
||||
/** 按后端白名单过滤重复或伪造字段,并保留页面列设置顺序。 */
|
||||
private List<ExportTableColumns> getSafeExportColumns(ExportTableColumns[] tableColumns,
|
||||
Map<String, String> allowedColumns) {
|
||||
if (ArrayUtil.isEmpty(tableColumns)) {
|
||||
return List.of();
|
||||
}
|
||||
List<ExportTableColumns> exportColumns = new ArrayList<>();
|
||||
Set<String> selectedProps = new HashSet<>();
|
||||
for (ExportTableColumns column : tableColumns) {
|
||||
if (column == null || !allowedColumns.containsKey(column.getProp()) || !selectedProps.add(column.getProp())) {
|
||||
continue;
|
||||
}
|
||||
ExportTableColumns safeColumn = new ExportTableColumns();
|
||||
safeColumn.setProp(column.getProp());
|
||||
safeColumn.setLabel(allowedColumns.get(column.getProp()));
|
||||
exportColumns.add(safeColumn);
|
||||
}
|
||||
return exportColumns;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用业务页面提供的字段白名单构建排序条件,非法字段或非法排序方向将被忽略。
|
||||
*
|
||||
@@ -306,7 +924,7 @@ public class ProposalCommonServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
pages.put("commissioner", orderColumns("code", "info.code", "name", "info.name", "typeName", "type.name", "sessionName", "tcs.fullName", "delegationName", "tcd.name", "CONFIRM_FILING_COUNT", "CONFIRM_FILING_COUNT", "SUGGESTION_COUNT", "SUGGESTION_COUNT", "NOT_COUNT", "NOT_COUNT", "taskName", "taskName", "instanceState", "ins.state"));
|
||||
pages.put("feedbackEvaluation", orderColumns("code", "info.code", "name", "info.name", "typeName", "type.name", "merge", "merge", "curTaskName", "curTaskName", "instanceState", "ins.state"));
|
||||
pages.put("delegation", standardOrderColumns());
|
||||
pages.put("control", standardOrderColumns());
|
||||
pages.put("control", mergeOrderColumns(standardOrderColumns(), orderColumns("caseFilingCode", "info.caseFilingCode")));
|
||||
pages.put("schoolLeaderApproval", orderColumns("code", "info.code", "name", "info.name", "typeName", "type.name", "undertakeUnits", "masterUnitName", "merge", "merge", "curTaskName", "curTaskName", "auditUser", "auditUser", "instanceState", "ins.state"));
|
||||
pages.put("committeeFilingUnit", orderColumns("code", "info.code", "name", "info.name", "typeName", "type.name", "sessionName", "tcs.fullName", "caseFilingResult", "info.caseFilingResult", "delegationName", "tcd.name", "curTaskName", "curTaskName", "instanceState", "ins.state"));
|
||||
pages.put("allFinished", orderColumns("code", "info.code", "name", "info.name", "createUserName", "info.createUserName", "typeName", "type.name", "sessionName", "tcs.fullName", "delegationName", "tcd.name", "instanceState", "ins.state"));
|
||||
@@ -318,7 +936,7 @@ public class ProposalCommonServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
pages.put("configUnit", orderColumns("name", "t1.name", "code", "t1.code", "unitLeader", "u2.username"));
|
||||
pages.put("configType", orderColumns("name", "name", "code", "code"));
|
||||
pages.put("seniorBasic", seniorOrderColumns());
|
||||
pages.put("expediting", orderColumns("code", "info.code", "name", "info.name", "typeName", "type.name", "delegationName", "tcd.name", "caseFilingResult", "info.caseFilingResult", "curTaskName", "curTaskName", "underTakeName", "underTakeName", "taskName", "t.displayName", "actorName", "ta.actorName", "instanceState", "ins.state"));
|
||||
pages.put("expediting", orderColumns("code", "info.code", "caseFilingCode", "info.caseFilingCode", "name", "info.name", "typeName", "type.name", "delegationName", "tcd.name", "caseFilingResult", "info.caseFilingResult", "curTaskName", "curTaskName", "underTakeName", "underTakeName", "taskName", "t.displayName", "actorName", "ta.actorName", "instanceState", "ins.state"));
|
||||
pages.put("seniorDelete", seniorOrderColumns());
|
||||
pages.put("seniorFeedback", mergeOrderColumns(seniorOrderColumns(), orderColumns("tf_feedback", "tf_feedback")));
|
||||
pages.put("seniorType", seniorOrderColumns());
|
||||
@@ -332,7 +950,7 @@ public class ProposalCommonServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
|
||||
/** 创建高级管理列表共用的字段映射。 */
|
||||
private static Map<String, String> seniorOrderColumns() {
|
||||
return orderColumns("code", "info.code", "name", "info.name", "createUserName", "info.createUserName", "typeName", "type.name", "delegationName", "tcd.name", "caseFilingResult", "info.caseFilingResult", "isConsolidation", "merge", "curTaskName", "curTaskName", "instanceState", "ins.state");
|
||||
return orderColumns("code", "info.code", "caseFilingCode", "info.caseFilingCode", "name", "info.name", "createUserName", "info.createUserName", "typeName", "type.name", "delegationName", "tcd.name", "caseFilingResult", "info.caseFilingResult", "isConsolidation", "merge", "curTaskName", "curTaskName", "instanceState", "ins.state");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -732,6 +1350,7 @@ public class ProposalCommonServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
SELECT
|
||||
info.name,
|
||||
info.code,
|
||||
info.caseFilingResult,
|
||||
info.brief,
|
||||
info.measures,
|
||||
info.createUserName,
|
||||
@@ -862,13 +1481,29 @@ public class ProposalCommonServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
docData.put("secondedList", secondInfos);
|
||||
docData.put("delegationAuditList", delegationAuditList);
|
||||
|
||||
String templateCode = getProposalTemplateCode(docData.getString("caseFilingResult"));
|
||||
try {
|
||||
XWPFTemplate.compile(sysOfficeTemplateUtil.getTemplate("proposal"), config).render(docData).writeAndClose(byteArrayOutputStream);
|
||||
XWPFTemplate.compile(sysOfficeTemplateUtil.getTemplate(templateCode), config).render(docData).writeAndClose(byteArrayOutputStream);
|
||||
} catch (IOException e) {
|
||||
log.error("提案导出失败{},提案id:{}", e.getMessage(), id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据立案结果选择数据库办公模板编码。
|
||||
*
|
||||
* @param caseFilingResult 立案结果字典编码:CONFIRM_FILING、SUGGESTION 或 NOT
|
||||
* @return 对应的 Word 模板编码;历史空值或未知编码返回 proposal
|
||||
*/
|
||||
private String getProposalTemplateCode(String caseFilingResult) {
|
||||
return switch (StrUtil.nullToEmpty(caseFilingResult)) {
|
||||
case "CONFIRM_FILING" -> PROPOSAL_CONFIRM_FILING_TEMPLATE_CODE;
|
||||
case "SUGGESTION" -> PROPOSAL_SUGGESTION_TEMPLATE_CODE;
|
||||
case "NOT" -> PROPOSAL_NOT_TEMPLATE_CODE;
|
||||
default -> PROPOSAL_DEFAULT_TEMPLATE_CODE;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 将现行工作流节点映射到历史提案表模板使用的区块名称,并按主协办单位拆分办理答复。
|
||||
* 模板仍使用旧节点名称时,避免已完成的意见和答复因键名不一致而无法渲染。
|
||||
@@ -879,28 +1514,52 @@ public class ProposalCommonServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
*/
|
||||
private void putProposalExportTaskAliases(String proposalId, Map<String, List<ProcessTaskVO>> taskGroups,
|
||||
NutMap docData) {
|
||||
putTaskAlias(docData, "提案委主任审核", taskGroups.get("校工会预审核"));
|
||||
/* putTaskAlias(docData, "提案委主任审核", taskGroups.get("校工会预审核"));
|
||||
putTaskAlias(docData, "提案委主任意见", taskGroups.get("提案委员会立案"));
|
||||
putTaskAlias(docData, "提案委委员审议", taskGroups.get("委员会确认承办单位"));
|
||||
putTaskAlias(docData, "提案委委员审议", taskGroups.get("委员会确认承办单位"));*/
|
||||
putProposalExportFeedbackName(taskGroups.get("反馈评价"));
|
||||
|
||||
List<ProcessTaskVO> replyTasks = taskGroups.get("承办单位答复");
|
||||
if (Lang.isEmpty(replyTasks)) {
|
||||
return;
|
||||
}
|
||||
Sql masterUnitSql = Sqls.create("SELECT unitName FROM proposal_reply_unit WHERE proposalId = @proposalId AND isMaster = 1")
|
||||
Sql replyUnitSql = Sqls.create("SELECT unitId, unitName, isMaster FROM proposal_reply_unit WHERE proposalId = @proposalId")
|
||||
.setParam("proposalId", proposalId);
|
||||
List<NutMap> masterUnitRows = listMap(masterUnitSql);
|
||||
Set<String> masterUnitNames = masterUnitRows.stream()
|
||||
.map(row -> row.getString("unitName"))
|
||||
List<NutMap> replyUnitRows = listMap(replyUnitSql);
|
||||
Set<String> masterUnitIds = replyUnitRows.stream()
|
||||
.filter(row -> row.getBoolean("isMaster", false))
|
||||
.map(row -> row.getString("unitId"))
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.collect(Collectors.toSet());
|
||||
Map<String, String> replyUnitNameMap = replyUnitRows.stream()
|
||||
.filter(row -> StrUtil.isNotBlank(row.getString("unitId")))
|
||||
.collect(Collectors.toMap(row -> row.getString("unitId"), row -> row.getString("unitName", ""),
|
||||
(left, right) -> left));
|
||||
|
||||
List<ProcessTaskVO> masterReplyTasks = new ArrayList<>();
|
||||
List<ProcessTaskVO> slaveReplyTasks = new ArrayList<>();
|
||||
for (ProcessTaskVO replyTask : replyTasks) {
|
||||
Dict taskExt = replyTask.getExt();
|
||||
Dict taskFormData = replyTask.getTaskFormData();
|
||||
String unitName = taskFormData == null ? null : taskFormData.getStr("unitName");
|
||||
if (masterUnitNames.contains(unitName)) {
|
||||
String underTakeId = taskExt == null ? null : taskExt.getStr("underTakeId");
|
||||
if (StrUtil.isBlank(underTakeId) && taskFormData != null) {
|
||||
underTakeId = taskFormData.getStr("unitId");
|
||||
}
|
||||
|
||||
/*
|
||||
* 承办单位名称保存在任务根变量 underTakeName 中,而模板读取 taskFormData.underTakeName。
|
||||
* 在本次导出对象中补充 tf_ 前缀字段,由 ProcessTaskVO 转换后即可保持现有模板不变。
|
||||
*/
|
||||
if (taskExt != null) {
|
||||
String underTakeName = taskExt.getStr("underTakeName");
|
||||
if (StrUtil.isBlank(underTakeName)) {
|
||||
underTakeName = replyUnitNameMap.getOrDefault(underTakeId, "");
|
||||
}
|
||||
taskExt.put("tf_underTakeName", underTakeName);
|
||||
}
|
||||
|
||||
// 主协办关系按单位ID匹配,避免把任务中的单位ID误当成单位名称后全部归入协办答复。
|
||||
if (masterUnitIds.contains(underTakeId)) {
|
||||
masterReplyTasks.add(replyTask);
|
||||
} else {
|
||||
slaveReplyTasks.add(replyTask);
|
||||
@@ -910,6 +1569,28 @@ public class ProposalCommonServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
putTaskAlias(docData, "协办单位答复", slaveReplyTasks);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将反馈评价字典编码转换为模板使用的中文名称,仅补充本次导出的任务变量。
|
||||
*
|
||||
* @param feedbackTasks 已完成的反馈评价任务;为空时无需处理
|
||||
*/
|
||||
private void putProposalExportFeedbackName(List<ProcessTaskVO> feedbackTasks) {
|
||||
if (Lang.isEmpty(feedbackTasks)) {
|
||||
return;
|
||||
}
|
||||
Map<String, String> feedbackNameMap = sysDictService.getSubListByCode("PROPOSAL_FEEDBACK").stream()
|
||||
.filter(item -> StrUtil.isNotBlank(item.getCode()))
|
||||
.collect(Collectors.toMap(Sys_dict::getCode, Sys_dict::getName, (left, right) -> left));
|
||||
for (ProcessTaskVO feedbackTask : feedbackTasks) {
|
||||
Dict taskExt = feedbackTask.getExt();
|
||||
if (taskExt == null) {
|
||||
continue;
|
||||
}
|
||||
String feedbackCode = taskExt.getStr("tf_feedback");
|
||||
taskExt.put("tf_feedback_name", feedbackNameMap.getOrDefault(feedbackCode, feedbackCode));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 仅在存在已完成任务时写入模板区块,空任务不触发 Word 条件标签。
|
||||
*
|
||||
@@ -980,7 +1661,7 @@ public class ProposalCommonServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
);
|
||||
if (feedbackTask != null) {
|
||||
info.put(FlowUtil.variableToDict(feedbackTask.getVariable()).getStr("tf_feedback"), "√");
|
||||
info.put("tf_feedback", FlowUtil.variableToDict(feedbackTask.getVariable()).getStr("tf_feedback"));
|
||||
info.put("tf_feedback_name", FlowUtil.variableToDict(feedbackTask.getVariable()).getStr("tf_feedback"));
|
||||
info.put("tf_opinion", FlowUtil.variableToDict(feedbackTask.getVariable()).getStr("tf_opinion"));
|
||||
info.put("tf_phone", FlowUtil.variableToDict(feedbackTask.getVariable()).getStr("tf_phone"));
|
||||
info.put("tf_address", FlowUtil.variableToDict(feedbackTask.getVariable()).getStr("tf_address"));
|
||||
|
||||
+123
@@ -2,14 +2,23 @@ package com.budwk.app.zhgh.democratic.proposal.service.impl;
|
||||
|
||||
import cn.hutool.core.lang.Dict;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.exception.BaseException;
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.flow.constant.FlowConst;
|
||||
import com.budwk.app.flow.entity.ProcessTask;
|
||||
import com.budwk.app.flow.enums.ProcessSubmitTypeEnum;
|
||||
import com.budwk.app.flow.service.FlowCommonService;
|
||||
import com.budwk.app.flow.service.ProcessTaskService;
|
||||
import com.budwk.app.sys.models.Sys_role;
|
||||
import com.budwk.app.sys.models.Sys_user_role;
|
||||
import com.budwk.app.sys.services.SysRoleService;
|
||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalConsolidation;
|
||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalInfo;
|
||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalMerge;
|
||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalUndertake;
|
||||
import com.budwk.app.zhgh.democratic.proposal.service.ProposalCommitteeFilingService;
|
||||
import com.budwk.app.zhgh.democratic.proposal.service.common.ProposalCommonService;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
@@ -20,7 +29,14 @@ import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.random.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class ProposalCommitteeFilingServiceImpl extends BaseServiceImpl<ProposalInfo> implements ProposalCommitteeFilingService {
|
||||
@@ -31,14 +47,26 @@ public class ProposalCommitteeFilingServiceImpl extends BaseServiceImpl<Proposal
|
||||
private FlowCommonService flowCommonService;
|
||||
@Inject
|
||||
private ProcessTaskService processTaskService;
|
||||
@Inject
|
||||
private SysRoleService sysRoleService;
|
||||
|
||||
public ProposalCommitteeFilingServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void executeFlowTask(Dict args) {
|
||||
validateSelectedUnitLeaders(args);
|
||||
flowCommonService.executeTask(args);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void merge(Dict args) {
|
||||
// 并案必须在创建并案关系和执行任一流程任务前完成负责人校验,保证失败时整组数据不发生变化。
|
||||
validateSelectedUnitLeaders(args);
|
||||
|
||||
List<Integer> taskIds = (List<Integer>) args.get("processTaskIds");
|
||||
List<String> proposalIds = (List<String>) args.get("proposalIds");
|
||||
|
||||
@@ -65,6 +93,101 @@ public class ProposalCommitteeFilingServiceImpl extends BaseServiceImpl<Proposal
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验正常提交所选承办单位的负责人配置。
|
||||
* 确认立案检查全部主办、协办单位;工作建议只检查办理单位;不予立案和退回操作不检查。
|
||||
* 负责人沿用 WF 承办单位分派口径:用户必须绑定“提案承办单位领导”角色及对应 underTakeId。
|
||||
*
|
||||
* @param args 页面流程参数,submitType=1 时根据 tf_caseFilingResult、tf_masterUnitIds、tf_slaveUnitIds 检查
|
||||
*/
|
||||
private void validateSelectedUnitLeaders(Dict args) {
|
||||
Integer submitType = args.getInt(FlowConst.SUBMIT_TYPE);
|
||||
if (!ProcessSubmitTypeEnum.AGREE.getCode().equals(submitType)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String caseFilingResult = args.getStr(FlowConst.TASK_FORM_DATA_PREFIX + "caseFilingResult");
|
||||
if (!List.of("CONFIRM_FILING", "SUGGESTION").contains(caseFilingResult)) {
|
||||
return;
|
||||
}
|
||||
|
||||
LinkedHashSet<String> selectedUnitIds = new LinkedHashSet<>(
|
||||
getUnitIdList(args, FlowConst.TASK_FORM_DATA_PREFIX + "masterUnitIds"));
|
||||
if ("CONFIRM_FILING".equals(caseFilingResult)) {
|
||||
selectedUnitIds.addAll(getUnitIdList(args, FlowConst.TASK_FORM_DATA_PREFIX + "slaveUnitIds"));
|
||||
}
|
||||
if (selectedUnitIds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Sys_role unitLeaderRole = sysRoleService.getByCode(RoleConstant.PROPOSAL_UNIT_LEADER);
|
||||
if (unitLeaderRole == null) {
|
||||
throw new BaseException("提案承办单位领导角色不存在");
|
||||
}
|
||||
|
||||
Map<String, ProposalUndertake> unitMap = dao().query(ProposalUndertake.class,
|
||||
Cnd.where(ProposalUndertake::getId, "in", selectedUnitIds))
|
||||
.stream()
|
||||
.collect(Collectors.toMap(ProposalUndertake::getId, unit -> unit));
|
||||
if (unitMap.size() != selectedUnitIds.size()) {
|
||||
throw new BaseException("选择的承办单位不存在,请重新选择");
|
||||
}
|
||||
|
||||
Set<String> configuredUnitIds = dao().query(Sys_user_role.class,
|
||||
Cnd.where(Sys_user_role::getRoleId, "=", unitLeaderRole.getId())
|
||||
.and(Sys_user_role::getUnderTakeId, "in", selectedUnitIds))
|
||||
.stream()
|
||||
.map(Sys_user_role::getUnderTakeId)
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.collect(Collectors.toSet());
|
||||
List<String> missingUnitNames = selectedUnitIds.stream()
|
||||
.filter(unitId -> !configuredUnitIds.contains(unitId))
|
||||
.map(unitMap::get)
|
||||
.map(ProposalUndertake::getName)
|
||||
.toList();
|
||||
if (!missingUnitNames.isEmpty()) {
|
||||
throw new BaseException(String.join("、", missingUnitNames) + "没有设置负责人!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将页面单位字段统一转换为去空、去重后的单位ID列表,兼容数组、JSON数组字符串和逗号分隔字符串。
|
||||
*
|
||||
* @param args 页面流程参数
|
||||
* @param key 需要读取的单位字段名
|
||||
* @return 规范化后的单位ID列表
|
||||
*/
|
||||
private List<String> getUnitIdList(Dict args, String key) {
|
||||
Object value = args.get(key);
|
||||
if (ObjectUtil.isEmpty(value)) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
List<String> unitIds = new ArrayList<>();
|
||||
if (value instanceof Collection<?> collection) {
|
||||
collection.forEach(item -> {
|
||||
if (ObjectUtil.isNotEmpty(item)) {
|
||||
unitIds.add(String.valueOf(item));
|
||||
}
|
||||
});
|
||||
} else if (value instanceof String stringValue) {
|
||||
if (StrUtil.isBlank(stringValue)) {
|
||||
return List.of();
|
||||
}
|
||||
if (JSONUtil.isTypeJSONArray(stringValue)) {
|
||||
unitIds.addAll(JSONUtil.parseArray(stringValue).toList(String.class));
|
||||
} else {
|
||||
Arrays.stream(stringValue.split(","))
|
||||
.map(String::trim)
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.forEach(unitIds::add);
|
||||
}
|
||||
} else {
|
||||
unitIds.add(String.valueOf(value));
|
||||
}
|
||||
return new ArrayList<>(new LinkedHashSet<>(unitIds));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void revokeTask(Long taskId, String proposalId) {
|
||||
|
||||
+98
-21
@@ -16,6 +16,7 @@ import com.budwk.app.bpm.models.BpmProcessTask;
|
||||
import com.budwk.app.bpm.service.BpmService;
|
||||
import com.budwk.app.flow.constant.FlowConst;
|
||||
import com.budwk.app.flow.entity.ProcessTask;
|
||||
import com.budwk.app.flow.enums.ProcessSubmitTypeEnum;
|
||||
import com.budwk.app.flow.service.FlowCommonService;
|
||||
import com.budwk.app.flow.service.ProcessTaskService;
|
||||
import com.budwk.app.sys.models.Sys_user_role;
|
||||
@@ -34,6 +35,8 @@ 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.dao.util.cri.Static;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
@@ -87,7 +90,7 @@ public class ProposalCommitteeFilingUnitServiceImpl extends BaseServiceImpl<Prop
|
||||
if (ObjectUtil.isEmpty(proposalIds)) {
|
||||
proposalIds = List.of(proposalId);
|
||||
}
|
||||
validateAndNormalizeCaseFilingCode(args, proposalIds);
|
||||
generateAndNormalizeCaseFilingCode(args, proposalIds);
|
||||
|
||||
/*
|
||||
* 先同步 proposal_info 和承办单位,再执行 WF 流转,使查看页面及下一节点读取到的都是本次最新数据。
|
||||
@@ -111,40 +114,114 @@ public class ProposalCommitteeFilingUnitServiceImpl extends BaseServiceImpl<Prop
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验并规范化立案编号。确定立案时必须传入不超过 20 个字符且不与历史立案编号重复的编号;
|
||||
* 当前提案及并案提案不参与重复校验,保证流程回退后可按原编号重新提交。
|
||||
* 其他立案结果不保存编号,避免切换选项后把历史输入带入业务表和流程变量。
|
||||
* 按立案结果和服务器当前年份生成立案编号,并覆盖页面可能传入的编号。
|
||||
* 正常提交时生成编号;退回等非同意操作不占用流水号。并案提案共用同一个编号。
|
||||
*
|
||||
* @param args 流程提交参数,其中 tf_caseFilingResult 为立案结果,tf_caseFilingCode 为手工填写的立案编号
|
||||
* @param excludedProposalIds 当前办理的提案及并案提案主键,不参与历史重复判断
|
||||
* @param args 流程提交参数,tf_caseFilingResult 分别支持 CONFIRM_FILING、SUGGESTION、NOT
|
||||
* @param proposalIds 当前办理的提案主键集合,并案时包含同组全部提案
|
||||
*/
|
||||
private void validateAndNormalizeCaseFilingCode(Dict args, List<String> excludedProposalIds) {
|
||||
private void generateAndNormalizeCaseFilingCode(Dict args, List<String> proposalIds) {
|
||||
String caseFilingResultKey = FlowConst.TASK_FORM_DATA_PREFIX + "caseFilingResult";
|
||||
String caseFilingCodeKey = FlowConst.TASK_FORM_DATA_PREFIX + "caseFilingCode";
|
||||
String caseFilingTypeKey = FlowConst.TASK_FORM_DATA_PREFIX + "caseFilingType";
|
||||
if (!"CONFIRM_FILING".equals(args.getStr(caseFilingResultKey))) {
|
||||
args.put(caseFilingCodeKey, "");
|
||||
String caseFilingResult = args.getStr(caseFilingResultKey);
|
||||
if (!"CONFIRM_FILING".equals(caseFilingResult)) {
|
||||
// 立案类型仅适用于确定立案,切换为其他结果时同步清理历史值。
|
||||
args.put(caseFilingTypeKey, "");
|
||||
}
|
||||
|
||||
Integer submitType = args.getInt(FlowConst.SUBMIT_TYPE);
|
||||
if (submitType == null) {
|
||||
submitType = ProcessSubmitTypeEnum.AGREE.getCode();
|
||||
args.put(FlowConst.SUBMIT_TYPE, submitType);
|
||||
}
|
||||
if (!ProcessSubmitTypeEnum.AGREE.getCode().equals(submitType)) {
|
||||
args.put(caseFilingCodeKey, "");
|
||||
return;
|
||||
}
|
||||
|
||||
String caseFilingCode = StrUtil.trim(args.getStr(caseFilingCodeKey));
|
||||
if (StrUtil.isBlank(caseFilingCode)) {
|
||||
throw new BaseException("立案编号不能为空");
|
||||
String codePrefix = resolveCaseFilingCodePrefix(caseFilingResult);
|
||||
int currentYear = java.time.LocalDate.now().getYear();
|
||||
String codeHead = currentYear + codePrefix;
|
||||
|
||||
/*
|
||||
* proposal_config 当前是单行配置表,锁定该行可让所有应用实例串行生成流水号。
|
||||
* 行锁一直持有到本次 WF 提交事务结束,避免两个审核请求同时读到相同最大值。
|
||||
*/
|
||||
Sql lockSql = Sqls.create("SELECT id FROM proposal_config ORDER BY id LIMIT 1 FOR UPDATE");
|
||||
lockSql.setCallback(Sqls.callback.map());
|
||||
dao().execute(lockSql);
|
||||
Map<?, ?> configRow = lockSql.getObject(Map.class);
|
||||
if (ObjectUtil.isEmpty(configRow)) {
|
||||
throw new BaseException("提案配置不存在,无法生成立案编号");
|
||||
}
|
||||
if (caseFilingCode.length() > 20) {
|
||||
throw new BaseException("立案编号不能超过20个字符");
|
||||
}
|
||||
Cnd duplicateCondition = Cnd.where("caseFilingCode", "=", caseFilingCode);
|
||||
if (!ObjectUtil.isEmpty(excludedProposalIds)) {
|
||||
duplicateCondition.and("id", "not in", excludedProposalIds);
|
||||
}
|
||||
if (dao().count(ProposalInfo.class, duplicateCondition) > 0) {
|
||||
throw new BaseException("立案编号已存在,请重新填写");
|
||||
|
||||
String reusableCode = findReusableCaseFilingCode(proposalIds, caseFilingResult, codeHead);
|
||||
if (StrUtil.isNotBlank(reusableCode)) {
|
||||
args.put(caseFilingCodeKey, reusableCode);
|
||||
return;
|
||||
}
|
||||
|
||||
Sql maxSequenceSql = Sqls.create("""
|
||||
SELECT COALESCE(MAX(CAST(SUBSTRING(caseFilingCode, 6) AS UNSIGNED)), 0)
|
||||
FROM proposal_info
|
||||
WHERE caseFilingCode REGEXP @codePattern
|
||||
""");
|
||||
maxSequenceSql.setParam("codePattern", "^" + codeHead + "[0-9]{3,}$");
|
||||
maxSequenceSql.setCallback(Sqls.callback.integer());
|
||||
dao().execute(maxSequenceSql);
|
||||
int nextSequence = maxSequenceSql.getInt() + 1;
|
||||
String caseFilingCode = codeHead + String.format("%03d", nextSequence);
|
||||
args.put(caseFilingCodeKey, caseFilingCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将立案结果转换成编号前缀,未知结果直接阻止流程提交,避免生成无业务含义的编号。
|
||||
*
|
||||
* @param caseFilingResult 立案结果编码
|
||||
* @return 确定立案返回 A、工作建议返回 B、不予立案返回 C
|
||||
*/
|
||||
private String resolveCaseFilingCodePrefix(String caseFilingResult) {
|
||||
return switch (StrUtil.nullToEmpty(caseFilingResult)) {
|
||||
case "CONFIRM_FILING" -> "A";
|
||||
case "SUGGESTION" -> "B";
|
||||
case "NOT" -> "C";
|
||||
default -> throw new BaseException("立案结果不正确,无法生成立案编号");
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 流程撤回或重新提交时,复用同一批提案已有的本年同类型编号,避免流水号无意义增长。
|
||||
* 只有全部提案的结果和编号完全一致且符合新编号格式时才允许复用。
|
||||
*
|
||||
* @param proposalIds 当前单案或并案提案主键集合
|
||||
* @param caseFilingResult 本次选择的立案结果
|
||||
* @param codeHead 年份和编号前缀,例如 2026A
|
||||
* @return 可复用的编号;不存在时返回空字符串
|
||||
*/
|
||||
private String findReusableCaseFilingCode(List<String> proposalIds, String caseFilingResult, String codeHead) {
|
||||
List<ProposalInfo> proposalInfos = dao().query(ProposalInfo.class,
|
||||
Cnd.where(ProposalInfo::getId, "in", proposalIds));
|
||||
if (proposalInfos.size() != new LinkedHashSet<>(proposalIds).size()) {
|
||||
return "";
|
||||
}
|
||||
boolean allProposalsMatch = proposalInfos.stream().allMatch(proposalInfo ->
|
||||
Objects.equals(caseFilingResult, proposalInfo.getCaseFilingResult())
|
||||
&& StrUtil.isNotBlank(proposalInfo.getCaseFilingCode()));
|
||||
if (!allProposalsMatch) {
|
||||
return "";
|
||||
}
|
||||
LinkedHashSet<String> existingCodes = proposalInfos.stream()
|
||||
.map(ProposalInfo::getCaseFilingCode)
|
||||
.map(StrUtil::trim)
|
||||
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
if (existingCodes.size() != 1) {
|
||||
return "";
|
||||
}
|
||||
String existingCode = existingCodes.iterator().next();
|
||||
return existingCode.matches(codeHead + "\\d{3,}") ? existingCode : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* old-flow 页面提交后,需要把立案编号、立案结果以及主协办单位同步落业务表。
|
||||
* 若这次改成“不予立案”等无需承办单位的结果,也要先清掉旧的承办单位记录,避免脏数据残留。
|
||||
|
||||
+84
-49
@@ -29,6 +29,7 @@ import com.deepoove.poi.XWPFTemplate;
|
||||
import com.deepoove.poi.config.Configure;
|
||||
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.poi.ss.usermodel.BorderStyle;
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.CellStyle;
|
||||
import org.apache.poi.ss.usermodel.Font;
|
||||
@@ -74,7 +75,8 @@ import java.util.zip.ZipOutputStream;
|
||||
public class ProposalExportServiceImpl extends BaseServiceImpl<ProposalInfo> implements ProposalExportService {
|
||||
|
||||
private static final String WORK_SUGGESTION_SECTION_MARKER = "__WORK_SUGGESTION_SECTION__";
|
||||
private static final int UNDERTAKE_UNIT_EXPORT_COLUMN_COUNT = 8;
|
||||
private static final int UNDERTAKE_UNIT_EXPORT_COLUMN_COUNT = 6;
|
||||
private static final int UNDERTAKE_UNIT_SECOND_TITLE_ROW_INDEX = 1;
|
||||
|
||||
@Inject
|
||||
private ProposalCommonService proposalCommonService;
|
||||
@@ -411,14 +413,14 @@ public class ProposalExportServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
LinkedHashSet<String> masterUnitNames = getUnitNameSet(proposalRow, "masterUnitNames");
|
||||
LinkedHashSet<String> slaveUnitNames = getUnitNameSet(proposalRow, "slaveUnitNames");
|
||||
NutMap excelRow = NutMap.NEW()
|
||||
.addv("code", proposalRow.getString("code"))
|
||||
.addv("caseFilingCode", proposalRow.getString("caseFilingCode"))
|
||||
// 承办单位表统一展示为“立案编号”;未生成立案编号的工作建议回退显示提案编号。
|
||||
.addv("caseFilingCode", StrUtil.blankToDefault(proposalRow.getString("caseFilingCode"),
|
||||
proposalRow.getString("code")))
|
||||
.addv("name", proposalRow.getString("name"))
|
||||
.addv("createUserName", proposalRow.getString("createUserName"))
|
||||
.addv("masterUnitNames", "")
|
||||
.addv("slaveUnitNames", "")
|
||||
.addv("workSuggestionUnitNames", "")
|
||||
.addv("remark", "");
|
||||
.addv("workSuggestionUnitNames", "");
|
||||
if ("CONFIRM_FILING".equals(proposalRow.getString("caseFilingResult"))) {
|
||||
excelRow.put("masterUnitNames", String.join(",", masterUnitNames));
|
||||
excelRow.put("slaveUnitNames", String.join(",", slaveUnitNames));
|
||||
@@ -432,14 +434,12 @@ public class ProposalExportServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
}
|
||||
if (!suggestionRows.isEmpty()) {
|
||||
filingRows.add(NutMap.NEW()
|
||||
.addv("code", WORK_SUGGESTION_SECTION_MARKER)
|
||||
.addv("caseFilingCode", "")
|
||||
.addv("caseFilingCode", WORK_SUGGESTION_SECTION_MARKER)
|
||||
.addv("name", "")
|
||||
.addv("createUserName", "")
|
||||
.addv("masterUnitNames", "")
|
||||
.addv("slaveUnitNames", "")
|
||||
.addv("workSuggestionUnitNames", "")
|
||||
.addv("remark", ""));
|
||||
.addv("workSuggestionUnitNames", ""));
|
||||
filingRows.addAll(suggestionRows);
|
||||
}
|
||||
return filingRows;
|
||||
@@ -450,14 +450,12 @@ public class ProposalExportServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
*/
|
||||
private Workbook buildUndertakeUnitWorkbook(String title, String unitName, List<NutMap> excelRows) {
|
||||
List<ExcelExportEntity> exportEntities = new ArrayList<>();
|
||||
exportEntities.add(new ExcelExportEntity("提案编号", "code", 18));
|
||||
exportEntities.add(new ExcelExportEntity("立案编号", "caseFilingCode", 18));
|
||||
exportEntities.add(new ExcelExportEntity("提案名称", "name", 45));
|
||||
exportEntities.add(new ExcelExportEntity("提案人", "createUserName", 15));
|
||||
exportEntities.add(new ExcelExportEntity("主办单位", "masterUnitNames", 28));
|
||||
exportEntities.add(new ExcelExportEntity("协办单位", "slaveUnitNames", 28));
|
||||
exportEntities.add(new ExcelExportEntity("工作建议送达单位", "workSuggestionUnitNames", 32));
|
||||
exportEntities.add(new ExcelExportEntity("备注", "remark", 20));
|
||||
exportEntities.add(new ExcelExportEntity("立案编号", "caseFilingCode", 11));
|
||||
exportEntities.add(new ExcelExportEntity("提案名称", "name", 43));
|
||||
exportEntities.add(new ExcelExportEntity("提案人", "createUserName", 13));
|
||||
exportEntities.add(new ExcelExportEntity("主办单位", "masterUnitNames", 19));
|
||||
exportEntities.add(new ExcelExportEntity("协办单位", "slaveUnitNames", 25));
|
||||
exportEntities.add(new ExcelExportEntity("工作建议送达单位", "workSuggestionUnitNames", 17));
|
||||
for (ExcelExportEntity exportEntity : exportEntities) {
|
||||
exportEntity.setWrap(true);
|
||||
}
|
||||
@@ -468,14 +466,59 @@ public class ProposalExportServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
exportParams.setSecondTitle("(" + unitName + ")");
|
||||
exportParams.setSheetName("提案承办单位表");
|
||||
exportParams.setHeaderHeight(30);
|
||||
exportParams.setHeight((short) 24);
|
||||
exportParams.setHeight((short) 13);
|
||||
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, exportEntities, excelRows);
|
||||
mergeWorkSuggestionSection(workbook);
|
||||
applyUndertakeUnitWorkbookStyle(workbook);
|
||||
return workbook;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找工作建议标记行,将八个单元格合并并设置为居中的分组标题。
|
||||
* 为承办单位表的全部有效单元格设置细实线边框,并保证第二行承办单位名称加粗且水平、垂直居中。
|
||||
* 相同原始样式复用同一个克隆样式,避免按单元格重复创建样式导致工作簿样式数量过多。
|
||||
*/
|
||||
private void applyUndertakeUnitWorkbookStyle(Workbook workbook) {
|
||||
Sheet sheet = workbook.getSheetAt(0);
|
||||
Map<String, CellStyle> borderedStyles = new HashMap<>();
|
||||
Font unitNameFont = workbook.createFont();
|
||||
unitNameFont.setFontName("宋体");
|
||||
unitNameFont.setFontHeightInPoints((short) 11);
|
||||
unitNameFont.setBold(true);
|
||||
for (int rowIndex = 0; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
|
||||
Row row = sheet.getRow(rowIndex);
|
||||
if (row == null) {
|
||||
continue;
|
||||
}
|
||||
boolean centerUnitName = rowIndex == UNDERTAKE_UNIT_SECOND_TITLE_ROW_INDEX;
|
||||
for (int columnIndex = 0; columnIndex < UNDERTAKE_UNIT_EXPORT_COLUMN_COUNT; columnIndex++) {
|
||||
Cell cell = row.getCell(columnIndex);
|
||||
if (cell == null) {
|
||||
cell = row.createCell(columnIndex);
|
||||
}
|
||||
CellStyle sourceStyle = cell.getCellStyle();
|
||||
String styleKey = sourceStyle.getIndex() + ":" + centerUnitName;
|
||||
CellStyle borderedStyle = borderedStyles.get(styleKey);
|
||||
if (borderedStyle == null) {
|
||||
borderedStyle = workbook.createCellStyle();
|
||||
borderedStyle.cloneStyleFrom(sourceStyle);
|
||||
borderedStyle.setBorderTop(BorderStyle.THIN);
|
||||
borderedStyle.setBorderRight(BorderStyle.THIN);
|
||||
borderedStyle.setBorderBottom(BorderStyle.THIN);
|
||||
borderedStyle.setBorderLeft(BorderStyle.THIN);
|
||||
if (centerUnitName) {
|
||||
borderedStyle.setAlignment(HorizontalAlignment.CENTER);
|
||||
borderedStyle.setVerticalAlignment(VerticalAlignment.CENTER);
|
||||
borderedStyle.setFont(unitNameFont);
|
||||
}
|
||||
borderedStyles.put(styleKey, borderedStyle);
|
||||
}
|
||||
cell.setCellStyle(borderedStyle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找工作建议标记行,将承办单位表的全部单元格合并并设置为居中的分组标题。
|
||||
*/
|
||||
private void mergeWorkSuggestionSection(Workbook workbook) {
|
||||
Sheet sheet = workbook.getSheetAt(0);
|
||||
@@ -577,47 +620,37 @@ public class ProposalExportServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
|
||||
@Override
|
||||
public void exportProposalStatisticsAsZip(ProposalQueryComprehensiveParam pageForm, HttpServletResponse response) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
info.id,
|
||||
info.code,
|
||||
info.name
|
||||
FROM
|
||||
proposal_info info
|
||||
LEFT JOIN proposal_type type on type.id = info.typeId
|
||||
LEFT JOIN teacher_congress_session tcs on tcs.id = info.sessionId
|
||||
LEFT JOIN teacher_congress_delegation tcd on tcd.id = info.delegationId
|
||||
LEFT JOIN teacher_congress_delegate tcde on tcde.loginName = info.createUserLoginName
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
ProposalQueryComprehensiveParam.buildSearch(cnd, pageForm);
|
||||
sql.setCondition(cnd);
|
||||
List<NutMap> list = listMap(sql);
|
||||
List<NutMap> list = queryProposalBaseList(pageForm);
|
||||
if (Lang.isEmpty(list)) {
|
||||
throw new BaseException("当前筛选条件下没有可导出的提案数据");
|
||||
}
|
||||
|
||||
try {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
ZipOutputStream zipOutputStream = new ZipOutputStream(bos);
|
||||
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
ZipOutputStream zipOutputStream = new ZipOutputStream(bos)) {
|
||||
Map<String, Integer> entryNameCounts = new HashMap<>();
|
||||
for (NutMap proposalRow : list) {
|
||||
try (ByteArrayOutputStream docxByteArrayOutputStream = new ByteArrayOutputStream()) {
|
||||
proposalCommonService.exportProposalAsDocx(proposalRow.getString("id"), docxByteArrayOutputStream);
|
||||
ZipEntry zipEntry = new ZipEntry(proposalRow.getString("code") + "-" + sanitizeZipFileName(proposalRow.getString("name")) + ".docx");
|
||||
if (docxByteArrayOutputStream.size() == 0) {
|
||||
throw new BaseException("提案【{}】Word生成失败", proposalRow.getString("code"));
|
||||
}
|
||||
ZipEntry zipEntry = new ZipEntry(createUniqueZipDocxEntryName("", proposalRow, entryNameCounts));
|
||||
zipOutputStream.putNextEntry(zipEntry);
|
||||
docxByteArrayOutputStream.writeTo(zipOutputStream);
|
||||
zipOutputStream.closeEntry();
|
||||
} catch (IOException e) {
|
||||
// 处理单个文件生成失败的情况
|
||||
throw new RuntimeException("zip entry write failed, proposalId=" + proposalRow.getString("id"), e);
|
||||
throw new BaseException("提案【{}】写入压缩包失败", proposalRow.getString("code"));
|
||||
}
|
||||
}
|
||||
zipOutputStream.finish();
|
||||
zipOutputStream.close();
|
||||
CommonDownloadUtil.download("提案汇总压缩包.zip", bos.toByteArray(), response);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.error("批量导出提案表压缩包失败", e);
|
||||
if (e instanceof BaseException) {
|
||||
throw (BaseException) e;
|
||||
}
|
||||
throw new BaseException("批量导出提案表压缩包失败:{}", e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -673,7 +706,8 @@ public class ProposalExportServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
LEFT JOIN proposal_type type on type.id = info.typeId
|
||||
LEFT JOIN teacher_congress_session tcs on tcs.id = info.sessionId
|
||||
LEFT JOIN teacher_congress_delegation tcd on tcd.id = info.delegationId
|
||||
LEFT JOIN teacher_congress_delegate tcde on tcde.loginName = info.createUserLoginName
|
||||
LEFT JOIN teacher_congress_delegate tcde
|
||||
ON tcde.loginName = info.createUserLoginName AND tcde.sessionId = info.sessionId
|
||||
LEFT JOIN proposal_reply_unit pru ON pru.proposalId = info.id
|
||||
$condition
|
||||
""");
|
||||
@@ -713,13 +747,14 @@ public class ProposalExportServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
/**
|
||||
* 生成 ZIP 内唯一且合法的 Word 文件名,避免提案名称中的非法字符或重名条目导致整个压缩包缺文件。
|
||||
*
|
||||
* @param prefix 文档类型前缀
|
||||
* @param prefix 文档类型前缀;为空时直接使用提案编号和名称
|
||||
* @param proposalRow 提案基础信息
|
||||
* @param entryNameCounts 已生成的基础文件名及其出现次数
|
||||
* @return 可以直接用于 ZipEntry 的文件名
|
||||
*/
|
||||
private String createUniqueZipDocxEntryName(String prefix, NutMap proposalRow, Map<String, Integer> entryNameCounts) {
|
||||
String baseName = sanitizeZipFileName(prefix + "-" + proposalRow.getString("code", "未编号") + "-" + proposalRow.getString("name", "未命名提案"));
|
||||
String prefixText = StrUtil.isBlank(prefix) ? "" : prefix + "-";
|
||||
String baseName = sanitizeZipFileName(prefixText + proposalRow.getString("code", "未编号") + "-" + proposalRow.getString("name", "未命名提案"));
|
||||
int sameNameCount = entryNameCounts.merge(baseName, 1, Integer::sum);
|
||||
return baseName + (sameNameCount > 1 ? "-" + sameNameCount : "") + ".docx";
|
||||
}
|
||||
|
||||
+31
@@ -3,11 +3,17 @@ package com.budwk.app.zhgh.democratic.proposal.service.impl;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.flow.entity.ProcessInstance;
|
||||
import com.budwk.app.flow.entity.ProcessTask;
|
||||
import com.budwk.app.flow.engine.util.FlowUtil;
|
||||
import com.budwk.app.flow.enums.ProcessSubmitTypeEnum;
|
||||
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
|
||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalSecond;
|
||||
import com.budwk.app.zhgh.democratic.proposal.service.ProposalSecondedService;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.Strings;
|
||||
|
||||
@@ -19,6 +25,31 @@ public class ProposalSecondedServiceImpl extends BaseServiceImpl<ProposalSecond>
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDelegationReviewed(String proposalId) {
|
||||
if (Strings.isBlank(proposalId)) {
|
||||
return false;
|
||||
}
|
||||
// 以提案最新一次流程实例为准;团长同意或不同意均截止附议,退回提案人则允许后续重新邀请附议。
|
||||
ProcessInstance processInstance = this.dao().fetch(ProcessInstance.class,
|
||||
Cnd.where(ProcessInstance::getBusinessNo, "=", proposalId)
|
||||
.desc(ProcessInstance::getCreatedAt));
|
||||
if (processInstance == null) {
|
||||
return false;
|
||||
}
|
||||
return this.dao().query(ProcessTask.class,
|
||||
Cnd.where(ProcessTask::getProcessInstanceId, "=", processInstance.getId())
|
||||
.and(ProcessTask::getTaskName, "=", "delegation")
|
||||
.and(ProcessTask::getTaskState, "=", ProcessTaskStateEnum.FINISHED.getCode()))
|
||||
.stream()
|
||||
.anyMatch(task -> {
|
||||
Integer submitType = FlowUtil.variableToDict(task.getVariable()).getInt("submitType");
|
||||
return ObjectUtil.equals(submitType, ProcessSubmitTypeEnum.AGREE.getCode())
|
||||
|| ObjectUtil.equals(submitType, ProcessSubmitTypeEnum.REJECT.getCode());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void updateSecondRecord(String proposalId, String taskActorUserId, String opinion, Integer submitType) {
|
||||
if (Strings.isBlank(proposalId) || Strings.isBlank(taskActorUserId) || submitType == null) {
|
||||
return;
|
||||
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
package com.budwk.app.zhgh.democratic.teachercongress.delegate.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.delegate.param.RepresentativeChangeRecordPageParam;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.delegate.service.RepresentativeChangeRecordService;
|
||||
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 javax.validation.Valid;
|
||||
|
||||
/**
|
||||
* 教代会代表变动记录页面及查询接口。
|
||||
*/
|
||||
@IocBean
|
||||
@At("/platform/jdh/db/changeRecord")
|
||||
@Ok("json:full")
|
||||
public class RepresentativeChangeRecordController {
|
||||
|
||||
@Inject
|
||||
private RepresentativeChangeRecordService representativeChangeRecordService;
|
||||
|
||||
/**
|
||||
* 打开代表变动记录页面。
|
||||
*/
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/democratic/teachercongress/delegate/changeRecord/index.html")
|
||||
@SaCheckPermission("sys.jdh.db.changeRecord")
|
||||
public void index() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询代表变动记录。
|
||||
*
|
||||
* @param pageForm 分页、关键字及组织筛选参数
|
||||
* @return 代表变动记录分页结果
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("sys.jdh.db.changeRecord")
|
||||
public Result pageData(@Valid @Param("pageForm") RepresentativeChangeRecordPageParam pageForm) {
|
||||
Pagination<NutMap> pagination = representativeChangeRecordService.pageData(pageForm);
|
||||
return Result.success(pagination);
|
||||
}
|
||||
}
|
||||
+16
-62
@@ -27,6 +27,7 @@ import com.budwk.app.zhgh.democratic.teachercongress.delegate.service.TeacherCon
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.delegation.models.Teacher_congress_delegation;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.delegation.models.Teacher_congress_delegation_union;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.delegation.models.Teacher_congress_delegation_unit;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.prepare.service.TeacherCongressSessionService;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.poi.ss.usermodel.*;
|
||||
@@ -68,6 +69,8 @@ public class TeacherCongressDelegateManageController {
|
||||
private SysRoleService sysRoleService;
|
||||
@Inject
|
||||
private TeacherCongressDelegateService teacherDelegateService;
|
||||
@Inject
|
||||
private TeacherCongressSessionService teacherCongressSessionService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/democratic/teachercongress/delegate/manage/index.html")
|
||||
@@ -123,12 +126,14 @@ public class TeacherCongressDelegateManageController {
|
||||
.and(Sys_user_role::getTcSessionId, "=", param.getSessionId())
|
||||
.and(Sys_user_role::getRoleId, "=", param.getRoleId()));
|
||||
|
||||
boolean roleEnable = teacherCongressSessionService.isSessionRoleEnabled(param.getSessionId());
|
||||
List<Sys_user_role> userRoles = userIds.stream().map(userId -> {
|
||||
Sys_user_role role = new Sys_user_role();
|
||||
role.setUserId(userId);
|
||||
role.setTcSessionId(param.getSessionId());
|
||||
role.setTcDelegationId(param.getDelegationId());
|
||||
role.setRoleId(param.getRoleId());
|
||||
role.setEnable(roleEnable);
|
||||
return role;
|
||||
}).toList();
|
||||
dao.insert(userRoles);
|
||||
@@ -160,6 +165,7 @@ public class TeacherCongressDelegateManageController {
|
||||
role.setTcSessionId(param.getSessionId());
|
||||
role.setTcDelegationId(param.getDelegationId());
|
||||
role.setRoleId(param.getRoleId());
|
||||
teacherCongressSessionService.prepareSessionRole(role);
|
||||
dao.insert(role);
|
||||
|
||||
sysUserService.clearCache();
|
||||
@@ -191,34 +197,7 @@ public class TeacherCongressDelegateManageController {
|
||||
@At
|
||||
@SaCheckPermission("tc.delegate.manage")
|
||||
public Result publicUser(@Valid TeacherCongressDelegateManagePublicUserParam param) {
|
||||
List<Teacher_congress_delegation_unit> units = dao.query(Teacher_congress_delegation_unit.class, Cnd.where("sessionId", "=", param.getSessionId()).and("delegationId", "=", param.getDelegationId()));
|
||||
List<String> unitIds = units.stream().map(Teacher_congress_delegation_unit::getUnitId).toList();
|
||||
if (ObjectUtil.isEmpty(unitIds)) {
|
||||
return Result.error("代表团没有组成单位");
|
||||
}
|
||||
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
t1.id,
|
||||
t1.username AS userName,
|
||||
t1.loginName AS loginName,
|
||||
t2.NAME AS unitName
|
||||
FROM
|
||||
`sys_user` t1
|
||||
LEFT JOIN sys_unit t2 ON t2.id = t1.unitId
|
||||
WHERE
|
||||
t1.id NOT IN ( SELECT userId FROM teacher_congress_delegate WHERE sessionId = @sessionId AND delegationId = @delegationId )
|
||||
AND
|
||||
t1.unitId in (@unitIds)
|
||||
AND
|
||||
(t1.loginname like @keyWord or username like @keyWord)
|
||||
""");
|
||||
sql.setParam("sessionId", param.getSessionId());
|
||||
sql.setParam("delegationId", param.getDelegationId());
|
||||
sql.setParam("unitIds", unitIds);
|
||||
sql.setParam("keyWord", "%" + param.getKeyWord() + "%");
|
||||
Pagination pagination = sysUserService.listPageMap(1, 50, sql);
|
||||
return Result.success(pagination.getList());
|
||||
return Result.success(teacherDelegateService.listPublicUsers(param));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -330,12 +309,14 @@ public class TeacherCongressDelegateManageController {
|
||||
dao.insert(delegates);
|
||||
|
||||
//插入权限
|
||||
boolean roleEnable = teacherCongressSessionService.isSessionRoleEnabled(sessionId);
|
||||
List<Sys_user_role> sysUserRoles = delegates.stream().map(delegate -> {
|
||||
Sys_user_role sysUserRole = new Sys_user_role();
|
||||
sysUserRole.setUserId(delegate.getUserId());
|
||||
sysUserRole.setRoleId(delegate.getRoleId());
|
||||
sysUserRole.setTcSessionId(sessionId);
|
||||
sysUserRole.setTcDelegationId(delegate.getDelegationId());
|
||||
sysUserRole.setEnable(roleEnable);
|
||||
return sysUserRole;
|
||||
}).toList();
|
||||
dao.insert(sysUserRoles);
|
||||
@@ -464,7 +445,12 @@ public class TeacherCongressDelegateManageController {
|
||||
|
||||
try {
|
||||
dao.insert(delegate);
|
||||
dao.insert("sys_user_role", Chain.make("userId", delegate.getUserId()).add("roleId", delegate.getRoleId()).add("tcSessionId", sessionId).add("tcDelegationId", delegate.getDelegationId()));
|
||||
// Excel导入也必须继承届次启用状态,避免向历史届次导入代表后恢复旧权限。
|
||||
dao.insert("sys_user_role", Chain.make("userId", delegate.getUserId())
|
||||
.add("roleId", delegate.getRoleId())
|
||||
.add("tcSessionId", sessionId)
|
||||
.add("tcDelegationId", delegate.getDelegationId())
|
||||
.add("enable", teacherCongressSessionService.isSessionRoleEnabled(sessionId)));
|
||||
sysUserService.clearCache();
|
||||
} catch (Exception e) {
|
||||
log.error("导入代表失败:{}", e.getMessage());
|
||||
@@ -484,39 +470,7 @@ public class TeacherCongressDelegateManageController {
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("tc.delegate.manage")
|
||||
public Result doAllocateDelegation(String sessionId) {
|
||||
List<Teacher_congress_delegate> delegateList = dao.query(Teacher_congress_delegate.class,
|
||||
Cnd.where(Teacher_congress_delegate::getSessionId, "=", sessionId)
|
||||
.and(Teacher_congress_delegate::getDelegationId, "is", null));
|
||||
|
||||
for (Teacher_congress_delegate delegate : delegateList) {
|
||||
Teacher_congress_delegation_unit delegation_unit = dao.fetch(Teacher_congress_delegation_unit.class,
|
||||
Cnd.where(Teacher_congress_delegation_unit::getUnitId, "=", delegate.getUnitId())
|
||||
.and(Teacher_congress_delegation_unit::getSessionId, "=", sessionId));
|
||||
if (ObjectUtil.isNotEmpty(delegation_unit)) {
|
||||
delegate.setDelegationId(delegation_unit.getDelegationId());
|
||||
dao.update(delegate);
|
||||
Sys_user_role userRole = new Sys_user_role();
|
||||
userRole.setTcDelegationId(delegation_unit.getDelegationId());
|
||||
userRole.setUserId(delegate.getUserId());
|
||||
userRole.setTcSessionId(sessionId);
|
||||
Sys_role sys_role = dao.fetch(Sys_role.class, Cnd.where(Sys_role::getCode, "=", RoleConstant.TEACHER_CONGRESS_DELEGATE_FORMAL.name()));
|
||||
|
||||
if (sys_role.getId().equals(delegate.getRoleId())) {
|
||||
delegate.setRoleId(sys_role.getId());
|
||||
userRole.setRoleId(sys_role.getId());
|
||||
}
|
||||
|
||||
Sys_role sys_role2 = dao.fetch(Sys_role.class, Cnd.where(Sys_role::getCode, "=", RoleConstant.TEACHER_CONGRESS_DELEGATE_ATTENDANCE.name()));
|
||||
if (sys_role2.getId().equals(delegate.getRoleId())) {
|
||||
delegate.setRoleId(sys_role2.getId());
|
||||
userRole.setRoleId(sys_role2.getId());
|
||||
}
|
||||
userRole.setTcDelegationId(delegate.getDelegationId());
|
||||
dao.insert(userRole);
|
||||
}
|
||||
sysUserService.clearCache();
|
||||
}
|
||||
return Result.success();
|
||||
return Result.success(teacherDelegateService.allocateDelegations(sessionId));
|
||||
}
|
||||
|
||||
|
||||
|
||||
+9
-79
@@ -1,27 +1,14 @@
|
||||
package com.budwk.app.zhgh.democratic.teachercongress.delegate.listener;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.event.user.SysUserEvent;
|
||||
import com.budwk.app.base.event.user.SysUserEventListener;
|
||||
import com.budwk.app.sys.models.Sys_role;
|
||||
import com.budwk.app.sys.models.Sys_user_role;
|
||||
import com.budwk.app.sys.services.SysRoleService;
|
||||
import com.budwk.app.sys.services.SysUserService;
|
||||
import com.budwk.app.sys.views.View_user;
|
||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalConfig;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.delegate.models.Teacher_congress_delegate;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.delegation.models.Teacher_congress_delegation_unit;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.prepare.models.Teacher_congress_session;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.delegate.service.TeacherCongressDelegateService;
|
||||
import com.budwk.app.zhgh.staffmanage.member.constant.MemberChangeType;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nutz.aop.interceptor.async.Async;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author zzr
|
||||
@@ -30,14 +17,11 @@ import java.util.List;
|
||||
* @注释
|
||||
*/
|
||||
@IocBean
|
||||
@Slf4j
|
||||
public class TeacherCongressDelegateListener implements SysUserEventListener {
|
||||
|
||||
@Inject
|
||||
private Dao dao;
|
||||
@Inject
|
||||
private SysUserService sysUserService;
|
||||
@Inject
|
||||
private SysRoleService sysRoleService;
|
||||
private TeacherCongressDelegateService teacherCongressDelegateService;
|
||||
|
||||
@Override
|
||||
@Async
|
||||
@@ -46,65 +30,11 @@ public class TeacherCongressDelegateListener implements SysUserEventListener {
|
||||
return;
|
||||
}
|
||||
|
||||
//查询当前最新届次
|
||||
Teacher_congress_session session = dao.fetch(Teacher_congress_session.class, Cnd.NEW().desc(Teacher_congress_session::getStartDate));
|
||||
if (session == null) {
|
||||
return;
|
||||
try {
|
||||
// 保持原有事件范围,仅将监听器内部归团逻辑下沉到事务服务。
|
||||
teacherCongressDelegateService.refreshCurrentDelegateOrganization(event.getUserId());
|
||||
} catch (Exception e) {
|
||||
log.error("刷新教代会代表组织信息失败,userId={}", event.getUserId(), e);
|
||||
}
|
||||
String userId = event.getUserId();
|
||||
//查询校领导的单位
|
||||
ProposalConfig config = dao.fetch(ProposalConfig.class, Cnd.NEW());
|
||||
List<String> schoolLeaderUnitIds = config.getSchoolLeaderUnitIds();
|
||||
|
||||
View_user user = dao.fetch(View_user.class, Cnd.where(View_user::getId, "=", userId));
|
||||
|
||||
//校领导排除在外
|
||||
if (StrUtil.isNotBlank(user.getUnitId()) && schoolLeaderUnitIds.contains(user.getUnitId())) {
|
||||
return;
|
||||
}
|
||||
|
||||
//查询当前代表的信息
|
||||
Teacher_congress_delegate currentDelegate = dao.fetch(Teacher_congress_delegate.class, Cnd.where(Teacher_congress_delegate::getSessionId, "=", session.getId()));
|
||||
if(currentDelegate == null){
|
||||
return;
|
||||
}
|
||||
|
||||
//查询当前分配的单位属于哪个代表团
|
||||
String unitId = user.getUnitId();
|
||||
Teacher_congress_delegation_unit unit = dao.fetch(Teacher_congress_delegation_unit.class, Cnd.where(Teacher_congress_delegation_unit::getSessionId, "=", session)
|
||||
.and(Teacher_congress_delegation_unit::getUnitId, "=", unitId));
|
||||
String delegationId = unit.getDelegationId();
|
||||
|
||||
currentDelegate.setDelegationId(delegationId);
|
||||
currentDelegate.setUnitId(user.getUnitId());
|
||||
currentDelegate.setUnitName(user.getUnitName());
|
||||
currentDelegate.setUnionId(user.getUnionId());
|
||||
currentDelegate.setUnionName(user.getUnionName());
|
||||
dao.updateIgnoreNull(currentDelegate);
|
||||
|
||||
|
||||
//角色数据
|
||||
Sys_role delegateFormalRole = sysRoleService.getByCode(RoleConstant.TEACHER_CONGRESS_DELEGATE_FORMAL.name());
|
||||
Sys_role delegateAttendanceRole = sysRoleService.getByCode(RoleConstant.TEACHER_CONGRESS_DELEGATE_ATTENDANCE.name());
|
||||
Sys_role delegateSpeciallyInviteRole = sysRoleService.getByCode(RoleConstant.TEACHER_CONGRESS_DELEGATE_SPECIALLY_INVITE.name());
|
||||
Sys_role delegationHeadRole = sysRoleService.getByCode(RoleConstant.TEACHER_CONGRESS_DELEGATION_HEAD.name());
|
||||
|
||||
//删除权限
|
||||
//删除角色数据
|
||||
dao.clear(Sys_user_role.class, Cnd.where(Sys_user_role::getUserId, "=", userId)
|
||||
.and(Sys_user_role::getRoleId, "in", List.of(delegateFormalRole.getId(), delegateAttendanceRole.getId(), delegateSpeciallyInviteRole.getId(), delegationHeadRole.getId()))
|
||||
.and(Sys_user_role::getTcSessionId, "=", session.getId())
|
||||
);
|
||||
|
||||
//再加权限
|
||||
Sys_user_role sysUserRole = new Sys_user_role();
|
||||
sysUserRole.setUserId(userId);
|
||||
sysUserRole.setTcSessionId(session.getId());
|
||||
sysUserRole.setTcDelegationId(currentDelegate.getDelegationId());
|
||||
sysUserRole.setRoleId(currentDelegate.getRoleId());
|
||||
dao.insert(sysUserRole);
|
||||
|
||||
sysUserService.clearCache();
|
||||
sysRoleService.clearCache();
|
||||
}
|
||||
}
|
||||
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
package com.budwk.app.zhgh.democratic.teachercongress.delegate.models;
|
||||
|
||||
import com.budwk.app.base.model.BaseModel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.nutz.dao.entity.annotation.ColDefine;
|
||||
import org.nutz.dao.entity.annotation.ColType;
|
||||
import org.nutz.dao.entity.annotation.Column;
|
||||
import org.nutz.dao.entity.annotation.Comment;
|
||||
import org.nutz.dao.entity.annotation.Name;
|
||||
import org.nutz.dao.entity.annotation.Table;
|
||||
import org.nutz.dao.entity.annotation.TableMeta;
|
||||
import org.nutz.dao.interceptor.annotation.PrevInsert;
|
||||
|
||||
/**
|
||||
* 教代会届次延用时产生的代表异动记录。
|
||||
* 记录代表在上一届与新一届之间单位、分工会及代表团的对应关系,供后续异动查询使用。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Table("representative_change_record")
|
||||
@TableMeta("{'mysql-charset':'utf8mb4'}")
|
||||
@Comment("教代会代表异动记录")
|
||||
public class RepresentativeChangeRecord extends BaseModel {
|
||||
|
||||
@Name
|
||||
@Comment("ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@PrevInsert(uu32 = true)
|
||||
private String id;
|
||||
|
||||
@Column
|
||||
@Comment("用户ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String userId;
|
||||
|
||||
@Column
|
||||
@Comment("原教代会届次")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String oldJdhSession;
|
||||
|
||||
@Column
|
||||
@Comment("新教代会届次")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String newJdhSession;
|
||||
|
||||
@Column
|
||||
@Comment("原单位ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String oldUnitId;
|
||||
|
||||
@Column
|
||||
@Comment("原单位名称")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 500)
|
||||
private String oldUnitName;
|
||||
|
||||
@Column
|
||||
@Comment("原工会ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String oldUnionId;
|
||||
|
||||
@Column
|
||||
@Comment("原工会名称")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String oldUnionName;
|
||||
|
||||
@Column
|
||||
@Comment("原代表团ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String oldDbtId;
|
||||
|
||||
@Column
|
||||
@Comment("原代表团名称")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String oldDbtName;
|
||||
|
||||
@Column
|
||||
@Comment("新单位ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String newUnitId;
|
||||
|
||||
@Column
|
||||
@Comment("新单位名称")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 500)
|
||||
private String newUnitName;
|
||||
|
||||
@Column
|
||||
@Comment("新工会ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String newUnionId;
|
||||
|
||||
@Column
|
||||
@Comment("新工会名称")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String newUnionName;
|
||||
|
||||
@Column
|
||||
@Comment("新代表团ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String newDbtId;
|
||||
|
||||
@Column
|
||||
@Comment("新代表团名称")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String newDbtName;
|
||||
}
|
||||
+3
@@ -12,6 +12,9 @@ import org.nutz.dao.interceptor.annotation.PrevInsert;
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Table("teacher_congress_delegate")
|
||||
@TableMeta("{'mysql-charset':'utf8mb4'}")
|
||||
@TableIndexes({
|
||||
@Index(name = "INDEX_TEACHER_CONGRESS_DELEGATE_LOGIN_SESSION", fields = {"loginName", "sessionId"}, unique = false)
|
||||
})
|
||||
@Comment("教代会代表")
|
||||
public class Teacher_congress_delegate extends BaseModel {
|
||||
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package com.budwk.app.zhgh.democratic.teachercongress.delegate.param;
|
||||
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 代表变动记录分页查询参数。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class RepresentativeChangeRecordPageParam extends PageForm {
|
||||
|
||||
/** 新教代会届次ID。 */
|
||||
private String sessionId;
|
||||
|
||||
/** 代表变动后的所属单位ID。 */
|
||||
private String unitId;
|
||||
|
||||
/** 代表变动后的所属分工会ID。 */
|
||||
private String unionId;
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.budwk.app.zhgh.democratic.teachercongress.delegate.service;
|
||||
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.delegate.models.RepresentativeChangeRecord;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.delegate.param.RepresentativeChangeRecordPageParam;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
|
||||
/**
|
||||
* 教代会代表变动记录服务。
|
||||
*/
|
||||
public interface RepresentativeChangeRecordService extends BaseService<RepresentativeChangeRecord> {
|
||||
|
||||
/**
|
||||
* 分页查询代表变动记录,并关联人员及新旧届次名称。
|
||||
*
|
||||
* @param pageForm 分页、关键字及组织筛选条件
|
||||
* @return 代表变动记录分页数据
|
||||
*/
|
||||
Pagination<NutMap> pageData(RepresentativeChangeRecordPageParam pageForm);
|
||||
}
|
||||
+25
@@ -4,6 +4,8 @@ import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.delegate.models.Teacher_congress_delegate;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.delegate.param.TeacherCongressDelegateManagePageParam;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.delegate.param.TeacherCongressDelegateManagePublicUserParam;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.List;
|
||||
@@ -20,4 +22,27 @@ public interface TeacherCongressDelegateService extends BaseService<Teacher_cong
|
||||
void exportXlsx(TeacherCongressDelegateManagePageParam pageForm, HttpServletResponse response);
|
||||
|
||||
void exportDocx(TeacherCongressDelegateManagePageParam pageForm, HttpServletResponse response);
|
||||
|
||||
/**
|
||||
* 查询当前代表团组成范围内、尚未成为本届代表的人员。
|
||||
*
|
||||
* @param param 届次、代表团及关键字参数
|
||||
* @return 候选人员列表
|
||||
*/
|
||||
List<NutMap> listPublicUsers(TeacherCongressDelegateManagePublicUserParam param);
|
||||
|
||||
/**
|
||||
* 根据系统配置的单位或分工会组成关系,为尚未归团的代表自动分配代表团。
|
||||
*
|
||||
* @param sessionId 届次ID
|
||||
* @return 已分配、未分配数量及未分配人员名称
|
||||
*/
|
||||
NutMap allocateDelegations(String sessionId);
|
||||
|
||||
/**
|
||||
* 人员组织变化后,按当前组成模式刷新其当前届次代表及角色归团信息。
|
||||
*
|
||||
* @param userId 用户ID
|
||||
*/
|
||||
void refreshCurrentDelegateOrganization(String userId);
|
||||
}
|
||||
|
||||
+148
@@ -12,13 +12,24 @@ import com.budwk.app.base.utils.CommonDownloadUtil;
|
||||
import com.budwk.app.base.utils.PageUtil;
|
||||
import com.budwk.app.base.utils.SysOfficeTemplateUtil;
|
||||
import com.budwk.app.sys.models.Sys_role;
|
||||
import com.budwk.app.sys.models.Sys_user_role;
|
||||
import com.budwk.app.sys.services.SysRoleService;
|
||||
import com.budwk.app.sys.services.SysUserService;
|
||||
import com.budwk.app.sys.views.View_user;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.zhgh.democratic.proposal.service.common.ProposalCommonService;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.delegate.models.Teacher_congress_delegate;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.delegate.param.TeacherCongressDelegateManagePageParam;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.delegate.param.TeacherCongressDelegateManagePublicUserParam;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.delegate.vo.TeacherCongressDelegateExcelVO;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.prepare.models.Teacher_congress_session;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.prepare.service.TeacherCongressSessionService;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.delegation.constant.TeacherCongressDelegationCompositionMode;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.delegation.models.Teacher_congress_delegation_union;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.delegation.models.Teacher_congress_delegation_unit;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.delegation.service.TeacherCongressDelegationService;
|
||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalConfig;
|
||||
import com.budwk.app.base.exception.BaseException;
|
||||
import com.deepoove.poi.XWPFTemplate;
|
||||
import com.deepoove.poi.config.Configure;
|
||||
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
|
||||
@@ -30,6 +41,8 @@ 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.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
@@ -39,6 +52,8 @@ import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class TeacherCongressDelegateServiceImpl extends BaseServiceImpl<Teacher_congress_delegate> implements TeacherCongressDelegateService {
|
||||
@@ -52,6 +67,139 @@ public class TeacherCongressDelegateServiceImpl extends BaseServiceImpl<Teacher_
|
||||
private SysOfficeTemplateUtil sysOfficeTemplateUtil;
|
||||
@Inject
|
||||
private ProposalCommonService proposalCommonService;
|
||||
@Inject
|
||||
private SysUserService sysUserService;
|
||||
@Inject
|
||||
private TeacherCongressSessionService teacherCongressSessionService;
|
||||
@Inject
|
||||
private TeacherCongressDelegationService teacherCongressDelegationService;
|
||||
|
||||
/**
|
||||
* 查询当前组成模式覆盖的候选人员,并按整个届次排除已存在代表,防止一人重复加入多个代表团。
|
||||
*/
|
||||
@Override
|
||||
public List<NutMap> listPublicUsers(TeacherCongressDelegateManagePublicUserParam param) {
|
||||
TeacherCongressDelegationCompositionMode mode = teacherCongressDelegationService.getCompositionMode();
|
||||
List<String> organizationIds;
|
||||
if (mode == TeacherCongressDelegationCompositionMode.UNION) {
|
||||
organizationIds = dao().query(Teacher_congress_delegation_union.class,
|
||||
Cnd.where(Teacher_congress_delegation_union::getSessionId, "=", param.getSessionId())
|
||||
.and(Teacher_congress_delegation_union::getDelegationId, "=", param.getDelegationId()))
|
||||
.stream().map(Teacher_congress_delegation_union::getUnionId).toList();
|
||||
} else {
|
||||
organizationIds = dao().query(Teacher_congress_delegation_unit.class,
|
||||
Cnd.where(Teacher_congress_delegation_unit::getSessionId, "=", param.getSessionId())
|
||||
.and(Teacher_congress_delegation_unit::getDelegationId, "=", param.getDelegationId()))
|
||||
.stream().map(Teacher_congress_delegation_unit::getUnitId).toList();
|
||||
}
|
||||
if (organizationIds.isEmpty()) {
|
||||
throw new BaseException("代表团没有组成" + mode.getLabel());
|
||||
}
|
||||
|
||||
String organizationColumn = mode == TeacherCongressDelegationCompositionMode.UNION ? "u.unionId" : "u.unitId";
|
||||
Sql sql = Sqls.create("SELECT u.id,u.username AS userName,u.loginname AS loginName,u.unitName,u.unionName " +
|
||||
"FROM vw_user u WHERE u.id NOT IN (SELECT userId FROM teacher_congress_delegate WHERE sessionId=@sessionId) " +
|
||||
"AND " + organizationColumn + " IN (@organizationIds) " +
|
||||
"AND (u.loginname LIKE @keyword OR u.username LIKE @keyword) ORDER BY u.loginname LIMIT 50");
|
||||
sql.setParam("sessionId", param.getSessionId());
|
||||
sql.setParam("organizationIds", organizationIds);
|
||||
sql.setParam("keyword", "%" + param.getKeyWord() + "%");
|
||||
return listMap(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* 为当前届次未归团代表批量解析代表团,同时刷新其届次代表角色,避免重复生成角色关系。
|
||||
*/
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public NutMap allocateDelegations(String sessionId) {
|
||||
List<Teacher_congress_delegate> delegates = query(Cnd.where(Teacher_congress_delegate::getSessionId, "=", sessionId)
|
||||
.and(Teacher_congress_delegate::getDelegationId, "is", null));
|
||||
List<String> unassignedNames = new ArrayList<>();
|
||||
int assignedCount = 0;
|
||||
for (Teacher_congress_delegate delegate : delegates) {
|
||||
String delegationId = teacherCongressDelegationService.resolveDelegationId(sessionId, delegate.getUnitId(), delegate.getUnionId());
|
||||
if (StrUtil.isBlank(delegationId)) {
|
||||
unassignedNames.add(delegate.getUserName() + "(" + delegate.getLoginName() + ")");
|
||||
continue;
|
||||
}
|
||||
delegate.setDelegationId(delegationId);
|
||||
updateIgnoreNull(delegate);
|
||||
replaceDelegateRole(delegate);
|
||||
assignedCount++;
|
||||
}
|
||||
sysUserService.clearCache();
|
||||
return NutMap.NEW().addv("assignedCount", assignedCount)
|
||||
.addv("unassignedCount", unassignedNames.size()).addv("unassignedNames", unassignedNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* 人员组织变更事件只处理当前开启届次;代表身份保留,代表团负责人角色在跨团时清理。
|
||||
*/
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void refreshCurrentDelegateOrganization(String userId) {
|
||||
Teacher_congress_session session = dao().fetch(Teacher_congress_session.class,
|
||||
Cnd.where(Teacher_congress_session::getEnable, "=", true).desc(Teacher_congress_session::getStartDate));
|
||||
if (session == null) {
|
||||
return;
|
||||
}
|
||||
View_user user = dao().fetch(View_user.class, Cnd.where(View_user::getId, "=", userId));
|
||||
if (user == null) {
|
||||
return;
|
||||
}
|
||||
ProposalConfig config = dao().fetch(ProposalConfig.class, Cnd.NEW());
|
||||
if (config != null && config.getSchoolLeaderUnitIds() != null
|
||||
&& StrUtil.isNotBlank(user.getUnitId()) && config.getSchoolLeaderUnitIds().contains(user.getUnitId())) {
|
||||
return;
|
||||
}
|
||||
Teacher_congress_delegate delegate = fetch(Cnd.where(Teacher_congress_delegate::getSessionId, "=", session.getId())
|
||||
.and(Teacher_congress_delegate::getUserId, "=", userId));
|
||||
if (delegate == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String oldDelegationId = delegate.getDelegationId();
|
||||
String newDelegationId = teacherCongressDelegationService.resolveDelegationId(session.getId(), user.getUnitId(), user.getUnionId());
|
||||
delegate.setDelegationId(newDelegationId);
|
||||
delegate.setUnitId(user.getUnitId());
|
||||
delegate.setUnitName(user.getUnitName());
|
||||
delegate.setUnionId(user.getUnionId());
|
||||
delegate.setUnionName(user.getUnionName());
|
||||
delegate.setMobile(user.getMobile());
|
||||
update(delegate);
|
||||
replaceDelegateRole(delegate);
|
||||
if (!java.util.Objects.equals(oldDelegationId, newDelegationId)) {
|
||||
clearDelegationManagerRoles(userId, session.getId());
|
||||
}
|
||||
sysUserService.clearCache();
|
||||
sysRoleService.clearCache();
|
||||
}
|
||||
|
||||
/** 替换代表本届次的同一身份角色,确保角色中的代表团ID与代表表一致。 */
|
||||
private void replaceDelegateRole(Teacher_congress_delegate delegate) {
|
||||
dao().clear(Sys_user_role.class, Cnd.where(Sys_user_role::getUserId, "=", delegate.getUserId())
|
||||
.and(Sys_user_role::getRoleId, "=", delegate.getRoleId())
|
||||
.and(Sys_user_role::getTcSessionId, "=", delegate.getSessionId()));
|
||||
Sys_user_role role = new Sys_user_role();
|
||||
role.setUserId(delegate.getUserId());
|
||||
role.setRoleId(delegate.getRoleId());
|
||||
role.setTcSessionId(delegate.getSessionId());
|
||||
role.setTcDelegationId(delegate.getDelegationId());
|
||||
teacherCongressSessionService.prepareSessionRole(role);
|
||||
dao().insert(role);
|
||||
}
|
||||
|
||||
/** 跨代表团后清理团长、副团长及联络人角色,避免保留原代表团管理权限。 */
|
||||
private void clearDelegationManagerRoles(String userId, String sessionId) {
|
||||
Set<String> roleIds = new HashSet<>();
|
||||
roleIds.add(sysRoleService.getByCode(RoleConstant.TEACHER_CONGRESS_DELEGATION_HEAD).getId());
|
||||
roleIds.add(sysRoleService.getByCode(RoleConstant.TEACHER_CONGRESS_VICE_DELEGATION_HEAD).getId());
|
||||
roleIds.add(sysRoleService.getByCode(RoleConstant.TEACHER_CONGRESS_DELEGATION_CONTACT).getId());
|
||||
dao().clear(Sys_user_role.class, Cnd.where(Sys_user_role::getUserId, "=", userId)
|
||||
.and(Sys_user_role::getTcSessionId, "=", sessionId)
|
||||
.and(Sys_user_role::getRoleId, "in", roleIds));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pagination<Teacher_congress_delegate> pageData(TeacherCongressDelegateManagePageParam pageForm) {
|
||||
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
package com.budwk.app.zhgh.democratic.teachercongress.delegate.service.impl;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.delegate.models.RepresentativeChangeRecord;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.delegate.param.RepresentativeChangeRecordPageParam;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.delegate.service.RepresentativeChangeRecordService;
|
||||
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;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 教代会代表变动记录服务实现。
|
||||
*/
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class RepresentativeChangeRecordServiceImpl extends BaseServiceImpl<RepresentativeChangeRecord>
|
||||
implements RepresentativeChangeRecordService {
|
||||
|
||||
/** 前端排序字段与查询字段映射,避免将未校验字段直接拼入 SQL。 */
|
||||
private static final Map<String, String> SORT_COLUMNS = Map.of(
|
||||
"username", "u.username",
|
||||
"loginname", "u.loginname",
|
||||
"oldJdhName", "oldSession.fullName",
|
||||
"newJdhName", "newSession.fullName",
|
||||
"oldUnitName", "c.oldUnitName",
|
||||
"newUnitName", "c.newUnitName",
|
||||
"oldDbtName", "c.oldDbtName",
|
||||
"newDbtName", "c.newDbtName"
|
||||
);
|
||||
|
||||
public RepresentativeChangeRecordServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询代表变动记录,并关联当前人员姓名、工号及新旧届次名称。
|
||||
*
|
||||
* @param pageForm 分页、关键字及组织筛选条件
|
||||
* @return 可直接供列表展示的分页 Map 数据
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Pagination<NutMap> pageData(RepresentativeChangeRecordPageParam pageForm) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
c.*,
|
||||
u.username,
|
||||
u.loginname,
|
||||
oldSession.fullName AS oldJdhName,
|
||||
newSession.fullName AS newJdhName
|
||||
FROM representative_change_record c
|
||||
LEFT JOIN sys_user u ON c.userId = u.id
|
||||
LEFT JOIN teacher_congress_session oldSession ON oldSession.id = c.oldJdhSession
|
||||
LEFT JOIN teacher_congress_session newSession ON newSession.id = c.newJdhSession
|
||||
$condition
|
||||
""");
|
||||
sql.setCondition(buildCondition(pageForm));
|
||||
return listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* 组装代表变动记录查询条件。单位和分工会均按变动后的组织信息筛选,保持与原系统口径一致。
|
||||
*
|
||||
* @param pageForm 页面查询参数
|
||||
* @return SQL 查询条件及安全排序规则
|
||||
*/
|
||||
private Cnd buildCondition(RepresentativeChangeRecordPageParam pageForm) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.andEX("c.newJdhSession", "=", pageForm.getSessionId());
|
||||
cnd.andEX("c.newUnionId", "=", pageForm.getUnionId());
|
||||
cnd.andEX("c.newUnitId", "=", pageForm.getUnitId());
|
||||
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
||||
String keyword = "%" + pageForm.getSearchKeyword().trim() + "%";
|
||||
cnd.and(Cnd.exps("u.username", "like", keyword)
|
||||
.or("u.loginname", "like", keyword));
|
||||
}
|
||||
|
||||
String sortColumn = SORT_COLUMNS.get(pageForm.getPageOrderName());
|
||||
if (StrUtil.isNotBlank(sortColumn)) {
|
||||
if ("ascending".equalsIgnoreCase(pageForm.getPageOrderBy())) {
|
||||
cnd.asc(sortColumn);
|
||||
} else {
|
||||
cnd.desc(sortColumn);
|
||||
}
|
||||
} else {
|
||||
cnd.desc("c.createdAt");
|
||||
}
|
||||
return cnd;
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package com.budwk.app.zhgh.democratic.teachercongress.delegation.constant;
|
||||
|
||||
/**
|
||||
* 代表团组成模式。
|
||||
*
|
||||
* <p>系统参数 {@code dbtzc} 为 {@code unit} 时按单位组成,
|
||||
* 为 {@code union} 时按分工会组成;空值或非法值统一兼容为单位模式。</p>
|
||||
*/
|
||||
public enum TeacherCongressDelegationCompositionMode {
|
||||
UNIT("unit", "单位"),
|
||||
UNION("union", "分工会");
|
||||
|
||||
private final String code;
|
||||
private final String label;
|
||||
|
||||
TeacherCongressDelegationCompositionMode(String code, String label) {
|
||||
this.code = code;
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将系统参数转换为组成模式,非法配置按历史默认行为使用单位模式。
|
||||
*
|
||||
* @param value 系统参数值
|
||||
* @return 有效组成模式
|
||||
*/
|
||||
public static TeacherCongressDelegationCompositionMode from(String value) {
|
||||
if (UNION.code.equalsIgnoreCase(value)) {
|
||||
return UNION;
|
||||
}
|
||||
return UNIT;
|
||||
}
|
||||
}
|
||||
+35
-51
@@ -170,45 +170,18 @@ public class TeacherCongressDelegationController {
|
||||
@At
|
||||
@SaCheckPermission("tc.delegation")
|
||||
public Result partUnitTransferData(@Valid String delegationId, @Valid String sessionId) {
|
||||
//找出本届次已经设置了代表团的所有单位
|
||||
List<Teacher_congress_delegation_unit> delegationUnits = dao.query(Teacher_congress_delegation_unit.class, Cnd.where("sessionId", "=", sessionId));
|
||||
List<String> unitIds = delegationUnits.stream().map(Teacher_congress_delegation_unit::getUnitId).toList();
|
||||
|
||||
//找出本代表团的单位
|
||||
List<String> selectUnitIds = delegationUnits.stream().filter(unit -> unit.getDelegationId().equals(delegationId)).map(Teacher_congress_delegation_unit::getUnitId).toList();
|
||||
|
||||
SqlExpressionGroup seg = new SqlExpressionGroup();
|
||||
seg.orEX("id", "not in", unitIds);
|
||||
seg.orEX("id", "in", selectUnitIds);
|
||||
|
||||
// Cnd cnd = Cnd.where("unitLevel", "=", 2);
|
||||
Cnd cnd = Cnd.where("unitTypeCode", "=", "1");
|
||||
if (!seg.isEmpty()) {
|
||||
cnd.and(seg);
|
||||
}
|
||||
cnd.asc("unitcode");
|
||||
|
||||
List<Sys_unit> units = dao.query(Sys_unit.class, cnd);
|
||||
|
||||
NutMap transferData = NutMap.NEW().addv("selectUnitIds", selectUnitIds).addv("allUnits", units);
|
||||
return Result.success(transferData);
|
||||
NutMap data = teacherCongressDelegationService.getCompositionTransferData(sessionId, delegationId);
|
||||
// 保留旧接口字段,兼容未同步更新的历史页面调用。
|
||||
data.put("selectUnitIds", data.get("selectedIds"));
|
||||
data.put("allUnits", data.get("allItems"));
|
||||
return Result.success(data);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tc.delegation")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Result partUnitSet(@Valid String delegationId, @Valid String sessionId, @Param("unitIds") String[] unitIds) {
|
||||
dao.clear(Teacher_congress_delegation_unit.class, Cnd.where("delegationId", "=", delegationId).and("sessionId", "=", sessionId));
|
||||
|
||||
List<Teacher_congress_delegation_unit> insertData = Arrays.stream(unitIds).map(unitId -> {
|
||||
Teacher_congress_delegation_unit delegationUnit = new Teacher_congress_delegation_unit();
|
||||
delegationUnit.setUnitId(unitId);
|
||||
delegationUnit.setDelegationId(delegationId);
|
||||
delegationUnit.setSessionId(sessionId);
|
||||
return delegationUnit;
|
||||
}).toList();
|
||||
|
||||
dao.insert(insertData);
|
||||
teacherCongressDelegationService.saveComposition(sessionId, delegationId, unitIds);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@@ -222,24 +195,35 @@ public class TeacherCongressDelegationController {
|
||||
@At
|
||||
@SaCheckPermission("tc.delegation")
|
||||
public Result partUnitPageData(@Valid PageForm pageForm, @Valid String sessionId, @Valid String delegationId) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
t2.id,
|
||||
t2.`name`
|
||||
FROM
|
||||
teacher_congress_delegation_unit t1
|
||||
LEFT JOIN sys_unit t2 ON t2.id = t1.unitId
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("t1.delegationId", "=", delegationId);
|
||||
cnd.and("t1.sessionId", "=", sessionId);
|
||||
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
||||
cnd.where().andLike("t2.name", pageForm.getSearchKeyword());
|
||||
}
|
||||
sql.setCondition(cnd);
|
||||
Pagination pagination = baseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
return Result.success(pagination);
|
||||
return Result.success(teacherCongressDelegationService.pageComposition(pageForm, sessionId, delegationId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前配置模式下的代表团组成选择数据。
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("tc.delegation")
|
||||
public Result compositionTransferData(@Valid String delegationId, @Valid String sessionId) {
|
||||
return Result.success(teacherCongressDelegationService.getCompositionTransferData(sessionId, delegationId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存当前配置模式下的代表团组成关系。
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("tc.delegation")
|
||||
public Result compositionSet(@Valid String delegationId, @Valid String sessionId, @Param("itemIds") String[] itemIds) {
|
||||
teacherCongressDelegationService.saveComposition(sessionId, delegationId, itemIds);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询当前配置模式下的代表团组成关系。
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("tc.delegation")
|
||||
public Result compositionPageData(@Valid PageForm pageForm, @Valid String sessionId, @Valid String delegationId) {
|
||||
return Result.success(teacherCongressDelegationService.pageComposition(pageForm, sessionId, delegationId));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user