diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/config/ProposalConfigTypeController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/config/ProposalConfigTypeController.java index f020cefe..4a3b81dd 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/config/ProposalConfigTypeController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/config/ProposalConfigTypeController.java @@ -8,6 +8,7 @@ import com.budwk.app.base.result.Result; import com.budwk.app.base.service.BaseService; import com.budwk.app.zhgh.democratic.proposal.models.ProposalInfo; import com.budwk.app.zhgh.democratic.proposal.models.ProposalType; +import com.budwk.app.zhgh.democratic.proposal.service.common.ProposalCommonService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiModelProperty; import lombok.extern.slf4j.Slf4j; @@ -33,6 +34,8 @@ public class ProposalConfigTypeController { private Dao dao; @Inject private BaseService baseService; + @Inject + private ProposalCommonService proposalCommonService; @At("") @Ok("beetl:/platform/zhgh/democratic/proposal/config/type/index.html") @@ -47,6 +50,8 @@ public class ProposalConfigTypeController { Sql sql = Sqls.create("select * from proposal_type $condition"); Cnd cnd = Cnd.NEW(); cnd.and(Cnd.likeEX("name", name)); + // 提案类型列表只允许名称和编码参与排序。 + proposalCommonService.applySafeProposalListOrder(cnd, pageForm, "configType"); sql.setCondition(cnd); Pagination pagination = baseService.listPageVO(pageForm, sql, ProposalType.class); return Result.success(pagination); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/config/ProposalConfigUnitController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/config/ProposalConfigUnitController.java index 61cf7986..b5822600 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/config/ProposalConfigUnitController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/config/ProposalConfigUnitController.java @@ -19,6 +19,7 @@ import com.budwk.app.sys.services.SysRoleService; import com.budwk.app.web.commons.auth.utils.SecurityUtil; import com.budwk.app.zhgh.democratic.proposal.models.ProposalConfig; import com.budwk.app.zhgh.democratic.proposal.models.ProposalUndertake; +import com.budwk.app.zhgh.democratic.proposal.service.common.ProposalCommonService; import lombok.extern.slf4j.Slf4j; import org.nutz.aop.interceptor.ioc.TransAop; import org.nutz.dao.Cnd; @@ -54,6 +55,8 @@ public class ProposalConfigUnitController { private BaseService baseService; @Inject private SysRoleService sysRoleService; + @Inject + private ProposalCommonService proposalCommonService; @At("") @Ok("beetl:/platform/zhgh/democratic/proposal/config/unit/index.html") @@ -99,7 +102,10 @@ public class ProposalConfigUnitController { cnd.where().orLike("u2.loginname", pageForm.getSearchKeyword()); cnd.where().orLike("t1.name", pageForm.getSearchKeyword()); } - cnd.asc("t1.code"); + // 承办单位列表未指定有效排序时继续按单位编码升序。 + if (!proposalCommonService.applySafeProposalListOrder(cnd, pageForm, "configUnit")) { + cnd.asc("t1.code"); + } sql.setCondition(cnd); Pagination pagination = baseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); return Result.success(pagination); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/dashboard/ProposalDashboardController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/dashboard/ProposalDashboardController.java index de4450fc..f4b5b30b 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/dashboard/ProposalDashboardController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/dashboard/ProposalDashboardController.java @@ -28,6 +28,7 @@ import org.nutz.mvc.annotation.Param; import java.util.ArrayList; import java.util.List; +import java.util.Map; @IocBean @At("/platform/proposal/dashboard") @@ -35,6 +36,23 @@ import java.util.List; @Ok("json:full") public class ProposalDashboardController { + /** + * 工作台表格允许排序的字段映射,值为查询中的真实字段或安全别名。 + */ + private static final Map DASHBOARD_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("isConsolidation", "info.isConsolidation"), + Map.entry("masterUnitName", "masterUnitName"), + Map.entry("slaveUnitNames", "slaveUnitNames"), + Map.entry("curTaskName", "curTaskName"), + Map.entry("instanceState", "instanceState") + ); + @Inject private ProposalCommonService proposalCommonService; @Inject @@ -178,6 +196,8 @@ public class ProposalDashboardController { } } + // 根据工作台字段白名单追加排序,未选择排序时保持原有查询顺序。 + proposalCommonService.applySafePageOrder(cnd, pageForm, DASHBOARD_ORDER_COLUMNS); sql.setCondition(cnd); Pagination pagination = proposalCommonService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); return Result.success(pagination); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/export/ProposalExportComprehensiveController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/export/ProposalExportComprehensiveController.java index c5110305..aa9fabaa 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/export/ProposalExportComprehensiveController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/export/ProposalExportComprehensiveController.java @@ -7,6 +7,7 @@ import com.budwk.app.base.param.ExportTableColumns; import com.budwk.app.base.result.Result; import com.budwk.app.zhgh.democratic.proposal.param.ProposalQueryComprehensiveParam; import com.budwk.app.zhgh.democratic.proposal.service.ProposalExportService; +import com.budwk.app.zhgh.democratic.proposal.service.common.ProposalCommonService; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.nutz.dao.Cnd; @@ -29,6 +30,8 @@ public class ProposalExportComprehensiveController { @Inject private ProposalExportService proposalExportService; + @Inject + private ProposalCommonService proposalCommonService; @At("") @Ok("beetl:/platform/zhgh/democratic/proposal/export/comprehensive/index.html") @@ -73,6 +76,8 @@ public class ProposalExportComprehensiveController { } ProposalQueryComprehensiveParam.buildSearch(cnd, pageForm); cnd.groupBy("info.id"); + // 综合导出主列表的聚合字段仅通过固定查询别名排序。 + proposalCommonService.applySafeProposalListOrder(cnd, pageForm, "exportComprehensive"); sql.setCondition(cnd); Pagination pagination = proposalExportService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); return Result.success(pagination); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/export/ProposalExportSingleCustomController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/export/ProposalExportSingleCustomController.java index 08972423..a0f1a2c3 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/export/ProposalExportSingleCustomController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/export/ProposalExportSingleCustomController.java @@ -17,6 +17,7 @@ import com.budwk.app.flow.entity.ProcessTask; import com.budwk.app.flow.enums.ProcessTaskStateEnum; import com.budwk.app.flow.vo.ProcessTaskVO; import com.budwk.app.zhgh.democratic.proposal.param.ProposalSearchParam; +import com.budwk.app.zhgh.democratic.proposal.service.common.ProposalCommonService; import com.deepoove.poi.XWPFTemplate; import com.deepoove.poi.config.Configure; import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy; @@ -63,6 +64,8 @@ public class ProposalExportSingleCustomController { @Inject private BaseService baseService; + @Inject + private ProposalCommonService proposalCommonService; @Inject private FlowEngine flowEngine; @@ -100,7 +103,10 @@ public class ProposalExportSingleCustomController { Cnd cnd = Cnd.NEW(); ProposalSearchParam.buildSearch(cnd, pageForm); cnd.groupBy("info.id"); - cnd.desc("info.createdAt"); + // 自定义导出列表未指定有效排序时保留提案创建时间倒序。 + if (!proposalCommonService.applySafeProposalListOrder(cnd, pageForm, "exportSingleCustom")) { + cnd.desc("info.createdAt"); + } sql.setCondition(cnd); Pagination pagination = baseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); return Result.success(pagination); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/query/ProposalQueryAnalysisController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/query/ProposalQueryAnalysisController.java index f816b8aa..4d839728 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/query/ProposalQueryAnalysisController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/query/ProposalQueryAnalysisController.java @@ -6,11 +6,13 @@ import cn.afterturn.easypoi.excel.entity.enmus.ExcelType; import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity; import cn.dev33.satoken.annotation.SaCheckPermission; import cn.hutool.core.util.StrUtil; +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.base.utils.CommonDownloadUtil; import com.budwk.app.sys.models.Sys_dict; import com.budwk.app.sys.services.SysDictService; +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; @@ -31,6 +33,7 @@ import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; @IocBean @@ -40,10 +43,26 @@ import java.util.stream.Collectors; @Api(tags = "提案统计分析") public class ProposalQueryAnalysisController { + /** + * 统计数据表允许排序的字段白名单。 + */ + private static final Set STATISTICS_ORDER_COLUMNS = Set.of( + "dimension", "itemName", "count", "rate" + ); + + /** + * 分析数据表允许排序的字段白名单。 + */ + private static final Set ANALYSIS_ORDER_COLUMNS = Set.of( + "dimension", "total", "categoryCount", "topItem", "topCount", "topRate", "analysis" + ); + @Inject private BaseService baseService; @Inject private SysDictService sysDictService; + @Inject + private ProposalCommonService proposalCommonService; @At("") @Ok("beetl:/platform/zhgh/democratic/proposal/query/analysis/index.html") @@ -51,36 +70,54 @@ public class ProposalQueryAnalysisController { public void index() { } + /** + * 查询提案统计数据。 + * + * @param sessionId 教代会届次ID + * @param dimension 统计维度,为空时返回全部维度 + * @param statisticsOrderName 统计表排序字段 + * @param statisticsOrderBy 统计表排序方向 + * @return 统计行列表,包含维度、分类项、数量和占比 + */ @At @ApiOperation("统计数据") @SaCheckPermission("proposal.query.analysis") - public Result statisticsData(String sessionId, String dimension) { - /* - * 查询参数说明: - * sessionId:教代会届次ID,用于限定统计提案范围; - * dimension:统计维度,可传“提案人单位、提案类型、代表团、立案结果、满意度”,为空时返回全部维度。 - * 返回值:Result.data 为统计行列表,包含 dimension、itemName、count、rate。 - */ + public Result statisticsData(String sessionId, String dimension, String statisticsOrderName, String statisticsOrderBy) { if (StrUtil.isBlank(sessionId)) { return Result.error("请先选择教代会届次"); } - return Result.success(buildStatisticsRows(sessionId, dimension)); + List rows = buildStatisticsRows(sessionId, dimension); + PageForm orderForm = new PageForm(); + orderForm.setPageOrderName(statisticsOrderName); + orderForm.setPageOrderBy(statisticsOrderBy); + // 统计数据生成后按独立白名单执行后端排序。 + proposalCommonService.sortStatisticsRows(rows, orderForm, STATISTICS_ORDER_COLUMNS); + return Result.success(rows); } + /** + * 查询提案分析数据。 + * + * @param sessionId 教代会届次ID + * @param dimension 统计维度,为空时返回全部维度 + * @param analysisOrderName 分析表排序字段 + * @param analysisOrderBy 分析表排序方向 + * @return 分析行列表,包含总量、最高项、最高占比和分析结论 + */ @At @ApiOperation("分析数据") @SaCheckPermission("proposal.query.analysis") - public Result analysisData(String sessionId, String dimension) { - /* - * 查询参数说明: - * sessionId:教代会届次ID,用于限定分析提案范围; - * dimension:统计维度,可传“提案人单位、提案类型、代表团、立案结果、满意度”,为空时返回全部维度。 - * 返回值:Result.data 为分析行列表,包含 dimension、total、categoryCount、topItem、topCount、topRate、analysis。 - */ + public Result analysisData(String sessionId, String dimension, String analysisOrderName, String analysisOrderBy) { if (StrUtil.isBlank(sessionId)) { return Result.error("请先选择教代会届次"); } - return Result.success(buildAnalysisRows(sessionId, dimension)); + List rows = buildAnalysisRows(sessionId, dimension); + PageForm orderForm = new PageForm(); + orderForm.setPageOrderName(analysisOrderName); + orderForm.setPageOrderBy(analysisOrderBy); + // 分析数据生成后按独立白名单执行后端排序。 + proposalCommonService.sortStatisticsRows(rows, orderForm, ANALYSIS_ORDER_COLUMNS); + return Result.success(rows); } @At @@ -94,9 +131,9 @@ public class ProposalQueryAnalysisController { entities.add(new ExcelExportEntity("分类项", "itemName", 30)); entities.add(new ExcelExportEntity("数量", "count", 12)); entities.add(new ExcelExportEntity("占比", "rate", 12)); - ExportParams params = new ExportParams(); - params.setType(ExcelType.XSSF); - Workbook workbook = ExcelExportUtil.exportExcel(params, entities, list); + ExportParams exportParams = new ExportParams(); + exportParams.setType(ExcelType.XSSF); + Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entities, list); CommonDownloadUtil.download("提案统计数据.xlsx", workbook, response); } @@ -114,9 +151,9 @@ public class ProposalQueryAnalysisController { entities.add(new ExcelExportEntity("最高数量", "topCount", 12)); entities.add(new ExcelExportEntity("最高占比", "topRate", 12)); entities.add(new ExcelExportEntity("分析结论", "analysis", 60)); - ExportParams params = new ExportParams(); - params.setType(ExcelType.XSSF); - Workbook workbook = ExcelExportUtil.exportExcel(params, entities, list); + ExportParams exportParams = new ExportParams(); + exportParams.setType(ExcelType.XSSF); + Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entities, list); CommonDownloadUtil.download("提案分析数据.xlsx", workbook, response); } diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/query/ProposalQueryCollectProgressController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/query/ProposalQueryCollectProgressController.java index a0c0abd4..ab386417 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/query/ProposalQueryCollectProgressController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/query/ProposalQueryCollectProgressController.java @@ -27,6 +27,7 @@ import org.nutz.mvc.annotation.Param; import javax.validation.Valid; import java.util.ArrayList; import java.util.List; +import java.util.Map; @IocBean @@ -36,6 +37,20 @@ import java.util.List; @Api(tags = "征集进度查询") public class ProposalQueryCollectProgressController { + /** + * 征集进度表格允许排序的字段映射,值为查询中的真实字段或安全别名。 + */ + private static final Map COLLECT_PROGRESS_ORDER_COLUMNS = Map.ofEntries( + Map.entry("code", "info.code"), + Map.entry("name", "info.name"), + Map.entry("createUserName", "info.createUserName"), + Map.entry("delegationName", "delegationName"), + Map.entry("inviteCount", "inviteCount"), + Map.entry("finishCount", "finishCount"), + Map.entry("curTaskName", "curTaskName"), + Map.entry("instanceState", "instanceState") + ); + static List states = new ArrayList<>() {{ add(NutMap.NEW().addv("code", 10).addv("id", 10).addv("name", "撰写提案")); add(NutMap.NEW().addv("code", 20).addv("id", 20).addv("name", "附议提案")); @@ -83,8 +98,9 @@ public class ProposalQueryCollectProgressController { LEFT JOIN wf_process_task t ON t.processInstanceId = ins.id AND t.taskState = 10 $condition """); - sql.setParam("sessionId", pageForm.getSessionId()); Cnd cnd = Cnd.NEW(); + // 征集进度必须按页面选中的教代会过滤,避免共享参数未处理sessionId导致跨届次查询。 + cnd.andEX("info.sessionId", "=", pageForm.getSessionId()); ProposalQueryComprehensiveParam.buildSearch(cnd, pageForm); SqlExpressionGroup seg = new SqlExpressionGroup(); @@ -106,6 +122,8 @@ public class ProposalQueryCollectProgressController { cnd.and(seg); } cnd.groupBy("info.id"); + // 征集进度包含关联字段和人数统计别名,只允许白名单字段进入排序条件。 + proposalCommonService.applySafePageOrder(cnd, pageForm, COLLECT_PROGRESS_ORDER_COLUMNS); sql.setCondition(cnd); Pagination pagination = proposalCommonService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); List list = (List) pagination.getList(); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/query/ProposalQueryComprehensiveController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/query/ProposalQueryComprehensiveController.java index 28be5a7f..7c6fbb82 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/query/ProposalQueryComprehensiveController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/query/ProposalQueryComprehensiveController.java @@ -25,6 +25,7 @@ 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") @@ -33,6 +34,23 @@ import java.util.Arrays; @Api(tags = "提案综合查询") public class ProposalQueryComprehensiveController { + /** + * 综合查询表格允许排序的字段映射,值为查询中的真实字段或安全别名。 + */ + private static final Map 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 @@ -62,7 +80,8 @@ public class ProposalQueryComprehensiveController { 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 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 @@ -120,6 +139,8 @@ public class ProposalQueryComprehensiveController { } 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); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/query/ProposalQueryDelegationController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/query/ProposalQueryDelegationController.java index 9561967f..65fe6e44 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/query/ProposalQueryDelegationController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/query/ProposalQueryDelegationController.java @@ -1,13 +1,16 @@ 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.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; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; @@ -19,8 +22,10 @@ import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.Ok; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; -import java.util.stream.Collectors; +import java.util.Map; @IocBean @At("/platform/proposal/query/delegation") @@ -29,9 +34,34 @@ import java.util.stream.Collectors; @Api(tags = "代表团提案统计") public class ProposalQueryDelegationController { + /** + * 代表团汇总表固定列的安全排序映射,动态立案结果列在查询时追加。 + */ + private static final Map DELEGATION_SUMMARY_ORDER_COLUMNS = Map.of( + "dbtName", "dbt.name", + "TOTAL", "TOTAL", + "caseRate", "caseRateOrder" + ); + + /** + * 代表团提案明细表允许排序的字段映射。 + */ + private static final Map DELEGATION_PROPOSAL_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("sessionName", "sessionName"), + Map.entry("delegationName", "delegationName"), + Map.entry("curTaskName", "curTaskName") + ); + @Inject private BaseService baseService; + @Inject + private ProposalCommonService proposalCommonService; + @Inject private SysDictService sysDictService; @@ -46,28 +76,45 @@ public class ProposalQueryDelegationController { @At @ApiOperation("代表团提案统计") @SaCheckPermission("proposal.query.delegation") - public Result pageData(String sessionId) { + public Result pageData(PageForm pageForm, String sessionId) { List 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.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 """); - String resultStr = dictList.stream().map(v -> { - return "( select count(1) from proposal_info info where info.delegationId = dbt.id and info.sessionId = dbt.sessionId and info.caseFilingResult= '%s' ) as `%s`".formatted(v.getCode(), v.getCode()); - }).collect(Collectors.joining(",")); - sql.setVar("resultSql", resultStr); + Map summaryOrderColumns = new HashMap<>(DELEGATION_SUMMARY_ORDER_COLUMNS); + List resultSqlParts = new ArrayList<>(); + int resultIndex = 0; + for (Sys_dict dict : dictList) { + String resultCode = dict.getCode(); + // 动态别名仅允许字母、数字和下划线,查询值使用参数绑定,避免字典内容进入SQL结构。 + if (StrUtil.isBlank(resultCode) || !resultCode.matches("[A-Za-z0-9_]+")) { + continue; + } + String paramName = "caseFilingResult" + resultIndex++; + resultSqlParts.add(", (select count(1) from proposal_info info where info.delegationId = dbt.id and info.sessionId = dbt.sessionId and info.caseFilingResult = @" + paramName + ") AS `" + resultCode + "`"); + sql.setParam(paramName, resultCode); + 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")) { } - cnd.asc("dbt.`code`"); + // 未选择排序时保留原有代表团编码升序,选择后仅应用白名单字段。 + if (!proposalCommonService.applySafePageOrder(cnd, pageForm, summaryOrderColumns)) { + cnd.asc("dbt.`code`"); + } sql.setCondition(cnd); return Result.success(baseService.listMap(sql)); } @@ -101,7 +148,18 @@ public class ProposalQueryDelegationController { $condition """); Cnd cnd = Cnd.NEW(); - ProposalSearchParam.buildSearch(cnd, pageForm); + // 先应用明细字段白名单,再隔离公共搜索中的原始排序处理,阻止任意字段进入SQL。 + proposalCommonService.applySafePageOrder(cnd, pageForm, DELEGATION_PROPOSAL_ORDER_COLUMNS); + String requestedOrderName = pageForm.getPageOrderName(); + String requestedOrderBy = pageForm.getPageOrderBy(); + pageForm.setPageOrderName(null); + pageForm.setPageOrderBy(null); + try { + ProposalSearchParam.buildSearch(cnd, pageForm); + } finally { + pageForm.setPageOrderName(requestedOrderName); + pageForm.setPageOrderBy(requestedOrderBy); + } cnd.groupBy("info.id"); sql.setCondition(cnd); Pagination pagination = baseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/query/ProposalQueryHistoryController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/query/ProposalQueryHistoryController.java index 3f3e01ad..27a9a4e3 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/query/ProposalQueryHistoryController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/query/ProposalQueryHistoryController.java @@ -5,6 +5,7 @@ import com.budwk.app.base.page.Pagination; import com.budwk.app.base.result.Result; import com.budwk.app.base.service.BaseService; 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; @@ -18,6 +19,7 @@ import org.nutz.mvc.annotation.Ok; import org.nutz.mvc.annotation.Param; import javax.validation.Valid; +import java.util.Map; @IocBean @At("/platform/proposal/query/history") @@ -26,8 +28,27 @@ import javax.validation.Valid; @Api(tags = "提案管理系统-查询统计-历史提案查询") public class ProposalQueryHistoryController { + /** + * 历史提案表格允许排序的字段映射,值为查询中的真实字段或安全别名。 + */ + private static final Map HISTORY_ORDER_COLUMNS = Map.ofEntries( + Map.entry("code", "info.code"), + Map.entry("name", "info.name"), + Map.entry("createUserName", "info.createUserName"), + Map.entry("sessionName", "sessionName"), + 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; @At("") @Ok("beetl:/platform/zhgh/democratic/proposal/query/history/index.html") @@ -53,7 +74,8 @@ public class ProposalQueryHistoryController { 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 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 @@ -69,6 +91,8 @@ public class ProposalQueryHistoryController { Cnd cnd = Cnd.NEW(); ProposalQueryComprehensiveParam.buildSearch(cnd, pageForm); cnd.groupBy("info.id"); + // 历史查询包含多表字段及聚合别名,只允许白名单字段进入排序条件。 + proposalCommonService.applySafePageOrder(cnd, pageForm, HISTORY_ORDER_COLUMNS); sql.setCondition(cnd); Pagination pagination = baseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); return Result.success(pagination); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/query/ProposalQueryUnitReplyController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/query/ProposalQueryUnitReplyController.java index 811f3976..d726b185 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/query/ProposalQueryUnitReplyController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/query/ProposalQueryUnitReplyController.java @@ -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.PageForm; import com.budwk.app.base.result.Result; import com.budwk.app.flow.engine.util.FlowUtil; import com.budwk.app.flow.entity.ProcessTask; @@ -31,6 +32,15 @@ import java.util.stream.Collectors; @Slf4j @Ok("json:full") public class ProposalQueryUnitReplyController { + + /** + * 承办单位办理统计允许排序的字段白名单。 + */ + private static final Set UNIT_REPLY_ORDER_COLUMNS = Set.of( + "unitName", "sum", "masterSum", "masterReplySum", "masterNoReplySum", + "slaveSum", "slaveReplySum", "slaveNoReplySum" + ); + @Inject private Dao dao; @Inject @@ -45,9 +55,10 @@ public class ProposalQueryUnitReplyController { @At @SaCheckPermission("proposal.query.unitReply") - public Result data(String sessionId, String undertakeUnitId, String caseFilingResult) { + public Result data(PageForm pageForm, String sessionId, String undertakeUnitId, String caseFilingResult) { /* * 查询参数说明: + * pageForm:表格排序字段和排序方向; * sessionId:教代会届次ID,用于限定统计的提案范围; * undertakeUnitId:承办单位ID,用于只统计某个承办单位,为空时统计全部承办单位; * caseFilingResult:立案结果字典值,对应 proposal_info.caseFilingResult,为空时不限制立案结果。 @@ -139,6 +150,8 @@ public class ProposalQueryUnitReplyController { tableData.add(tableRow); }); + // 统计结果生成后在服务层按白名单字段排序,避免前端字段参与任意业务处理。 + proposalCommonService.sortStatisticsRows(tableData, pageForm, UNIT_REPLY_ORDER_COLUMNS); return Result.success().addData(Map.of("tableData", tableData, "slaveNeedReply", slaveNeedReply)); } } diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/query/ProposalQueryYearReportController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/query/ProposalQueryYearReportController.java index 46728b36..2c1e0549 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/query/ProposalQueryYearReportController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/query/ProposalQueryYearReportController.java @@ -21,6 +21,7 @@ import org.nutz.mvc.annotation.Param; import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; +import java.util.Map; @IocBean @At("/platform/proposal/query/yearReport") @@ -29,6 +30,22 @@ import javax.validation.Valid; @Api(tags = "提案年度报告") public class ProposalQueryYearReportController { + /** + * 年度报告表格允许排序的字段映射,值为查询中的真实字段或安全别名。 + */ + private static final Map YEAR_REPORT_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("isConsolidation", "info.isConsolidation"), + Map.entry("undertakeUnits", "undertakeUnitsOrder"), + Map.entry("curTaskName", "curTaskName"), + Map.entry("instanceState", "instanceState") + ); + @Inject private ProposalCommonService proposalCommonService; @@ -56,7 +73,8 @@ public class ProposalQueryYearReportController { 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 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 @@ -70,8 +88,12 @@ public class ProposalQueryYearReportController { $condition """); Cnd cnd = Cnd.NEW(); + // 年度报告必须按页面选中的教代会过滤,避免共享参数未处理sessionId导致跨届次查询。 + cnd.andEX("info.sessionId", "=", pageForm.getSessionId()); ProposalQueryComprehensiveParam.buildSearch(cnd, pageForm); cnd.groupBy("info.id"); + // 年度报告包含多表字段及聚合别名,只允许白名单字段进入排序条件。 + proposalCommonService.applySafePageOrder(cnd, pageForm, YEAR_REPORT_ORDER_COLUMNS); sql.setCondition(cnd); Pagination pagination = proposalCommonService.listPageMap(pageForm.getPageNumber(),pageForm.getPageSize(),sql); return Result.success(pagination); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/query/ProposalUnderTakeSatisfactionController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/query/ProposalUnderTakeSatisfactionController.java index 8bfd4b08..32286e40 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/query/ProposalUnderTakeSatisfactionController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/query/ProposalUnderTakeSatisfactionController.java @@ -1,6 +1,8 @@ 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.PageForm; import com.budwk.app.base.result.Result; import com.budwk.app.flow.engine.util.FlowUtil; import com.budwk.app.flow.entity.ProcessInstance; @@ -10,6 +12,7 @@ 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; @@ -30,10 +33,19 @@ import java.util.stream.Collectors; @Api(tags = "提案承办单位满意度") public class ProposalUnderTakeSatisfactionController { + /** + * 满意度统计固定列的排序白名单,动态满意度列在查询时追加。 + */ + private static final Set SATISFACTION_ORDER_COLUMNS = Set.of( + "unitName", "sum", "masterSum", "slaveSum" + ); + @Inject private Dao dao; @Inject private SysDictService sysDictService; + @Inject + private ProposalCommonService proposalCommonService; @At("") @Ok("beetl:/platform/zhgh/democratic/proposal/query/underTakeSatisfaction/index.html") @@ -42,10 +54,24 @@ public class ProposalUnderTakeSatisfactionController { } + /** + * 查询指定教代会和承办单位的满意度统计结果。 + * + * @param pageForm 表格排序参数 + * @param sessionId 教代会届次ID + * @param undertakeUnitId 承办单位ID + * @return 满意度统计结果 + */ @At @SaCheckPermission("proposal.query.underTake.satisfaction") - public Result data(String sessionId, String undertakeUnitId) { + public Result data(PageForm pageForm, String sessionId, String undertakeUnitId) { List feedbackCodes = sysDictService.getSubListByCode("PROPOSAL_FEEDBACK"); + Set 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); @@ -109,6 +135,8 @@ public class ProposalUnderTakeSatisfactionController { tableData.add(tableRow); }); + // 汇总完成后在服务层执行白名单排序,数字列按数值顺序处理。 + proposalCommonService.sortStatisticsRows(tableData, pageForm, orderColumns); return Result.success(tableData); } diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/senior/ProposalExpeditingController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/senior/ProposalExpeditingController.java index 19ead9f6..c96630de 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/senior/ProposalExpeditingController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/senior/ProposalExpeditingController.java @@ -111,7 +111,10 @@ public class ProposalExpeditingController { ProposalSearchParam.buildSearch(cnd, pageForm); cnd.groupBy("t.id"); - cnd.desc("t.createdAt"); + // 提案催办列表未指定有效排序时保留任务创建时间倒序。 + if (!proposalCommonService.applySafeProposalListOrder(cnd, pageForm, "expediting")) { + cnd.desc("t.createdAt"); + } sql.setCondition(cnd); Pagination pagination = proposalCommonService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); return Result.success(pagination); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/senior/ProposalSeniorBasicController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/senior/ProposalSeniorBasicController.java index abe824cf..6b44aef9 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/senior/ProposalSeniorBasicController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/senior/ProposalSeniorBasicController.java @@ -78,6 +78,8 @@ public class ProposalSeniorBasicController { Cnd cnd = Cnd.NEW(); ProposalQueryComprehensiveParam.buildSearch(cnd, pageForm); cnd.groupBy("info.id"); + // 内容修改列表仅允许页面展示字段参与排序。 + proposalCommonService.applySafeProposalListOrder(cnd, pageForm, "seniorBasic"); sql.setCondition(cnd); Pagination pagination = proposalCommonService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); return Result.success(pagination); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/senior/ProposalSeniorDeleteController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/senior/ProposalSeniorDeleteController.java index 04b326eb..697967b6 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/senior/ProposalSeniorDeleteController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/senior/ProposalSeniorDeleteController.java @@ -78,6 +78,8 @@ public class ProposalSeniorDeleteController { } ProposalQueryComprehensiveParam.buildSearch(cnd, pageForm); cnd.groupBy("info.id"); + // 高级删除列表仅允许页面展示字段参与排序。 + proposalCommonService.applySafeProposalListOrder(cnd, pageForm, "seniorDelete"); sql.setCondition(cnd); Pagination pagination = proposalCommonService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); return Result.success(pagination); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/senior/ProposalSeniorFeedBackController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/senior/ProposalSeniorFeedBackController.java index 2ecc9421..6e57f67a 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/senior/ProposalSeniorFeedBackController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/senior/ProposalSeniorFeedBackController.java @@ -93,6 +93,8 @@ public class ProposalSeniorFeedBackController { ProposalQueryComprehensiveParam.buildSearch(cnd, pageForm); // cnd.and("latestFeedBack.id","is not",null); cnd.groupBy("info.id"); + // 反馈评分修改列表包含反馈计算列,使用页面独立白名单排序。 + proposalCommonService.applySafeProposalListOrder(cnd, pageForm, "seniorFeedback"); sql.setCondition(cnd); Pagination pagination = proposalCommonService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); return Result.success(pagination); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/senior/ProposalSeniorTypeController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/senior/ProposalSeniorTypeController.java index 448488d1..a0d83b3d 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/senior/ProposalSeniorTypeController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/senior/ProposalSeniorTypeController.java @@ -82,6 +82,8 @@ public class ProposalSeniorTypeController { } ProposalQueryComprehensiveParam.buildSearch(cnd, pageForm); cnd.groupBy("info.id"); + // 类型修改列表仅允许页面展示字段参与排序。 + proposalCommonService.applySafeProposalListOrder(cnd, pageForm, "seniorType"); sql.setCondition(cnd); Pagination pagination = proposalCommonService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); return Result.success(pagination); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalAllFinishedController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalAllFinishedController.java index d6d3016a..c4c0f0cd 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalAllFinishedController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalAllFinishedController.java @@ -5,23 +5,23 @@ 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.service.BaseService; -import com.budwk.app.flow.enums.ProcessTaskStateEnum; import com.budwk.app.web.commons.auth.utils.AuthUtil; import com.budwk.app.web.commons.auth.utils.SecurityUtil; import com.budwk.app.zhgh.democratic.proposal.param.ProposalSearchParam; +import com.budwk.app.zhgh.democratic.proposal.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.Static; 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 javax.validation.Valid; -import java.util.List; /** * @version 1.0 @@ -39,6 +39,8 @@ public class ProposalAllFinishedController { @Inject private BaseService baseService; + @Inject + private ProposalCommonService proposalCommonService; @At("") @Ok("beetl:/platform/zhgh/democratic/proposal/transact/allFinished/index.html") @@ -62,7 +64,9 @@ public class ProposalAllFinishedController { ins.variable instanceVariable, ins.processDefineId instanceProcessDefineId FROM wf_process_instance ins - LEFT JOIN proposal_info info ON info.id = ins.businessNo + /* Limit all-finished data to proposal workflow instances and discard other module instances. */ + INNER JOIN wf_process_define def ON def.id = ins.processDefineId AND def.name = 'JDHTA_NC' + 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 @@ -72,9 +76,12 @@ public class ProposalAllFinishedController { cnd.and("ins.state", "=", "20"); if(!AuthUtil.hasRole(RoleConstant.SYSADMIN.name())){ - cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId())); + // Non-admin users can only see proposal flows where they participated in at least one task. + cnd.and(new Static("EXISTS (SELECT 1 FROM wf_process_task wt INNER JOIN wf_process_task_actor wta ON wta.processTaskId = wt.id WHERE wt.processInstanceId = ins.id AND wta.actorId = '" + SecurityUtil.getUserId() + "')")); } ProposalSearchParam.buildSearch(cnd, pageForm); + // 已办结列表仅允许页面展示字段参与排序。 + proposalCommonService.applySafeProposalListOrder(cnd, pageForm, "allFinished"); sql.setCondition(cnd); Pagination pagination = baseService.listPageMap(pageForm.getPageNumber(),pageForm.getPageSize(), sql); return Result.success(pagination); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalCaseCheckController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalCaseCheckController.java index 069da813..f96e9315 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalCaseCheckController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalCaseCheckController.java @@ -10,6 +10,7 @@ import com.budwk.app.web.commons.auth.utils.AuthUtil; import com.budwk.app.web.commons.auth.utils.SecurityUtil; import com.budwk.app.zhgh.democratic.proposal.param.ProposalSearchParam; import com.budwk.app.zhgh.democratic.proposal.service.ProposalCaseCheckService; +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; @@ -42,6 +43,8 @@ public class ProposalCaseCheckController { private BaseService baseService; @Inject private ProposalCaseCheckService proposalCaseCheckService; + @Inject + private ProposalCommonService proposalCommonService; @At("") @Ok("beetl:/platform/zhgh/democratic/proposal/transact/caseCheck/index.html") @@ -104,7 +107,10 @@ public class ProposalCaseCheckController { cnd.andEX("vu.unionId", "=", pageForm.getUnionId()); ProposalSearchParam.buildSearch(cnd, pageForm); cnd.groupBy("t.id"); - cnd.desc("t.createdAt"); + // 委员会审查列表未指定有效排序时保留任务创建时间倒序。 + if (!proposalCommonService.applySafeProposalListOrder(cnd, pageForm, "caseCheck")) { + cnd.desc("t.createdAt"); + } sql.setCondition(cnd); Pagination pagination = baseService.listPageMap(pageForm.getPageNumber(),pageForm.getPageSize(), sql); return Result.success(pagination); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalCommissionerController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalCommissionerController.java index ec5d51cd..91046e88 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalCommissionerController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalCommissionerController.java @@ -85,7 +85,10 @@ public class ProposalCommissionerController { ProposalSearchParam.buildSearch(cnd, pageForm); cnd.and("pco.id", approval ? "is not" : "is", null); cnd.groupBy("t.id"); - cnd.desc("t.createdAt"); + // 委员查询包含统计列,未指定有效排序时保留任务创建时间倒序。 + if (!proposalCommonService.applySafeProposalListOrder(cnd, pageForm, "commissioner")) { + cnd.desc("t.createdAt"); + } sql.setCondition(cnd); Pagination pagination = proposalCommonService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); return Result.success(pagination); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalCommitteeFilingController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalCommitteeFilingController.java index 1da9b452..78306070 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalCommitteeFilingController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalCommitteeFilingController.java @@ -10,6 +10,7 @@ import com.budwk.app.web.commons.auth.utils.AuthUtil; import com.budwk.app.web.commons.auth.utils.SecurityUtil; import com.budwk.app.zhgh.democratic.proposal.param.ProposalSearchParam; import com.budwk.app.zhgh.democratic.proposal.service.ProposalCommitteeFilingService; +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; @@ -40,6 +41,8 @@ public class ProposalCommitteeFilingController { private Dao dao; @Inject private ProposalCommitteeFilingService proposalCommitteeFilingService; + @Inject + private ProposalCommonService proposalCommonService; @At("") @Ok("beetl:/platform/zhgh/democratic/proposal/transact/committeeFiling/index.html") @@ -102,7 +105,10 @@ public class ProposalCommitteeFilingController { cnd.andEX("vu.unionId", "=", pageForm.getUnionId()); ProposalSearchParam.buildSearch(cnd, pageForm); cnd.groupBy("t.id"); - cnd.desc("t.createdAt"); + // 立案审核列表未指定有效排序时保留任务创建时间倒序。 + if (!proposalCommonService.applySafeProposalListOrder(cnd, pageForm, "committeeFiling")) { + cnd.desc("t.createdAt"); + } sql.setCondition(cnd); Pagination pagination = proposalCommitteeFilingService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); return Result.success(pagination); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalCommitteeFilingUnitController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalCommitteeFilingUnitController.java index dae7c618..e2883d49 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalCommitteeFilingUnitController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalCommitteeFilingUnitController.java @@ -118,7 +118,10 @@ public class ProposalCommitteeFilingUnitController { cnd.andEX("vu.unionId", "=", pageForm.getUnionId()); ProposalSearchParam.buildSearch(cnd, pageForm); cnd.groupBy("t.id"); - cnd.desc("t.createdAt"); + // 确认承办单位列表未指定有效排序时保留任务创建时间倒序。 + if (!proposalCommonService.applySafeProposalListOrder(cnd, pageForm, "committeeFilingUnit")) { + cnd.desc("t.createdAt"); + } sql.setCondition(cnd); Pagination pagination = proposalCommitteeFilingUnitService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); return Result.success(pagination); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalControlController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalControlController.java index bb7b3de6..9f77a5ec 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalControlController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalControlController.java @@ -10,6 +10,7 @@ import com.budwk.app.flow.enums.ProcessTaskStateEnum; import com.budwk.app.web.commons.auth.utils.AuthUtil; import com.budwk.app.web.commons.auth.utils.SecurityUtil; import com.budwk.app.zhgh.democratic.proposal.param.ProposalSearchParam; +import com.budwk.app.zhgh.democratic.proposal.service.common.ProposalCommonService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; @@ -33,6 +34,8 @@ public class ProposalControlController { @Inject private BaseService baseService; + @Inject + private ProposalCommonService proposalCommonService; @At("") @Ok("beetl:/platform/zhgh/democratic/proposal/transact/control/index.html") @@ -84,7 +87,10 @@ public class ProposalControlController { ProposalSearchParam.buildSearch(cnd, pageForm); cnd.groupBy("t.id"); - cnd.desc("t.createdAt"); + // 状态调整列表未指定有效排序时保留任务创建时间倒序。 + if (!proposalCommonService.applySafeProposalListOrder(cnd, pageForm, "control")) { + cnd.desc("t.createdAt"); + } sql.setCondition(cnd); Pagination pagination = baseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); return Result.success(pagination); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalDelegationController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalDelegationController.java index eb57d6b9..8249ac24 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalDelegationController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalDelegationController.java @@ -118,7 +118,10 @@ public class ProposalDelegationController { } ProposalSearchParam.buildSearch(cnd, pageForm); cnd.groupBy("t.id"); - cnd.desc("t.createdAt"); + // 团长审核列表未指定有效排序时保留任务创建时间倒序。 + if (!proposalCommonService.applySafeProposalListOrder(cnd, pageForm, "delegation")) { + cnd.desc("t.createdAt"); + } sql.setCondition(cnd); Pagination pagination = baseService.listPageMap(pageForm.getPageNumber(),pageForm.getPageSize(), sql); return Result.success(pagination); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalFeedbackEvaluationController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalFeedbackEvaluationController.java index 22f0086a..537882a7 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalFeedbackEvaluationController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalFeedbackEvaluationController.java @@ -107,7 +107,10 @@ public class ProposalFeedbackEvaluationController { } ProposalSearchParam.buildSearch(cnd, pageForm); cnd.groupBy("t.id"); - cnd.desc("t.createdAt"); + // 反馈评分列表未指定有效排序时保留任务创建时间倒序。 + if (!proposalCommonService.applySafeProposalListOrder(cnd, pageForm, "feedbackEvaluation")) { + cnd.desc("t.createdAt"); + } sql.setCondition(cnd); Pagination pagination = proposalCommonService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); return Result.success(pagination); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalInviteController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalInviteController.java index fba3c315..741abae7 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalInviteController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalInviteController.java @@ -6,7 +6,6 @@ import cn.hutool.core.util.StrUtil; import com.budwk.app.base.page.Pagination; import com.budwk.app.base.param.PageForm; import com.budwk.app.base.result.Result; -import com.budwk.app.base.utils.PageUtil; import com.budwk.app.flow.engine.FlowEngine; import com.budwk.app.flow.enums.ProcessTaskStateEnum; import com.budwk.app.web.commons.auth.utils.SecurityUtil; @@ -99,10 +98,9 @@ public class ProposalInviteController { cnd.and("t.taskState", "=", ProcessTaskStateEnum.DOING.getCode()); } - if (StrUtil.isAllBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) { + // 页面排序仅使用邀请列表白名单,未指定有效字段时保留创建时间倒序。 + if (!proposalCommonService.applySafeProposalListOrder(cnd, pageForm, "invite")) { cnd.desc("info.createdAt"); - } else { - cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy())); } cnd.groupBy("t.id"); sql.setCondition(cnd); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalMineController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalMineController.java index 538aaca7..fa81cbb8 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalMineController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalMineController.java @@ -62,6 +62,28 @@ import java.util.Objects; @Ok("json:full") @Api(tags = "提案管理-我的提案") public class ProposalMineController { + /** 我的提案列表允许排序的页面字段与 SQL 字段映射。 */ + private static final Map MINE_ORDER_COLUMNS = Map.of( + "code", "info.code", + "name", "info.name", + "createTime", "info.createTime", + "typeName", "type.name", + "sourceName", "sd.name", + "sessionName", "tcs.fullName", + "taskName", "t.displayName", + "instanceState", "ins.state" + ); + + /** 邀请附议人列表允许排序的页面字段与 SQL 字段映射。 */ + private static final Map SECONDER_ORDER_COLUMNS = Map.of( + "loginName", "t1.loginName", + "userName", "t1.userName", + "sex", "t1.sex", + "unitName", "t1.unitName", + "unionName", "t1.unionName", + "delegationName", "t2.name" + ); + @Inject private Dao dao; @Inject @@ -128,6 +150,8 @@ public class ProposalMineController { cnd.and("info.createdBy", "=", SecurityUtil.getUserId()); ProposalSearchParam.buildSearch(cnd, pageForm); cnd.andEX("info.sessionId", "=", sessionId); + // 排序字段必须经过白名单映射,避免前端参数直接参与 SQL 排序。 + proposalCommonService.applySafePageOrder(cnd, pageForm, MINE_ORDER_COLUMNS); cnd.groupBy("info.id"); sql.setCondition(cnd); Pagination pagination = proposalCommonService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); @@ -255,6 +279,8 @@ public class ProposalMineController { seg.orLike("t1.userName", pageForm.getSearchKeyword()); cnd.and(seg); } + // 邀请列表与主列表使用独立白名单,确保关联表字段排序准确且安全。 + proposalCommonService.applySafePageOrder(cnd, pageForm, SECONDER_ORDER_COLUMNS); sql.setCondition(cnd); Pagination pagination = proposalCommonService.listPageVO(pageForm, sql, ProposalInviteSeconderVO.class); return Result.success(pagination); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalPreAuditController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalPreAuditController.java index 6a60c9e4..e3e7fa16 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalPreAuditController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalPreAuditController.java @@ -9,6 +9,7 @@ import com.budwk.app.flow.enums.ProcessTaskStateEnum; import com.budwk.app.web.commons.auth.utils.AuthUtil; import com.budwk.app.web.commons.auth.utils.SecurityUtil; import com.budwk.app.zhgh.democratic.proposal.param.ProposalSearchParam; +import com.budwk.app.zhgh.democratic.proposal.service.common.ProposalCommonService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; @@ -39,6 +40,8 @@ public class ProposalPreAuditController { @Inject private BaseService baseService; + @Inject + private ProposalCommonService proposalCommonService; @At("") @Ok("beetl:/platform/zhgh/democratic/proposal/transact/preAudit/index.html") @@ -102,7 +105,10 @@ public class ProposalPreAuditController { cnd.andEX("vu.unionId", "=", pageForm.getUnionId()); ProposalSearchParam.buildSearch(cnd, pageForm); cnd.groupBy("t.id"); - cnd.desc("t.createdAt"); + // 预审核列表未指定有效排序时保留任务创建时间倒序。 + if (!proposalCommonService.applySafeProposalListOrder(cnd, pageForm, "preAudit")) { + cnd.desc("t.createdAt"); + } sql.setCondition(cnd); Pagination pagination = baseService.listPageMap(pageForm.getPageNumber(),pageForm.getPageSize(), sql); return Result.success(pagination); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalSchoolLeaderApprovalController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalSchoolLeaderApprovalController.java index dff9ab32..4c8625b4 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalSchoolLeaderApprovalController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalSchoolLeaderApprovalController.java @@ -135,7 +135,10 @@ public class ProposalSchoolLeaderApprovalController { cnd.andEX("vu.unionId", "=", pageForm.getUnionId()); ProposalSearchParam.buildSearch(cnd, pageForm); cnd.groupBy("t.id"); - cnd.desc("t.createdAt"); + // 分管领导审批列表未指定有效排序时保留任务创建时间倒序。 + if (!proposalCommonService.applySafeProposalListOrder(cnd, pageForm, "schoolLeaderApproval")) { + cnd.desc("t.createdAt"); + } sql.setCondition(cnd); Pagination pagination = proposalCommonService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); return Result.success(pagination); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalSecondedController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalSecondedController.java index 326cf7a7..b54cb81a 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalSecondedController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalSecondedController.java @@ -21,6 +21,7 @@ import com.budwk.app.web.commons.auth.utils.SecurityUtil; import com.budwk.app.zhgh.democratic.proposal.models.ProposalSecond; import com.budwk.app.zhgh.democratic.proposal.param.ProposalSearchParam; import com.budwk.app.zhgh.democratic.proposal.service.ProposalSecondedService; +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; @@ -41,6 +42,7 @@ import org.nutz.mvc.annotation.Param; import javax.validation.Valid; import java.util.List; +import java.util.Map; /** * 附议提案 @@ -51,6 +53,17 @@ import java.util.List; @Ok("json:full") @Api(tags = "提案管理系统-提案附议") public class ProposalSecondedController { + /** 提案附议列表允许排序的页面字段与 SQL 字段或查询别名映射。 */ + private static final Map ORDER_COLUMNS = Map.of( + "code", "info.code", + "name", "info.name", + "createUserName", "info.createUserName", + "typeName", "type.name", + "delegationName", "tcd.name", + "taskActorName", "taskActorName", + "curTaskName", "curTaskName", + "instanceState", "ins.state" + ); @Inject private Dao dao; @@ -59,6 +72,8 @@ public class ProposalSecondedController { @Inject private ProposalSecondedService proposalSecondedService; @Inject + private ProposalCommonService proposalCommonService; + @Inject private FlowCommonService flowCommonService; @At("") @@ -141,7 +156,10 @@ public class ProposalSecondedController { } ProposalSearchParam.buildSearch(cnd, pageForm); cnd.groupBy("t.id"); - cnd.desc("t.createdAt"); + // 用户未指定有效排序字段时,继续沿用原有任务创建时间倒序。 + if (!proposalCommonService.applySafePageOrder(cnd, pageForm, ORDER_COLUMNS)) { + cnd.desc("t.createdAt"); + } sql.setCondition(cnd); Pagination pagination = baseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); return Result.success(pagination); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalUnSubmitQueryController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalUnSubmitQueryController.java index 25dd611d..24065458 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalUnSubmitQueryController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalUnSubmitQueryController.java @@ -96,6 +96,8 @@ public class ProposalUnSubmitQueryController { cnd.and("info.sessionId", "=", pageForm.getSessionId()); } + // 未提交查询包含子查询统计列,统一通过页面独立白名单排序。 + proposalCommonService.applySafeProposalListOrder(cnd, pageForm, "unSubmitQuery"); sql.setCondition(cnd); Pagination pagination = proposalCommonService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); return Result.success(pagination); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalUnderTakeReadController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalUnderTakeReadController.java index 4d32fc79..63eda76a 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalUnderTakeReadController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalUnderTakeReadController.java @@ -137,6 +137,8 @@ public class ProposalUnderTakeReadController { ProposalSearchParam.buildSearch(cnd, pageForm); cnd.groupBy("info.id","task.id","JSON_EXTRACT( unit_data.DATA, '$.underTakeId' )"); + // 初步阅览列表的计算字段使用固定查询别名排序。 + proposalCommonService.applySafeProposalListOrder(cnd, pageForm, "unitRead"); // cnd.groupBy("task.id"); // cnd.groupBy("JSON_EXTRACT( unit_data.DATA, '$.underTakeId' ) "); sql.setCondition(cnd); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalUnderTakeReplyController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalUnderTakeReplyController.java index a8fa6146..6219bc61 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalUnderTakeReplyController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalUnderTakeReplyController.java @@ -141,7 +141,10 @@ public class ProposalUnderTakeReplyController { } ProposalSearchParam.buildSearch(cnd, pageForm); cnd.groupBy("t.id"); - cnd.desc("t.createdAt"); + // 承办答复列表未指定有效排序时,继续按任务创建时间倒序。 + if (!proposalCommonService.applySafeProposalListOrder(cnd, pageForm, "unitReply")) { + cnd.desc("t.createdAt"); + } sql.setCondition(cnd); Pagination pagination = proposalCommonService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalUndertakeSuggestionController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalUndertakeSuggestionController.java index 4bfe8140..42252763 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalUndertakeSuggestionController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalUndertakeSuggestionController.java @@ -100,7 +100,10 @@ public class ProposalUndertakeSuggestionController { cnd.groupBy("t.id"); cnd.having(Cnd.where("count", approval ? ">" : "=", 0)); - cnd.desc("t.createdAt"); + // 承办意见列表未指定有效排序时,继续按任务创建时间倒序。 + if (!proposalCommonService.applySafeProposalListOrder(cnd, pageForm, "suggestion")) { + cnd.desc("t.createdAt"); + } sql.setCondition(cnd); Pagination pagination = proposalCommonService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); return Result.success(pagination); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalViceDelegationController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalViceDelegationController.java index 6b0562dd..2a0d0028 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalViceDelegationController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalViceDelegationController.java @@ -80,6 +80,8 @@ public class ProposalViceDelegationController { cnd.and("info.delegationId", "in", proposalCommonService.getSelfManageDelegationIds()); } ProposalSearchParam.buildSearch(cnd, pageForm); + // 副团长查阅列表仅允许页面已展示字段参与排序。 + proposalCommonService.applySafeProposalListOrder(cnd, pageForm, "viceDelegation"); cnd.groupBy("info.id"); sql.setCondition(cnd); Pagination pagination = proposalCommonService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/param/ProposalQueryComprehensiveParam.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/param/ProposalQueryComprehensiveParam.java index 5315291a..f3776cfc 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/param/ProposalQueryComprehensiveParam.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/param/ProposalQueryComprehensiveParam.java @@ -21,6 +21,8 @@ public class ProposalQueryComprehensiveParam extends PageForm { private String code; @ApiModelProperty(name = "教代会ID") private String sessionId; + @ApiModelProperty(name = "search session id") + private String searchSessionId; @ApiModelProperty(name = "教代会ID") private String[] sessionIds; @ApiModelProperty(name = "代表团ID") @@ -79,6 +81,8 @@ public class ProposalQueryComprehensiveParam extends PageForm { } else { // cnd.andEX("info.sessionId", "=", searchParam.getSessionId()); } + // Isolated single-session filter for pages that should not reuse sessionId semantics. + cnd.andEX("info.sessionId", "=", searchParam.getSearchSessionId()); //提案名称 if (StrUtil.isNotBlank(searchParam.getName())) { diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/service/common/ProposalCommonService.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/service/common/ProposalCommonService.java index a416a455..7d6f645d 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/service/common/ProposalCommonService.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/service/common/ProposalCommonService.java @@ -1,17 +1,49 @@ package com.budwk.app.zhgh.democratic.proposal.service.common; import com.budwk.app.base.service.BaseService; +import com.budwk.app.base.param.PageForm; import com.budwk.app.zhgh.democratic.proposal.models.ProposalInfo; import com.budwk.app.zhgh.democratic.proposal.models.ProposalUndertake; +import org.nutz.dao.Cnd; import org.nutz.lang.util.NutMap; import javax.servlet.http.HttpServletResponse; import java.io.ByteArrayOutputStream; import java.util.List; import java.util.Map; +import java.util.Set; public interface ProposalCommonService extends BaseService { + /** + * 按页面允许的字段白名单添加排序条件,避免前端字段直接进入SQL。 + * + * @param cnd 查询条件 + * @param pageForm 分页及排序参数 + * @param allowedOrderColumns 前端字段与数据库字段或查询别名的映射 + * @return 是否成功添加安全排序条件 + */ + boolean applySafePageOrder(Cnd cnd, PageForm pageForm, Map allowedOrderColumns); + + /** + * 按提案列表页面注册的独立字段白名单添加排序条件。 + * + * @param cnd 查询条件 + * @param pageForm 分页及排序参数 + * @param pageCode 提案列表页面代码 + * @return 是否成功添加安全排序条件 + */ + boolean applySafeProposalListOrder(Cnd cnd, PageForm pageForm, String pageCode); + + /** + * 按白名单字段对已汇总的统计结果进行后端排序。 + * + * @param rows 统计结果行 + * @param pageForm 排序字段及方向参数 + * @param allowedOrderColumns 允许排序的统计字段 + */ + void sortStatisticsRows(List rows, PageForm pageForm, Set allowedOrderColumns); + /** * 查询提案信息 */ diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/service/common/ProposalCommonServiceImpl.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/service/common/ProposalCommonServiceImpl.java index 00dc0c2f..f7fb81b2 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/service/common/ProposalCommonServiceImpl.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/service/common/ProposalCommonServiceImpl.java @@ -9,8 +9,10 @@ import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONObject; import com.budwk.app.base.constant.RoleConstant; import com.budwk.app.base.exception.BaseException; +import com.budwk.app.base.param.PageForm; import com.budwk.app.base.service.impl.BaseServiceImpl; 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.flow.constant.FlowConst; import com.budwk.app.flow.engine.FlowEngine; @@ -58,7 +60,9 @@ import javax.servlet.http.HttpServletResponse; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.math.BigDecimal; import java.nio.charset.StandardCharsets; +import java.text.Collator; import java.util.*; import java.util.stream.Collectors; @@ -66,6 +70,9 @@ import java.util.stream.Collectors; @IocBean(args = {"refer:dao"}) public class ProposalCommonServiceImpl extends BaseServiceImpl implements ProposalCommonService { + /** PC端提案列表页面的排序字段白名单,页面代码由对应Controller固定传入。 */ + private static final Map> PROPOSAL_LIST_ORDER_COLUMNS = createProposalListOrderColumns(); + //找出富文本里面上传的图片 static String IMG_SRC_REGEX = "]*src\\s*=\\s*([\"'])(/platform/sys/file/download\\?id=.*?)\\1[^>]*>"; @@ -88,6 +95,178 @@ public class ProposalCommonServiceImpl extends BaseServiceImpl imp super(dao); } + /** + * 使用业务页面提供的字段白名单构建排序条件,非法字段或非法排序方向将被忽略。 + * + * @param cnd 查询条件 + * @param pageForm 分页及排序参数 + * @param allowedOrderColumns 前端字段与数据库字段或查询别名的映射 + * @return 是否成功添加安全排序条件 + */ + @Override + public boolean applySafePageOrder(Cnd cnd, PageForm pageForm, Map allowedOrderColumns) { + if (cnd == null || pageForm == null || allowedOrderColumns == null) { + return false; + } + + // 仅允许白名单中的字段参与排序,防止构造任意SQL排序字段。 + String orderColumn = allowedOrderColumns.get(pageForm.getPageOrderName()); + String orderBy = PageUtil.getOrder(pageForm.getPageOrderBy()); + if (StrUtil.isBlank(orderColumn) || StrUtil.isBlank(orderBy)) { + return false; + } + cnd.orderBy(orderColumn, orderBy); + return true; + } + + /** + * 根据页面代码读取独立白名单并应用排序,未注册页面不会接受前端排序字段。 + * + * @param cnd 查询条件 + * @param pageForm 分页及排序参数 + * @param pageCode 提案列表页面代码 + * @return 是否成功添加安全排序条件 + */ + @Override + public boolean applySafeProposalListOrder(Cnd cnd, PageForm pageForm, String pageCode) { + if (StrUtil.isBlank(pageCode)) { + return false; + } + return applySafePageOrder(cnd, pageForm, PROPOSAL_LIST_ORDER_COLUMNS.get(pageCode)); + } + + /** + * 创建各列表页独立排序白名单,显示字段与真实SQL字段或固定查询别名一一对应。 + * + * @return 不可变的页面排序白名单 + */ + private static Map> createProposalListOrderColumns() { + Map> pages = new HashMap<>(); + pages.put("invite", orderColumns("code", "info.code", "name", "info.name", "typeName", "type.name", "sessionName", "tcs.fullName", "delegationName", "tcd.name", "curTaskName", "curTaskName", "instanceState", "ins.state")); + pages.put("viceDelegation", orderColumns("code", "info.code", "name", "info.name", "typeName", "type.name", "sessionName", "tcs.fullName", "delegationName", "tcd.name", "curTaskName", "curTaskName", "instanceState", "ins.state")); + pages.put("unSubmitQuery", orderColumns("proposalCode", "info.code", "proposalName", "info.name", "username", "vu.username", "mobile", "vu.mobile", "unitName", "vu.unitName", "delegationName", "tcd.name", "typeName", "pt.name", "mannerName", "manner.name", "secondedNum", "secondedNum", "secondedAgreeNum", "secondedAgreeNum", "delegationAudit", "delegationAudit")); + pages.put("unitReply", orderColumns("code", "info.code", "name", "info.name", "typeName", "type.name", "caseFilingResult", "info.caseFilingResult", "merge", "merge", "underTakeName", "underTakeName", "underTakeIsMaster", "underTakeIsMaster", "curTaskName", "curTaskName", "auditUser", "auditUser", "instanceState", "ins.state", "transfer", "transferUserName")); + pages.put("unitRead", orderColumns("code", "info.code", "name", "info.name", "createUserName", "info.createUserName", "delegationName", "tcd.name", "caseFilingResult", "info.caseFilingResult", "isConsolidation", "isConsolidation", "isMasterUnderTake", "isMasterUnderTake", "underTakeName", "underTakeName", "processInstanceNodeName", "inst.processInstanceNodeName")); + pages.put("suggestion", orderColumns("code", "info.code", "name", "info.name", "typeName", "type.name", "sessionName", "tcs.fullName", "delegationName", "tcd.name", "suggestUnits", "info.suggestUnits", "count", "count", "curTaskName", "curTaskName", "instanceState", "ins.state")); + 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("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")); + pages.put("preAudit", standardOrderColumns()); + pages.put("committeeFiling", 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("caseCheck", orderColumns("code", "info.code", "name", "info.name", "createUserName", "info.createUserName", "typeName", "type.name", "sessionName", "tcs.fullName", "delegationName", "tcd.name", "curTaskName", "curTaskName", "instanceState", "ins.state", "finishTime", "t.finishTime")); + pages.put("exportComprehensive", orderColumns("code", "info.code", "name", "info.name", "createUserName", "info.createUserName", "typeName", "type.name", "sessionName", "tcs.fullName", "delegationName", "tcd.name", "caseFilingResult", "info.caseFilingResult", "caseFilingType", "info.caseFilingType", "merge", "merge", "brief", "info.brief", "measures", "info.measures", "undertakeUnits", "masterUnitName", "curTaskName", "curTaskName", "instanceState", "ins.state")); + pages.put("exportSingleCustom", standardOrderColumns()); + 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("seniorDelete", seniorOrderColumns()); + pages.put("seniorFeedback", mergeOrderColumns(seniorOrderColumns(), orderColumns("tf_feedback", "tf_feedback"))); + pages.put("seniorType", seniorOrderColumns()); + return Collections.unmodifiableMap(pages); + } + + /** 创建常规流程列表共用的字段映射。 */ + private static Map standardOrderColumns() { + return orderColumns("code", "info.code", "name", "info.name", "createUserName", "info.createUserName", "typeName", "type.name", "sessionName", "tcs.fullName", "delegationName", "tcd.name", "curTaskName", "curTaskName", "instanceState", "ins.state"); + } + + /** 创建高级管理列表共用的字段映射。 */ + private static Map 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"); + } + + /** + * 按前端字段、SQL字段成对创建不可变映射。 + * + * @param mappings 交替排列的前端字段和SQL字段 + * @return 不可变字段映射 + */ + private static Map orderColumns(String... mappings) { + if (mappings == null || mappings.length % 2 != 0) { + throw new IllegalArgumentException("排序字段映射必须成对配置"); + } + Map columns = new LinkedHashMap<>(); + for (int i = 0; i < mappings.length; i += 2) { + columns.put(mappings[i], mappings[i + 1]); + } + return Collections.unmodifiableMap(columns); + } + + /** 合并基础字段和页面扩展字段,并返回不可变映射。 */ + private static Map mergeOrderColumns(Map base, Map extension) { + Map columns = new LinkedHashMap<>(base); + columns.putAll(extension); + return Collections.unmodifiableMap(columns); + } + + /** + * 按白名单字段对统计结果执行后端排序,数字按数值比较,文本按中文区域规则比较。 + * + * @param rows 统计结果行 + * @param pageForm 排序字段及方向参数 + * @param allowedOrderColumns 允许排序的统计字段 + */ + @Override + public void sortStatisticsRows(List rows, PageForm pageForm, Set allowedOrderColumns) { + if (rows == null || pageForm == null || allowedOrderColumns == null) { + return; + } + String orderName = pageForm.getPageOrderName(); + String orderBy = pageForm.getPageOrderBy(); + boolean ascending = "ascending".equals(orderBy); + boolean descending = "descending".equals(orderBy); + if (StrUtil.isBlank(orderName) || !allowedOrderColumns.contains(orderName) || (!ascending && !descending)) { + return; + } + + // 空值始终排在末尾,降序只反转有效值的比较结果。 + rows.sort((leftRow, rightRow) -> { + Object leftValue = leftRow.get(orderName); + Object rightValue = rightRow.get(orderName); + if (leftValue == null && rightValue == null) { + return 0; + } + if (leftValue == null) { + return 1; + } + if (rightValue == null) { + return -1; + } + int result = compareStatisticsValue(leftValue, rightValue); + return descending ? -result : result; + }); + } + + /** + * 比较统计字段值,兼容不同整数类型以及中文文本。 + * + * @param leftValue 左侧字段值 + * @param rightValue 右侧字段值 + * @return 标准比较结果 + */ + private int compareStatisticsValue(Object leftValue, Object rightValue) { + if (leftValue instanceof Number && rightValue instanceof Number) { + BigDecimal leftNumber = new BigDecimal(leftValue.toString()); + BigDecimal rightNumber = new BigDecimal(rightValue.toString()); + return leftNumber.compareTo(rightNumber); + } + String leftText = String.valueOf(leftValue); + String rightText = String.valueOf(rightValue); + String leftPercent = StrUtil.removeSuffix(leftText, "%"); + String rightPercent = StrUtil.removeSuffix(rightText, "%"); + // 百分比展示值按实际数值比较,避免字符串顺序导致10%排在9%之前。 + if (leftText.endsWith("%") && rightText.endsWith("%") + && NumberUtil.isNumber(leftPercent) && NumberUtil.isNumber(rightPercent)) { + return new BigDecimal(leftPercent).compareTo(new BigDecimal(rightPercent)); + } + return Collator.getInstance(Locale.CHINA).compare(leftText, rightText); + } + @Override public NutMap info(String id) { if (StrUtil.isBlank(id)) { diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/service/impl/ProposalWriteServiceImpl.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/service/impl/ProposalWriteServiceImpl.java index e559478f..a4e08b4e 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/service/impl/ProposalWriteServiceImpl.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/service/impl/ProposalWriteServiceImpl.java @@ -118,7 +118,11 @@ public class ProposalWriteServiceImpl extends BaseServiceImpl impl @Override public List listSourceByCode(String code) { Sys_dict dict = sysDictService.fetch(Cnd.where("code", "=", code)); - return dict == null ? new ArrayList<>() : sysDictService.query(Cnd.where("parentId", "=", Strings.sNull(dict.getId())).asc("location")); + return dict == null ? new ArrayList<>() : sysDictService.query( + Cnd.NEW().where("parentId", "=", Strings.sNull(dict.getId())) + .and("disabled","=",0) + .asc("location") + ); } @Override diff --git a/src/main/java/com/budwk/app/zhgh/democratic/teachercongress/delegation/controller/TeacherCongressDelegationController.java b/src/main/java/com/budwk/app/zhgh/democratic/teachercongress/delegation/controller/TeacherCongressDelegationController.java index fe7a8ba2..a86d1a43 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/teachercongress/delegation/controller/TeacherCongressDelegationController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/teachercongress/delegation/controller/TeacherCongressDelegationController.java @@ -7,7 +7,6 @@ import cn.hutool.core.lang.tree.TreeNode; import cn.hutool.core.lang.tree.TreeUtil; import cn.hutool.core.util.StrUtil; import com.budwk.app.base.constant.RoleConstant; -import com.budwk.app.base.exception.BaseException; import com.budwk.app.base.page.Pagination; import com.budwk.app.base.param.PageForm; import com.budwk.app.base.result.Result; @@ -20,15 +19,14 @@ import com.budwk.app.sys.services.SysUserService; 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.delegation.service.TeacherCongressDelegationService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; 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.entity.Record; import org.nutz.dao.sql.Sql; import org.nutz.dao.util.cri.SqlExpressionGroup; import org.nutz.ioc.aop.Aop; @@ -43,7 +41,6 @@ import org.nutz.mvc.annotation.Param; import javax.validation.Valid; import java.util.Arrays; import java.util.List; -import java.util.Optional; @IocBean @At("/platform/teacherCongress/delegation") @@ -63,6 +60,9 @@ public class TeacherCongressDelegationController { @Inject private SysRoleService sysRoleService; + @Inject + private TeacherCongressDelegationService teacherCongressDelegationService; + @At("") @Ok("beetl:/platform/zhgh/democratic/teachercongress/delegation/index.html") @SaCheckPermission("tc.delegation") @@ -288,97 +288,50 @@ public class TeacherCongressDelegationController { } /** - * 查询团长 + * 查询代表团负责人,副团长返回多条以兼容V3多个副团长。 * - * @param sessionId - * @param delegationId - * @return + * @param sessionId 届次ID + * @param delegationId 代表团ID + * @param type 负责人角色编码 + * @return 负责人列表 */ @At @SaCheckPermission("tc.delegation") public Result headUser(@Valid String sessionId, @Valid String delegationId, @Param(value = "type", df = "TEACHER_CONGRESS_DELEGATION_HEAD") String type) { - Sys_role role = null; - if (type.equals(RoleConstant.TEACHER_CONGRESS_DELEGATION_HEAD.name())) { - role = sysRoleService.getByCode(RoleConstant.TEACHER_CONGRESS_DELEGATION_HEAD); - } else if (type.equals(RoleConstant.TEACHER_CONGRESS_VICE_DELEGATION_HEAD.name())) { - role = sysRoleService.getByCode(RoleConstant.TEACHER_CONGRESS_VICE_DELEGATION_HEAD); - } else if (type.equals(RoleConstant.TEACHER_CONGRESS_DELEGATION_CONTACT.name())) { - role = sysRoleService.getByCode(RoleConstant.TEACHER_CONGRESS_DELEGATION_CONTACT); - } else { - throw new BaseException("参数错误"); - } - - Record record = dao.fetch("sys_user_role", Cnd.where("tcSessionId", "=", sessionId).and("tcDelegationId", "=", delegationId).and("roleId", "=", role.getId())); - String userId = Optional.ofNullable(record).map(r -> r.getString("userId")).orElse(null); - - Sql sql = Sqls.create(""" - SELECT - u.id as userId, - u.loginname as loginName, - u.username as userName, - u.mobile, - n.name as unitName - FROM - sys_user u - LEFT JOIN sys_unit n on n.id = u.unitId - WHERE - u.id = @userId - """); - sql.setParam("userId", userId); - sql.setCallback(Sqls.callback.map()); - dao.execute(sql); - NutMap user = (NutMap) sql.getResult(); - return Result.success().addData(user); + List users = teacherCongressDelegationService.listHeadUsers(sessionId, delegationId, type); + return Result.success().addData(users); } /** - * 设置团长 + * 设置代表团团长、副团长和联络人。 * * @param delegationId 代表团ID * @param sessionId 届次ID - * @param userId 团长id - * @param viceUserId 副团长id - * @param contactUserId 联络人 - * @return + * @param userId 团长ID + * @param viceUserIds 副团长ID数组 + * @param contactUserId 联络人ID + * @return 操作结果 */ @At @SaCheckPermission("tc.delegation") - @Aop(TransAop.READ_COMMITTED) - public Result insertHead(@Valid String delegationId, @Valid String sessionId, @Valid String userId, @Valid String viceUserId, String contactUserId) { - // 团长 - Sys_role role = sysRoleService.getByCode(RoleConstant.TEACHER_CONGRESS_DELEGATION_HEAD); - dao.clear(Sys_user_role.class, Cnd.where(Sys_user_role::getTcDelegationId, "=", delegationId).and(Sys_user_role::getTcSessionId, "=", sessionId).and(Sys_user_role::getRoleId, "=", role.getId())); - dao.insert("sys_user_role", Chain.make("userId", userId).add("roleId", role.getId()).add("tcDelegationId", delegationId).add("tcSessionId", sessionId)); - - // 副团长 - Sys_role role2 = sysRoleService.getByCode(RoleConstant.TEACHER_CONGRESS_VICE_DELEGATION_HEAD); - dao.clear(Sys_user_role.class, Cnd.where(Sys_user_role::getTcDelegationId, "=", delegationId).and(Sys_user_role::getTcSessionId, "=", sessionId).and(Sys_user_role::getRoleId, "=", role2.getId())); - dao.insert("sys_user_role", Chain.make("userId", viceUserId).add("roleId", role2.getId()).add("tcDelegationId", delegationId).add("tcSessionId", sessionId)); - - // 联络人 - Sys_role role3 = sysRoleService.getByCode(RoleConstant.TEACHER_CONGRESS_DELEGATION_CONTACT); - dao.clear(Sys_user_role.class, Cnd.where(Sys_user_role::getTcDelegationId, "=", delegationId).and(Sys_user_role::getTcSessionId, "=", sessionId).and(Sys_user_role::getRoleId, "=", role3.getId())); - dao.insert("sys_user_role", Chain.make("userId", contactUserId).add("roleId", role3.getId()).add("tcDelegationId", delegationId).add("tcSessionId", sessionId)); - - sysUserService.clearCache(); + public Result insertHead(@Valid String delegationId, @Valid String sessionId, @Valid String userId, @Param("viceUserIds") String[] viceUserIds, String contactUserId) { + teacherCongressDelegationService.setHeadUsers(sessionId, delegationId, userId, viceUserIds, contactUserId); return Result.success(); } /** - * 删除团长角色 + * 删除代表团负责人角色。 * - * @param delegationId - * @param sessionId - * @param userId - * @return + * @param delegationId 代表团ID + * @param sessionId 届次ID + * @param userId 用户ID + * @param type 负责人角色编码 + * @return 操作结果 */ @At @SaCheckPermission("tc.delegation") - public Result deleteHead(@Valid String delegationId, @Valid String sessionId, @Valid String userId) { - Sys_role role = sysRoleService.getByCode(RoleConstant.TEACHER_CONGRESS_DELEGATION_HEAD); - //先删除角色 - dao.clear(Sys_user_role.class, Cnd.where(Sys_user_role::getTcDelegationId, "=", delegationId).and(Sys_user_role::getTcSessionId, "=", sessionId).and(Sys_user_role::getRoleId, "=", role.getId()).and(Sys_user_role::getUserId, "=", userId)); - sysUserService.clearCache(); + public Result deleteHead(@Valid String delegationId, @Valid String sessionId, @Valid String userId, @Param(value = "type", df = "TEACHER_CONGRESS_DELEGATION_HEAD") String type) { + teacherCongressDelegationService.deleteHeadUser(sessionId, delegationId, userId, type); return Result.success(); } } diff --git a/src/main/java/com/budwk/app/zhgh/democratic/teachercongress/delegation/service/TeacherCongressDelegationService.java b/src/main/java/com/budwk/app/zhgh/democratic/teachercongress/delegation/service/TeacherCongressDelegationService.java new file mode 100644 index 00000000..7d47a167 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/democratic/teachercongress/delegation/service/TeacherCongressDelegationService.java @@ -0,0 +1,44 @@ +package com.budwk.app.zhgh.democratic.teachercongress.delegation.service; + +import com.budwk.app.base.service.BaseService; +import com.budwk.app.zhgh.democratic.teachercongress.delegation.models.Teacher_congress_delegation; +import org.nutz.lang.util.NutMap; + +import java.util.List; + +/** + * 教代会代表团业务服务。 + */ +public interface TeacherCongressDelegationService extends BaseService { + + /** + * 按角色查询代表团负责人信息。 + * + * @param sessionId 届次ID + * @param delegationId 代表团ID + * @param type 负责人角色编码 + * @return 负责人用户列表 + */ + List listHeadUsers(String sessionId, String delegationId, String type); + + /** + * 设置代表团团长、副团长和联络人。 + * + * @param sessionId 届次ID + * @param delegationId 代表团ID + * @param userId 团长用户ID + * @param viceUserIds 副团长用户ID列表 + * @param contactUserId 联络人用户ID + */ + void setHeadUsers(String sessionId, String delegationId, String userId, String[] viceUserIds, String contactUserId); + + /** + * 删除代表团指定负责人角色。 + * + * @param sessionId 届次ID + * @param delegationId 代表团ID + * @param userId 用户ID + * @param type 负责人角色编码 + */ + void deleteHeadUser(String sessionId, String delegationId, String userId, String type); +} \ No newline at end of file diff --git a/src/main/java/com/budwk/app/zhgh/democratic/teachercongress/delegation/service/impl/TeacherCongressDelegationServiceImpl.java b/src/main/java/com/budwk/app/zhgh/democratic/teachercongress/delegation/service/impl/TeacherCongressDelegationServiceImpl.java new file mode 100644 index 00000000..6d539c7a --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/democratic/teachercongress/delegation/service/impl/TeacherCongressDelegationServiceImpl.java @@ -0,0 +1,164 @@ +package com.budwk.app.zhgh.democratic.teachercongress.delegation.service.impl; + +import cn.hutool.core.util.StrUtil; +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.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.zhgh.democratic.teachercongress.delegation.models.Teacher_congress_delegation; +import com.budwk.app.zhgh.democratic.teachercongress.delegation.service.TeacherCongressDelegationService; +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.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.util.NutMap; + +import java.util.Arrays; +import java.util.List; + +/** + * 教代会代表团业务服务实现。 + */ +@IocBean(args = {"refer:dao"}) +public class TeacherCongressDelegationServiceImpl extends BaseServiceImpl implements TeacherCongressDelegationService { + + @Inject + private SysRoleService sysRoleService; + + @Inject + private SysUserService sysUserService; + + public TeacherCongressDelegationServiceImpl(Dao dao) { + super(dao); + } + + /** + * 按角色查询代表团负责人信息,副团长允许返回多条记录以兼容V3多副团长数据。 + * + * @param sessionId 届次ID + * @param delegationId 代表团ID + * @param type 负责人角色编码 + * @return 负责人用户列表 + */ + @Override + public List listHeadUsers(String sessionId, String delegationId, String type) { + Sys_role role = getHeadRole(type); + Sql sql = Sqls.create(""" + SELECT + u.id as userId, + u.loginname as loginName, + u.username as userName, + u.mobile, + n.name as unitName + FROM + sys_user_role sur + LEFT JOIN sys_user u ON u.id = sur.userId + LEFT JOIN sys_unit n ON n.id = u.unitId + WHERE + sur.tcSessionId = @sessionId + AND sur.tcDelegationId = @delegationId + AND sur.roleId = @roleId + ORDER BY u.loginname + """); + sql.setParam("sessionId", sessionId); + sql.setParam("delegationId", delegationId); + sql.setParam("roleId", role.getId()); + return listMap(sql); + } + + /** + * 设置代表团团长、副团长和联络人,保存前按角色清理旧值,避免同一角色残留脏数据。 + * + * @param sessionId 届次ID + * @param delegationId 代表团ID + * @param userId 团长用户ID + * @param viceUserIds 副团长用户ID列表 + * @param contactUserId 联络人用户ID + */ + @Override + @Aop(TransAop.READ_COMMITTED) + public void setHeadUsers(String sessionId, String delegationId, String userId, String[] viceUserIds, String contactUserId) { + // 团长仍然保持单人设置。 + Sys_role headRole = sysRoleService.getByCode(RoleConstant.TEACHER_CONGRESS_DELEGATION_HEAD); + replaceRoleUsers(sessionId, delegationId, headRole.getId(), new String[]{userId}); + + // 副团长支持多人设置,完整保留V3迁移后的多个副团长关系。 + Sys_role viceHeadRole = sysRoleService.getByCode(RoleConstant.TEACHER_CONGRESS_VICE_DELEGATION_HEAD); + replaceRoleUsers(sessionId, delegationId, viceHeadRole.getId(), viceUserIds); + + // 联络人保持单人设置,未选择时只清理旧联络人。 + Sys_role contactRole = sysRoleService.getByCode(RoleConstant.TEACHER_CONGRESS_DELEGATION_CONTACT); + replaceRoleUsers(sessionId, delegationId, contactRole.getId(), new String[]{contactUserId}); + + sysUserService.clearCache(); + } + + /** + * 删除代表团指定负责人角色,按角色类型精确删除,避免删除副团长时影响团长。 + * + * @param sessionId 届次ID + * @param delegationId 代表团ID + * @param userId 用户ID + * @param type 负责人角色编码 + */ + @Override + @Aop(TransAop.READ_COMMITTED) + public void deleteHeadUser(String sessionId, String delegationId, String userId, String type) { + Sys_role role = getHeadRole(type); + dao().clear(Sys_user_role.class, Cnd.where(Sys_user_role::getTcDelegationId, "=", delegationId) + .and(Sys_user_role::getTcSessionId, "=", sessionId) + .and(Sys_user_role::getRoleId, "=", role.getId()) + .and(Sys_user_role::getUserId, "=", userId)); + sysUserService.clearCache(); + } + /** + * 根据负责人类型解析系统角色,集中校验避免 controller 层出现业务分支。 + * + * @param type 负责人角色编码 + * @return 系统角色 + */ + private Sys_role getHeadRole(String type) { + if (RoleConstant.TEACHER_CONGRESS_DELEGATION_HEAD.name().equals(type)) { + return sysRoleService.getByCode(RoleConstant.TEACHER_CONGRESS_DELEGATION_HEAD); + } + if (RoleConstant.TEACHER_CONGRESS_VICE_DELEGATION_HEAD.name().equals(type)) { + return sysRoleService.getByCode(RoleConstant.TEACHER_CONGRESS_VICE_DELEGATION_HEAD); + } + if (RoleConstant.TEACHER_CONGRESS_DELEGATION_CONTACT.name().equals(type)) { + return sysRoleService.getByCode(RoleConstant.TEACHER_CONGRESS_DELEGATION_CONTACT); + } + throw new BaseException("参数错误"); + } + + /** + * 替换指定角色用户关系,先清理再按去重后的用户ID批量插入。 + * + * @param sessionId 届次ID + * @param delegationId 代表团ID + * @param roleId 角色ID + * @param userIds 用户ID数组 + */ + private void replaceRoleUsers(String sessionId, String delegationId, String roleId, String[] userIds) { + dao().clear(Sys_user_role.class, Cnd.where(Sys_user_role::getTcDelegationId, "=", delegationId) + .and(Sys_user_role::getTcSessionId, "=", sessionId) + .and(Sys_user_role::getRoleId, "=", roleId)); + if (userIds == null || userIds.length == 0) { + return; + } + Arrays.stream(userIds) + .filter(StrUtil::isNotBlank) + .distinct() + .forEach(userId -> dao().insert("sys_user_role", Chain.make("userId", userId) + .add("roleId", roleId) + .add("tcDelegationId", delegationId) + .add("tcSessionId", sessionId))); + } +} \ No newline at end of file diff --git a/src/main/java/com/budwk/app/zhgh/staffmanage/member/controller/apply/MemberApplyBranchUnionApprovalController.java b/src/main/java/com/budwk/app/zhgh/staffmanage/member/controller/apply/MemberApplyBranchUnionApprovalController.java index 24b993b4..d17e8083 100644 --- a/src/main/java/com/budwk/app/zhgh/staffmanage/member/controller/apply/MemberApplyBranchUnionApprovalController.java +++ b/src/main/java/com/budwk/app/zhgh/staffmanage/member/controller/apply/MemberApplyBranchUnionApprovalController.java @@ -98,6 +98,7 @@ public class MemberApplyBranchUnionApprovalController { wf_process_task t LEFT JOIN wf_process_instance ins ON ins.id = t.processInstanceId LEFT JOIN member_apply_record info ON info.id = ins.businessNo + LEFT JOIN vw_user u ON u.id = info.userId 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 rt ON rt.processInstanceId = ins.id AND rt.taskParentId = t.id AND rt.taskState = 10 diff --git a/src/main/java/com/budwk/app/zhgh/staffmanage/member/controller/apply/MemberApplySchoolUnionApprovalController.java b/src/main/java/com/budwk/app/zhgh/staffmanage/member/controller/apply/MemberApplySchoolUnionApprovalController.java index eb5377c3..4f6ca767 100644 --- a/src/main/java/com/budwk/app/zhgh/staffmanage/member/controller/apply/MemberApplySchoolUnionApprovalController.java +++ b/src/main/java/com/budwk/app/zhgh/staffmanage/member/controller/apply/MemberApplySchoolUnionApprovalController.java @@ -113,6 +113,7 @@ public class MemberApplySchoolUnionApprovalController { wf_process_task t LEFT JOIN wf_process_instance ins ON ins.id = t.processInstanceId LEFT JOIN member_apply_record info ON info.id = ins.businessNo + LEFT JOIN vw_user u ON u.id = info.userId 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 rt ON rt.processInstanceId = ins.id AND rt.taskParentId = t.id AND rt.taskState = 10 diff --git a/src/main/java/com/budwk/app/zhgh/staffmanage/member/controller/apply/MemberApplyUnionGroupApprovalController.java b/src/main/java/com/budwk/app/zhgh/staffmanage/member/controller/apply/MemberApplyUnionGroupApprovalController.java index 4e5d3902..f747e094 100644 --- a/src/main/java/com/budwk/app/zhgh/staffmanage/member/controller/apply/MemberApplyUnionGroupApprovalController.java +++ b/src/main/java/com/budwk/app/zhgh/staffmanage/member/controller/apply/MemberApplyUnionGroupApprovalController.java @@ -87,6 +87,7 @@ public class MemberApplyUnionGroupApprovalController { wf_process_task t LEFT JOIN wf_process_instance ins ON ins.id = t.processInstanceId LEFT JOIN member_apply_record info ON info.id = ins.businessNo + LEFT JOIN vw_user u ON u.id = info.userId 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 rt ON rt.processInstanceId = ins.id AND rt.taskParentId = t.id AND rt.taskState = 10 diff --git a/src/main/java/com/budwk/app/zhgh/staffmanage/member/param/pageform/MemberApplyPageForm.java b/src/main/java/com/budwk/app/zhgh/staffmanage/member/param/pageform/MemberApplyPageForm.java index 051166ec..b3999485 100644 --- a/src/main/java/com/budwk/app/zhgh/staffmanage/member/param/pageform/MemberApplyPageForm.java +++ b/src/main/java/com/budwk/app/zhgh/staffmanage/member/param/pageform/MemberApplyPageForm.java @@ -34,6 +34,9 @@ public class MemberApplyPageForm extends PageForm { private String userAttribute; //人员属性 + /** 人员属性多选值,供开启多选查询的页面使用。 */ + private List userAttributes; + public static void buildSearch(Cnd cnd, MemberApplyPageForm pageForm) { if (cnd == null) { cnd = Cnd.NEW(); @@ -50,6 +53,11 @@ public class MemberApplyPageForm extends PageForm { cnd.andEX("info.personType","in",pageForm.getPersonTypes()); cnd.andEX("info.preparedBy","in",pageForm.getPreparedBys()); cnd.andEX("u.aidFundMemberUserType","=",pageForm.getAidFundMemberUserType()); - cnd.andEX("u.userAttribute","=",pageForm.getUserAttribute()); + // 多选值优先使用IN查询;未传多选值时保留原单值查询,兼容其他调用页面。 + if (pageForm.getUserAttributes() != null && !pageForm.getUserAttributes().isEmpty()) { + cnd.and("u.userAttribute", "in", pageForm.getUserAttributes()); + } else { + cnd.andEX("u.userAttribute", "=", pageForm.getUserAttribute()); + } } } diff --git a/src/main/java/com/budwk/app/zhgh/staffmanage/member/param/pageform/MemberChangePageForm.java b/src/main/java/com/budwk/app/zhgh/staffmanage/member/param/pageform/MemberChangePageForm.java index e3b49fe0..85c8cf90 100644 --- a/src/main/java/com/budwk/app/zhgh/staffmanage/member/param/pageform/MemberChangePageForm.java +++ b/src/main/java/com/budwk/app/zhgh/staffmanage/member/param/pageform/MemberChangePageForm.java @@ -47,6 +47,9 @@ public class MemberChangePageForm extends PageForm { @ApiModelProperty("人员属性") private String userAttribute; + @ApiModelProperty("人员属性组") + private List userAttributes; + public void buildSearch(Cnd cnd, String prefix){ if (cnd == null) { @@ -66,6 +69,11 @@ public class MemberChangePageForm extends PageForm { cnd.andEX(prefix + "preparedBy", "in", this.getPreparedBys()); cnd.andEX(prefix + "personType", "in", this.getPersonTypes()); cnd.andEX(prefix + "aidFundMemberUserType", "=", this.getAidFundMemberUserType()); - cnd.andEX(prefix + "userAttribute", "=", this.getUserAttribute()); + // 多选条件优先,兼容仍按单值提交人员属性的旧页面。 + if (this.getUserAttributes() != null && !this.getUserAttributes().isEmpty()) { + cnd.and(prefix + "userAttribute", "in", this.getUserAttributes()); + } else { + cnd.andEX(prefix + "userAttribute", "=", this.getUserAttribute()); + } } } diff --git a/src/main/java/com/budwk/app/zhgh/staffmanage/member/param/pageform/MemberInfoPageForm.java b/src/main/java/com/budwk/app/zhgh/staffmanage/member/param/pageform/MemberInfoPageForm.java index 271f5339..f9558c84 100644 --- a/src/main/java/com/budwk/app/zhgh/staffmanage/member/param/pageform/MemberInfoPageForm.java +++ b/src/main/java/com/budwk/app/zhgh/staffmanage/member/param/pageform/MemberInfoPageForm.java @@ -162,10 +162,11 @@ public class MemberInfoPageForm extends PageForm { } else if (Lang.isNotEmpty(this.getPersonTypes())) { cnd.and(prefix + "personType", "in", this.getPersonTypes()); } - if (StrUtil.isNotBlank(this.getUserAttribute())) { - cnd.and(prefix + "userAttribute", "=", this.getUserAttribute()); - } else if (Lang.isNotEmpty(this.getUserAttributes())) { + // 多选条件优先,兼容仍按单值提交人员属性的旧页面。 + if (Lang.isNotEmpty(this.getUserAttributes())) { cnd.and(prefix + "userAttribute", "in", this.getUserAttributes()); + } else if (StrUtil.isNotBlank(this.getUserAttribute())) { + cnd.and(prefix + "userAttribute", "=", this.getUserAttribute()); } if (StrUtil.isNotBlank(this.getAidFundMemberUserType())) { diff --git a/src/main/java/com/budwk/app/zhgh/staffmanage/member/param/pageform/MemberManagePageForm.java b/src/main/java/com/budwk/app/zhgh/staffmanage/member/param/pageform/MemberManagePageForm.java index 365b24d4..117ab932 100644 --- a/src/main/java/com/budwk/app/zhgh/staffmanage/member/param/pageform/MemberManagePageForm.java +++ b/src/main/java/com/budwk/app/zhgh/staffmanage/member/param/pageform/MemberManagePageForm.java @@ -42,6 +42,9 @@ public class MemberManagePageForm extends PageForm { private String userAttribute; + /** 人员属性多选查询条件。 */ + private List userAttributes; + private String changeType; //变更状态数组 @@ -93,7 +96,12 @@ public class MemberManagePageForm extends PageForm { cnd.andEX("u.sex", "=", pageForm.getSex()); cnd.andEX("u.personType", "=", pageForm.getPersonType()); cnd.andEX("u.aidFundMemberUserType", "=", pageForm.getAidFundMemberUserType()); - cnd.andEX("u.userAttribute", "=", pageForm.getUserAttribute()); + // 多选条件优先,兼容仍按单值提交人员属性的旧页面。 + if (Lang.isNotEmpty(pageForm.getUserAttributes())) { + cnd.and("u.userAttribute", "in", pageForm.getUserAttributes()); + } else { + cnd.andEX("u.userAttribute", "=", pageForm.getUserAttribute()); + } if (StrUtil.isNotBlank(pageForm.getChangeDateBefore()) && StrUtil.isNotBlank(pageForm.getChangeDateEnd())) { cnd.and(new Static(String.format("Date(his.changeTime) >= '%s' and Date(his.changeTime) <= '%s'", pageForm.getChangeDateBefore(), pageForm.getChangeDateEnd()))); @@ -148,7 +156,12 @@ public class MemberManagePageForm extends PageForm { cnd.andEX("record.preparedBy", "=", pageForm.getPreparedBy()); cnd.andEX("record.personType", "=", pageForm.getPersonType()); cnd.andEX("record.aidFundMemberUserType", "=", pageForm.getAidFundMemberUserType()); - cnd.andEX("record.userAttribute", "=", pageForm.getUserAttribute()); + // 历史记录查询与当前会员查询使用一致的人员属性多选规则。 + if (Lang.isNotEmpty(pageForm.getUserAttributes())) { + cnd.and("record.userAttribute", "in", pageForm.getUserAttributes()); + } else { + cnd.andEX("record.userAttribute", "=", pageForm.getUserAttribute()); + } cnd.groupBy("record.id,task.id"); } diff --git a/src/main/java/com/budwk/app/zhgh/staffmanage/member/service/impl/MemberInfoServiceImpl.java b/src/main/java/com/budwk/app/zhgh/staffmanage/member/service/impl/MemberInfoServiceImpl.java index e1617358..b4b203b8 100644 --- a/src/main/java/com/budwk/app/zhgh/staffmanage/member/service/impl/MemberInfoServiceImpl.java +++ b/src/main/java/com/budwk/app/zhgh/staffmanage/member/service/impl/MemberInfoServiceImpl.java @@ -396,6 +396,12 @@ public class MemberInfoServiceImpl extends BaseServiceImpl implements cnd.andEX("mh.personType", "=", pageForm.getPersonType()); cnd.andEX("mh.preparedBy", "=", pageForm.getPreparedBy()); cnd.andEX("mh.userState", "=", pageForm.getUserState()); + // 历史台账未复用通用 buildSearch,需要在此显式处理人员属性多选条件。 + if (Lang.isNotEmpty(pageForm.getUserAttributes())) { + cnd.and("mh.userAttribute", "in", pageForm.getUserAttributes()); + } else { + cnd.andEX("mh.userAttribute", "=", pageForm.getUserAttribute()); + } if (StrUtil.isAllNotBlank(pageForm.getMemberSearchName(), pageForm.getMemberSearchKeyWord())) { cnd.and(new SqlExpressionGroup().andLike("u." + pageForm.getMemberSearchName(), pageForm.getMemberSearchKeyWord())); } diff --git a/src/main/java/com/budwk/app/zhgh/staffmanage/member/service/impl/MemberManageServiceImpl.java b/src/main/java/com/budwk/app/zhgh/staffmanage/member/service/impl/MemberManageServiceImpl.java index 03828356..3673b382 100644 --- a/src/main/java/com/budwk/app/zhgh/staffmanage/member/service/impl/MemberManageServiceImpl.java +++ b/src/main/java/com/budwk/app/zhgh/staffmanage/member/service/impl/MemberManageServiceImpl.java @@ -175,6 +175,12 @@ public class MemberManageServiceImpl extends BaseServiceImpl implement cnd.andEX("his.unitId", "=", pageForm.getUnitId()); cnd.andEX("his.personType", "=", pageForm.getPersonType()); cnd.andEX("his.userState", "=", pageForm.getUserState()); + // 变更记录查询自行拼接历史表条件,需要单独补充人员属性多选及旧单值兼容。 + if (Lang.isNotEmpty(pageForm.getUserAttributes())) { + cnd.and("his.userAttribute", "in", pageForm.getUserAttributes()); + } else { + cnd.andEX("his.userAttribute", "=", pageForm.getUserAttribute()); + } if (StrUtil.isNotBlank(pageForm.getChangeType())){ cnd.and(new Static("JSON_CONTAINS(his.changeTypes, JSON_ARRAY('%s'), '$')".formatted(pageForm.getChangeType()))); } diff --git a/src/main/resources/db/evaluate_apply_add_history_import_fields.sql b/src/main/resources/db/evaluate_apply_add_history_import_fields.sql new file mode 100644 index 00000000..c40919dc --- /dev/null +++ b/src/main/resources/db/evaluate_apply_add_history_import_fields.sql @@ -0,0 +1,4 @@ +-- 评优评先申请表新增历史导入来源和类型名称字段。 +ALTER TABLE `evaluate_apply` + ADD COLUMN `source` int(2) DEFAULT 0 COMMENT '来源 0.流程申请 1.历史导入' AFTER `honorTypeId`, + ADD COLUMN `typeName` varchar(200) DEFAULT NULL COMMENT '类型名称' AFTER `source`; diff --git a/src/main/resources/static/components/plugins/sysTextEditor/index.vue b/src/main/resources/static/components/plugins/sysTextEditor/index.vue index 7109db8d..786fa097 100644 --- a/src/main/resources/static/components/plugins/sysTextEditor/index.vue +++ b/src/main/resources/static/components/plugins/sysTextEditor/index.vue @@ -170,6 +170,16 @@ module.exports = { type: Number, default: 300 }, + // 富文本编辑器占位提示,透传给 wangEditor 初始化配置。 + placeholder: { + type: String, + default: "" + }, + // 编辑区顶部红色提示,只做展示,不写入编辑器正文内容。 + topTip: { + type: String, + default: "" + }, menus: { type: Array, default: () => { @@ -205,13 +215,18 @@ module.exports = { data() { return { editor: null, - cursorPos: 0 + cursorPos: 0, + topTipElement: null } }, mounted() { this.initEditor() }, + beforeDestroy() { + this.removeTopTip() + }, + watch: { value: { handler: function (newValue) { @@ -229,6 +244,13 @@ module.exports = { }) }, immediate: true + }, + topTip: { + handler: function () { + this.$nextTick(() => { + this.renderTopTip() + }) + } } }, @@ -266,7 +288,43 @@ module.exports = { this.editor.config.pasteFilterStyle = false this.editor.config.height = this.height this.editor.config.menus = this.menus + // wangEditor 的 placeholder 必须在 create 前设置,父页面传入才会生效。 + this.editor.config.placeholder = this.placeholder this.editor.create() + this.renderTopTip() + }, + renderTopTip() { + if (!this.editor || !this.$refs.editorRef) { + return + } + const textContainer = this.$refs.editorRef.querySelector(".w-e-text-container") + if (!textContainer) { + return + } + if (!this.topTip) { + this.removeTopTip() + return + } + if (!this.topTipElement) { + this.topTipElement = document.createElement("div") + this.topTipElement.setAttribute("contenteditable", "false") + this.topTipElement.style.color = "#f56c6c" + this.topTipElement.style.fontSize = "12px" + this.topTipElement.style.lineHeight = "20px" + this.topTipElement.style.padding = "6px 10px 0" + this.topTipElement.style.userSelect = "none" + this.topTipElement.style.pointerEvents = "none" + } + // 提示节点放在可编辑正文区域外层,保证用户无法删除且保存内容不携带该提示。 + this.topTipElement.innerText = this.topTip + if (textContainer.firstChild !== this.topTipElement) { + textContainer.insertBefore(this.topTipElement, textContainer.firstChild) + } + }, + removeTopTip() { + if (this.topTipElement && this.topTipElement.parentNode) { + this.topTipElement.parentNode.removeChild(this.topTipElement) + } }, uploadFiles(resultFiles) { return resultFiles.map(async (file) => { diff --git a/src/main/resources/static/components/plugins/sysUpload/index.vue b/src/main/resources/static/components/plugins/sysUpload/index.vue index 9ddfa92f..b23d1f16 100644 --- a/src/main/resources/static/components/plugins/sysUpload/index.vue +++ b/src/main/resources/static/components/plugins/sysUpload/index.vue @@ -133,6 +133,12 @@ module.exports = { default: 1024 * 1024 * 10, required: false }, + // 是否限制上传文件大小,默认保留原有大小校验逻辑。 + limit_upload_size: { + type: Boolean, + default: true, + required: false + }, // 上传按钮文字 upload_text: { type: String, @@ -216,7 +222,7 @@ module.exports = { } else { tips = tips + '不限格式;' } - if (fileSize) { + if (this.limit_upload_size && fileSize) { tips = tips + `单个文件大小不能超过${fileSize / 1024 / 1024}M;` } return tips @@ -313,7 +319,8 @@ module.exports = { // 这是兜底逻辑,保准只让这个image类型上传图片 beforeUpload(file) { - if (file.size > this.upload_size) { + // 需要兼容部分业务不限制附件大小,关闭后仅跳过大小校验,不影响数量和格式控制。 + if (this.limit_upload_size && file.size > this.upload_size) { this.$message.error("文件过大,请上传小于" + (this.upload_size / 1024 / 1024).toFixed(0) + "M的文件!") return false } diff --git a/src/main/resources/views/layouts/platform.html b/src/main/resources/views/layouts/platform.html index 3575c275..88818ddc 100644 --- a/src/main/resources/views/layouts/platform.html +++ b/src/main/resources/views/layouts/platform.html @@ -419,6 +419,25 @@ layout("/layouts/v4/baseLayout.html"){ }, defaultSelect() { + // 应用中心点击根菜单时会缓存完整应用信息,根菜单配置了href则应优先进入根菜单页面。 + try { + const rootApp = JSON.parse(window.sessionStorage.getItem("zhgh_sub_app")) + const currentAppId = GetQueryString("appId") + const hasRootHref = rootApp && typeof rootApp.href === "string" && rootApp.href.trim() !== "" + // 校验缓存应用与当前URL一致,避免复用旧标签页缓存时跳转到其他应用。 + if (hasRootHref && String(rootApp.id) === currentAppId) { + this.activeMenuIndex = rootApp.id + this.openedMenus = [] + this.$nextTick(() => { + this.menuSelect(this.activeMenuIndex, this.openedMenus) + commonUtil.pjaxPush(getBaseSubAppPath(rootApp.href)) + }) + return + } + } catch (e) { + // 根菜单缓存缺失或格式异常时,继续使用子菜单href作为默认入口。 + } + // 查找第一个有href的子菜单 function findFirstChildWithHref(menus) { for (const menu of menus) { diff --git a/src/main/resources/views/platform/sys/union/branchUnionGroupManage.js b/src/main/resources/views/platform/sys/union/branchUnionGroupManage.js index 52b19956..1e289846 100644 --- a/src/main/resources/views/platform/sys/union/branchUnionGroupManage.js +++ b/src/main/resources/views/platform/sys/union/branchUnionGroupManage.js @@ -19,7 +19,7 @@ const branchUnionGroupManage = { - + @@ -85,6 +85,11 @@ const branchUnionGroupManage = { union_id: { type: String, required: true + }, + // 工会小组列表包含分页,父页面传入高度后预留分页区域。 + table_height: { + type: Number, + default: null } }, data() { diff --git a/src/main/resources/views/platform/sys/union/branchUnionPartUnitManage.js b/src/main/resources/views/platform/sys/union/branchUnionPartUnitManage.js index 4eef5e20..413730bd 100644 --- a/src/main/resources/views/platform/sys/union/branchUnionPartUnitManage.js +++ b/src/main/resources/views/platform/sys/union/branchUnionPartUnitManage.js @@ -16,7 +16,7 @@ const branchUnionPartUnitManage = { - + @@ -48,6 +48,11 @@ const branchUnionPartUnitManage = { union_id: { type: String, required: true + }, + // 父页面可传入可用高度;默认值保持组件在其他页面的原有展示能力。 + table_height: { + type: Number, + default: null } }, data() { diff --git a/src/main/resources/views/platform/sys/union/branchUnionUserManage.js b/src/main/resources/views/platform/sys/union/branchUnionUserManage.js index 20b71059..87e1ce61 100644 --- a/src/main/resources/views/platform/sys/union/branchUnionUserManage.js +++ b/src/main/resources/views/platform/sys/union/branchUnionUserManage.js @@ -45,7 +45,7 @@ const branchUnionUserManage = { - + @@ -123,6 +123,11 @@ const branchUnionUserManage = { union_id: { type: String, required: true + }, + // 父页面可传入可用高度;默认值保持组件在其他页面的原有展示能力。 + table_height: { + type: Number, + default: null } }, data() { diff --git a/src/main/resources/views/platform/zhgh/democratic/proposal/config/type/index.html b/src/main/resources/views/platform/zhgh/democratic/proposal/config/type/index.html index c887c20c..99febfaa 100644 --- a/src/main/resources/views/platform/zhgh/democratic/proposal/config/type/index.html +++ b/src/main/resources/views/platform/zhgh/democratic/proposal/config/type/index.html @@ -15,10 +15,10 @@ layout("/layouts/platform.html"){ 新增 - + - - + +