From 248b661320f0f05845639ca5c38e251840a2305a Mon Sep 17 00:00:00 2001 From: zhouhefeng Date: Thu, 3 Sep 2026 10:30:00 +0800 Subject: [PATCH] =?UTF-8?q?=E7=A7=BB=E6=A4=8Dv3=E7=96=97=E4=BC=91=E5=85=BB?= =?UTF-8?q?=E5=88=B0=E8=BF=99=E4=B8=AA=E7=89=88=E6=9C=AC=E4=B8=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...uperationEvaluateStatisticsController.java | 6 +- ...uperationFlexibleGroupQueryController.java | 21 +- .../RecuperationLineStatisticsController.java | 21 + .../RecuperationLineStatisticsService.java | 28 + ...uperationProvinceFlexibleGroupService.java | 9 + .../impl/RecuperationEnrollServiceImpl.java | 23 +- ...RecuperationLineStatisticsServiceImpl.java | 213 +++++- ...ationProvinceFlexibleGroupServiceImpl.java | 129 +++- .../flexibleGroupQuery/index.html | 306 +++++++- .../recuperation/lineStatistics/index.html | 445 ++++++++++- .../recuperation/statistics/index.html | 699 +++++++++++++++++- 11 files changed, 1806 insertions(+), 94 deletions(-) diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/controller/RecuperationEvaluateStatisticsController.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/controller/RecuperationEvaluateStatisticsController.java index 517dd69..4aa3bcc 100644 --- a/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/controller/RecuperationEvaluateStatisticsController.java +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/controller/RecuperationEvaluateStatisticsController.java @@ -157,12 +157,14 @@ public class RecuperationEvaluateStatisticsController { List columns = new ArrayList<>(); columns.add(new ExcelExportEntity("序号", "no", 10)); columns.add(new ExcelExportEntity("报名方式", "typeName", 12)); - columns.add(new ExcelExportEntity("方案名称", "schemeName", 24)); + columns.add(new ExcelExportEntity("方案名称", "projectName", 24)); columns.add(new ExcelExportEntity("旅行社", "travelAgencyName", 22)); columns.add(new ExcelExportEntity("评价人", "userName", 14)); columns.add(new ExcelExportEntity("所属单位", "unitName", 24)); columns.add(new ExcelExportEntity("旅行社评分", "evaluationForTravelAgency", 14)); - columns.add(new ExcelExportEntity("住宿/酒店评分", "evaluationForAccommodation", 16)); + String accommodationLabel = "线路".equals(typeName) ? "住宿评分" + : ("灵活组团".equals(typeName) || "定点".equals(typeName) ? "酒店评分" : "住宿/酒店评分"); + columns.add(new ExcelExportEntity(accommodationLabel, "evaluationForAccommodation", 16)); columns.add(new ExcelExportEntity("行程评分", "evaluationForJourney", 14)); columns.add(new ExcelExportEntity("餐饮评分", "evaluationForDining", 14)); columns.add(new ExcelExportEntity("交通评分", "evaluationForTransportation", 14)); diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/controller/RecuperationFlexibleGroupQueryController.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/controller/RecuperationFlexibleGroupQueryController.java index d4afbad..6d3ad5e 100644 --- a/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/controller/RecuperationFlexibleGroupQueryController.java +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/controller/RecuperationFlexibleGroupQueryController.java @@ -62,10 +62,11 @@ public class RecuperationFlexibleGroupQueryController { return Result.success(flexibleGroupService.querySignUsers(pageForm, groupId, groupLeaderUserId, groupLeaderLoginName, noGroupLeader)); } + /** pageForm 传分页信息,groupId 传灵活组团 ID;data 返回全部报名人员的分页结构。 */ @At @SaCheckLogin public Result getAllSignUser(PageForm pageForm, String groupId) { - return Result.success(flexibleGroupService.querySignUsers(pageForm, groupId, null, null, false)); + return Result.success(flexibleGroupService.queryAllSignUsers(pageForm, groupId)); } @At @@ -98,16 +99,16 @@ public class RecuperationFlexibleGroupQueryController { String searchKeyword, HttpServletResponse response) { List columns = new ArrayList<>(); columns.add(new ExcelExportEntity("序号", "no", 10)); - columns.add(new ExcelExportEntity("工号", "loginName", 18)); - columns.add(new ExcelExportEntity("姓名", "userName", 14)); - columns.add(new ExcelExportEntity("联系电话", "mobile", 18)); - columns.add(new ExcelExportEntity("身份证号", "idCard", 24)); - columns.add(new ExcelExportEntity("单位", "unitName", 24)); - columns.add(new ExcelExportEntity("工会", "unionName", 20)); - columns.add(new ExcelExportEntity("旅行社", "travelAgencyName", 22)); + columns.add(new ExcelExportEntity("工号", "loginName", 20)); + columns.add(new ExcelExportEntity("姓名", "userName", 20)); + columns.add(new ExcelExportEntity("联系电话", "mobile", 20)); + columns.add(new ExcelExportEntity("身份证号", "idCard", 30)); + columns.add(new ExcelExportEntity("单位", "unitName", 30)); + columns.add(new ExcelExportEntity("工会", "unionName", 30)); + columns.add(new ExcelExportEntity("旅行社", "travelAgencyName", 30)); columns.add(new ExcelExportEntity("报名时间", "signingUptime", 20)); - columns.add(new ExcelExportEntity("团长", "leaderName", 20)); - columns.add(new ExcelExportEntity("是否成团", "formedTeamState", 14)); + columns.add(new ExcelExportEntity("团长", "leaderName", 25)); + columns.add(new ExcelExportEntity("是否成团", "formedTeamState", 15)); ExportParams exportParams = new ExportParams(); exportParams.setType(ExcelType.XSSF); Workbook workbook = ExcelExportUtil.exportExcel(exportParams, columns, diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/controller/RecuperationLineStatisticsController.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/controller/RecuperationLineStatisticsController.java index ff0e7ad..69da6fa 100644 --- a/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/controller/RecuperationLineStatisticsController.java +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/controller/RecuperationLineStatisticsController.java @@ -13,6 +13,9 @@ import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.Ok; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + /** PC 端线路报名情况及成团通知。 */ @IocBean @At("/platform/recuperation/lineStatistics") @@ -48,6 +51,24 @@ public class RecuperationLineStatisticsController { return Result.success(statisticsService.lineOptions(startYear, endYear, signUpMode, regionalNature)); } + /** lineId 为线路 ID;data 中 selectId 表示具体出行批次,times 为时间及报名人数说明。 */ + @At + @SaCheckPermission("recuperation.lineStatistics") + public Result getLinePlayTimes(String lineId, Integer startYear, Integer endYear) { + return Result.success(statisticsService.linePlayTimeOptions(lineId, startYear, endYear)); + } + + /** 按当前筛选条件导出达到最低成团人数的线路人员,并按线路生成 Excel 压缩包。 */ + @At + @Ok("void") + @SaCheckPermission("recuperation.lineStatistics") + public void doExport(Integer startYear, Integer endYear, String unionId, String takePartInLineId, + String lotId, String selectId, String regionalNature, + HttpServletResponse response) throws IOException { + statisticsService.exportFormedLineUsers(startYear, endYear, unionId, takePartInLineId, + lotId, selectId, regionalNature, response); + } + @At @SaCheckPermission("recuperation.lineStatistics") public Result countSuccessNotice(String id) { return Result.success(enrollService.countLineGroupNoticeUsers(id, true)); } diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/service/RecuperationLineStatisticsService.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/service/RecuperationLineStatisticsService.java index 2564703..f774b20 100644 --- a/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/service/RecuperationLineStatisticsService.java +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/service/RecuperationLineStatisticsService.java @@ -4,6 +4,8 @@ import com.budwk.app.base.page.Pagination; import com.budwk.app.base.param.PageForm; import org.nutz.lang.util.NutMap; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; import java.util.List; /** PC 端线路成团统计查询。 */ @@ -14,4 +16,30 @@ public interface RecuperationLineStatisticsService { Pagination userPage(PageForm pageForm, String lineSelectId, String searchKeyword, String unionId, String unitId); List lineOptions(Integer startYear, Integer endYear, String signUpMode, String regionalNature); + + /** + * 查询指定线路在年度范围内的出行批次选项。 + * + * @param lineId 线路 ID + * @param startYear 开始年度 + * @param endYear 结束年度 + * @return selectId 为工会选线记录 ID,times 为出行时间及报名人数说明 + */ + List linePlayTimeOptions(String lineId, Integer startYear, Integer endYear); + + /** + * 导出达到最低成团人数的线路报名人员。 + * + * @param startYear 开始年度 + * @param endYear 结束年度 + * @param unionId 报名人员所属工会 ID + * @param lineId 线路 ID + * @param lotId 标段 ID + * @param selectId 工会选线记录 ID,用于限定具体出行批次 + * @param regionalNature 线路类型,可传省内、省外或空值 + * @param response 返回 ZIP 文件的 HTTP 响应 + */ + void exportFormedLineUsers(Integer startYear, Integer endYear, String unionId, String lineId, + String lotId, String selectId, String regionalNature, + HttpServletResponse response) throws IOException; } diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/service/RecuperationProvinceFlexibleGroupService.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/service/RecuperationProvinceFlexibleGroupService.java index 7d21595..4d3360f 100644 --- a/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/service/RecuperationProvinceFlexibleGroupService.java +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/service/RecuperationProvinceFlexibleGroupService.java @@ -105,6 +105,15 @@ public interface RecuperationProvinceFlexibleGroupService extends BaseService queryTravelAgencyOptions(Integer startYear, Integer endYear); diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/service/impl/RecuperationEnrollServiceImpl.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/service/impl/RecuperationEnrollServiceImpl.java index 2ec9a3e..617d7e3 100644 --- a/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/service/impl/RecuperationEnrollServiceImpl.java +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/service/impl/RecuperationEnrollServiceImpl.java @@ -1594,7 +1594,7 @@ public class RecuperationEnrollServiceImpl extends BaseServiceImpl'' + WHERE rating.statisticYear=@year AND IFNULL(rating.schemeId,'')<>'' GROUP BY rating.typeName, rating.schemeId, rating.schemeName, rating.travelAgencyName ORDER BY FIELD(rating.typeName,'线路','灵活组团','定点'), rating.schemeName """); @@ -1635,12 +1635,20 @@ public class RecuperationEnrollServiceImpl extends BaseServiceImpl satisfactionFeedbackDetails(Integer year, String typeName) { Sql sql = Sqls.create(""" - SELECT rating.*, + SELECT rating.*, rating.schemeName AS projectName, ROUND(CASE WHEN rating.typeName='线路' THEN (rating.evaluationForTravelAgency+rating.evaluationForJourney+rating.evaluationForAccommodation+rating.evaluationForDining+rating.evaluationForTransportation)/5 ELSE (rating.evaluationForTravelAgency+rating.evaluationForAccommodation)/2 END,1) AS compositeScore FROM ($ratingSql) rating - WHERE rating.feedbackContent IS NOT NULL AND rating.feedbackContent<>'' + WHERE rating.statisticYear=@year AND ( + rating.evaluationForTravelAgency IS NOT NULL + OR rating.evaluationForJourney IS NOT NULL + OR rating.evaluationForAccommodation IS NOT NULL + OR rating.evaluationForDining IS NOT NULL + OR rating.evaluationForTransportation IS NOT NULL + OR rating.evaluationForLine IS NOT NULL + OR IFNULL(rating.feedbackContent,'')<>'' + ) ORDER BY rating.signingUptime DESC """); sql.setVar("ratingSql", satisfactionBaseSql()).setParam("year", year == null ? DateUtil.thisYear() : year); @@ -1652,9 +1660,10 @@ public class RecuperationEnrollServiceImpl extends BaseServiceImpl linePlayTimeOptions(String lineId, Integer startYear, Integer endYear) { + Sql sql = Sqls.create(""" + SELECT lineu.id AS selectId, + CONCAT( + DATE_FORMAT(lineu.playStartTime,'%m月%d日'),'-',DATE_FORMAT(lineu.playEndTime,'%m月%d日'), + '(报名人数:', + COUNT(DISTINCT enroll.loginName) + + IF(COALESCE((SELECT familyInfo FROM the_rapy_recuperation_config LIMIT 1),1)=2, + (SELECT COUNT(1) + FROM the_rapy_recuperation_enroll_companion companion + WHERE companion.trreId IN ( + SELECT signed.id + FROM the_rapy_recuperation_enroll signed + WHERE signed.takePartInLineId=lineu.id + AND signed.isNormal=true + AND signed.stateId NOT IN (2715,2725,2735) + )), + COALESCE(SUM(enroll.familyNumber),0)), + ',其中家属:', + IF(COALESCE((SELECT familyInfo FROM the_rapy_recuperation_config LIMIT 1),1)=2, + (SELECT COUNT(1) + FROM the_rapy_recuperation_enroll_companion companion + WHERE companion.trreId IN ( + SELECT signed.id + FROM the_rapy_recuperation_enroll signed + WHERE signed.takePartInLineId=lineu.id + AND signed.isNormal=true + AND signed.stateId NOT IN (2715,2725,2735) + )), + COALESCE(SUM(enroll.familyNumber),0)), + '人)' + ) AS times + FROM the_rapy_recuperation_line_union_select lineu + LEFT JOIN the_rapy_recuperation_enroll enroll + ON enroll.takePartInLineId=lineu.id + AND enroll.isNormal=true + AND enroll.stateId NOT IN (2715,2725,2735) + $condition + """); + Cnd cnd = Cnd.where("lineu.lineId", "=", lineId) + .andEX("YEAR(lineu.selectTime)", ">=", startYear) + .andEX("YEAR(lineu.selectTime)", "<=", endYear); + if (!AuthUtil.hasRoleOr("sysadmin", "H06", "A06")) { + cnd.and("lineu.unionId", "=", SecurityUtil.getUnionId()); + } + cnd.groupBy("lineu.id", "lineu.playStartTime", "lineu.playEndTime"); + cnd.asc("lineu.playStartTime"); + sql.setCondition(cnd); + return listMap(sql); + } + + @Override + public void exportFormedLineUsers(Integer startYear, Integer endYear, String unionId, String lineId, + String lotId, String selectId, String regionalNature, + HttpServletResponse response) throws IOException { + List exportRows = queryLineExportRows(startYear, endYear, unionId, lineId, lotId, selectId, regionalNature); + RecuperationConfig config = dao().fetch(RecuperationConfig.class, Cnd.NEW()); + Integer minimumGroupSize = config == null ? null : config.getOutsideQuota(); + + Map> batchGroups = exportRows.stream().collect(Collectors.groupingBy( + row -> StrUtil.blankToDefault(row.getString("takePartInLineId"), ""), + LinkedHashMap::new, + Collectors.toList())); + List formedRows = batchGroups.values().stream() + .filter(rows -> isFormedGroup(rows, minimumGroupSize)) + .flatMap(List::stream) + .collect(Collectors.toList()); + Map> lineGroups = formedRows.stream().collect(Collectors.groupingBy( + row -> StrUtil.blankToDefault(row.getString("lineId"), ""), + LinkedHashMap::new, + Collectors.toList())); + + response.setContentType("application/zip"); + response.setHeader("Content-Disposition", "attachment;filename=" + + URLEncoder.encode("疗休养集体线路报名人员名单.zip", StandardCharsets.UTF_8)); + Set zipEntryNames = new HashSet<>(); + try (ZipOutputStream zipOutputStream = new ZipOutputStream(new BufferedOutputStream(response.getOutputStream()))) { + for (List rows : lineGroups.values()) { + String lineName = rows.isEmpty() ? "未命名" : StrUtil.blankToDefault(rows.get(0).getString("lineName"), "未命名"); + writeExcelToZip(zipOutputStream, zipEntryNames, lineName, rows); + } + zipOutputStream.flush(); + } + response.flushBuffer(); + } + + /** 查询导出所需的审核通过线路报名人员,并按当前登录角色限制可见工会。 */ + private List queryLineExportRows(Integer startYear, Integer endYear, String unionId, String lineId, + String lotId, String selectId, String regionalNature) { + Sql sql = Sqls.create(""" + SELECT line.id AS lineId, line.lineName, line.regionalNature, agency.travelAgencyName, + enroll.*, DATE_FORMAT(lineu.playStartTime,'%Y-%m-%d') AS playStartTime, + IF(COALESCE((SELECT familyInfo FROM the_rapy_recuperation_config LIMIT 1),1)=2, + (SELECT COUNT(1) FROM the_rapy_recuperation_enroll_companion companion WHERE companion.trreId=enroll.id), + COALESCE(enroll.familyNumber,0)) AS familyCount, + (SELECT GROUP_CONCAT( + companion.userName,'-',companion.sex,'(',companion.idcard,'、',companion.mobile,')-', + IFNULL(bed.bedType,''),',家属备注:',IFNULL(companion.remark,'') + SEPARATOR ';') + FROM the_rapy_recuperation_enroll_companion companion + LEFT JOIN the_rapy_recuperation_enroll_bed bed ON bed.id=companion.bedInfoId + WHERE companion.trreId=enroll.id) AS companionInfo, + user_info.arrivalAtSchoolDate AS schoolTime + FROM the_rapy_recuperation_enroll enroll + LEFT JOIN sys_user user_info ON user_info.loginname=enroll.loginName + LEFT JOIN the_rapy_recuperation_line_union_select lineu ON lineu.id=enroll.takePartInLineId + LEFT JOIN the_rapy_recuperation_line line ON line.id=lineu.lineId + LEFT JOIN the_rapy_recuperation_travel_agency agency ON agency.id=lineu.travelAgencyId + $condition + """); + Cnd cnd = Cnd.where("enroll.stateId", "=", 2750) + .and("enroll.isNormal", "=", true) + .and("enroll.takePartInLineId", "is not", null) + .and("enroll.takePartInLineId", "!=", "") + .andEX("YEAR(enroll.signingUptime)", ">=", startYear) + .andEX("YEAR(enroll.signingUptime)", "<=", endYear) + .andEX("line.id", "=", lineId) + .andEX("line.lotId", "=", lotId) + .andEX("lineu.id", "=", selectId) + .andEX("line.regionalNature", "=", regionalNature); + if (AuthUtil.hasRoleOr("sysadmin", "H06", "A06")) { + cnd.andEX("enroll.selfUnionId", "=", unionId); + } else { + cnd.and(Cnd.exps("enroll.takePartInUnionId", "=", SecurityUtil.getUnionId()) + .or("enroll.selfUnionId", "=", SecurityUtil.getUnionId())); + } + cnd.asc("line.lineName").asc("lineu.playStartTime").asc("enroll.unionName"); + sql.setCondition(cnd); + List rows = listMap(sql); + rows.forEach(row -> row.setv("remark", RecuperationCommon.getRemarkBySchoolTime(row.getString("schoolTime")))); + return rows; + } + + /** 最低成团人数同时计算去重后的教职工人数和家属人数。 */ + private boolean isFormedGroup(List rows, Integer minimumGroupSize) { + if (minimumGroupSize == null || minimumGroupSize <= 0) { + return false; + } + long teacherCount = rows.stream().map(row -> row.getString("loginName")) + .filter(StrUtil::isNotBlank).distinct().count(); + int familyCount = rows.stream().mapToInt(row -> row.getInt("familyCount", 0)).sum(); + return teacherCount + familyCount >= minimumGroupSize; + } + + /** 每条线路生成一个 XSSF 工作簿后写入 ZIP,避免工作簿内部流与外层 ZIP 冲突。 */ + private void writeExcelToZip(ZipOutputStream zipOutputStream, Set zipEntryNames, + String rawLineName, List rows) throws IOException { + String safeLineName = rawLineName.replaceAll("[\\\\/:*?\"<>|]", "_").replaceAll("[\\r\\n]", "").trim(); + String entryName = "集体线路报名人员/" + StrUtil.blankToDefault(safeLineName, "未命名") + ".xlsx"; + int index = 1; + while (!zipEntryNames.add(entryName)) { + entryName = "集体线路报名人员/" + StrUtil.blankToDefault(safeLineName, "未命名") + "-" + index++ + ".xlsx"; + } + ExportParams exportParams = new ExportParams(); + exportParams.setType(ExcelType.XSSF); + try (Workbook workbook = ExcelExportUtil.exportExcel(exportParams, lineExportColumns(), rows); + ByteArrayOutputStream excelOutputStream = new ByteArrayOutputStream()) { + workbook.write(excelOutputStream); + zipOutputStream.putNextEntry(new ZipEntry(entryName)); + zipOutputStream.write(excelOutputStream.toByteArray()); + zipOutputStream.closeEntry(); + } + } + + /** 旧版成团线路人员导出的列结构。 */ + private List lineExportColumns() { + List columns = new ArrayList<>(); + columns.add(new ExcelExportEntity("姓名", "userName", 20)); + columns.add(new ExcelExportEntity("工号", "loginName", 20)); + columns.add(new ExcelExportEntity("性别", "sex", 10)); + columns.add(new ExcelExportEntity("所属单位", "unitName", 20)); + columns.add(new ExcelExportEntity("所属工会", "unionName", 20)); + columns.add(new ExcelExportEntity("身份证号", "idCard", 30)); + columns.add(new ExcelExportEntity("手机号", "mobile", 15)); + columns.add(new ExcelExportEntity("备注", "remark", 30)); + ExcelExportEntity signingTime = new ExcelExportEntity("报名时间", "signingUptime", 20); + signingTime.setFormat("yyyy-MM-dd HH:mm:ss"); + columns.add(signingTime); + columns.add(new ExcelExportEntity("出行时间", "playStartTime", 20)); + columns.add(new ExcelExportEntity("线路名称", "lineName", 20)); + columns.add(new ExcelExportEntity("旅行社", "travelAgencyName", 20)); + columns.add(new ExcelExportEntity("家属人数", "familyCount", 12)); + ExcelExportEntity companionInfo = new ExcelExportEntity("家属信息", "companionInfo", 50); + companionInfo.setWrap(true); + columns.add(companionInfo); + return columns; + } } diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/service/impl/RecuperationProvinceFlexibleGroupServiceImpl.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/service/impl/RecuperationProvinceFlexibleGroupServiceImpl.java index 6961996..b691f44 100644 --- a/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/service/impl/RecuperationProvinceFlexibleGroupServiceImpl.java +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/service/impl/RecuperationProvinceFlexibleGroupServiceImpl.java @@ -380,6 +380,9 @@ public class RecuperationProvinceFlexibleGroupServiceImpl extends BaseServiceImp @Override public Pagination queryPage(PageForm pageForm, Integer startYear, Integer endYear, String groupName, String travelAgencyId, String searchKeyword) { + if (StrUtil.isNotBlank(searchKeyword)) { + return queryPersonMatchedGroups(pageForm, startYear, endYear, groupName, travelAgencyId, searchKeyword); + } Sql sql = Sqls.create(""" SELECT fg.id, fg.groupName, fg.year, ta.travelAgencyName, COUNT(DISTINCT CASE WHEN enroll.groupLeaderUserId IS NOT NULL AND enroll.groupLeaderUserId <> '' @@ -412,6 +415,53 @@ public class RecuperationProvinceFlexibleGroupServiceImpl extends BaseServiceImp return listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); } + /** 姓名或工号查询时按匹配人员展开,并保留组团总团队数和总报名人数。 */ + private Pagination queryPersonMatchedGroups(PageForm pageForm, Integer startYear, Integer endYear, + String groupName, String travelAgencyId, String searchKeyword) { + Sql sql = Sqls.create(""" + SELECT fg.id, CONCAT(fg.id,'_',enroll.id) AS rowKey, fg.groupName, fg.year, + ta.travelAgencyName, enroll.userName AS signUserName, enroll.loginName AS signLoginName, + (SELECT COUNT(DISTINCT CASE + WHEN grouped.groupLeaderUserId IS NOT NULL AND grouped.groupLeaderUserId<>'' THEN grouped.groupLeaderUserId + WHEN grouped.groupLeaderLoginName IS NOT NULL AND grouped.groupLeaderLoginName<>'' THEN grouped.groupLeaderLoginName + END) + FROM the_rapy_recuperation_enroll grouped + WHERE grouped.takePartInTravelAgencyId=fg.travelAgencyId + AND YEAR(grouped.signingUptime)=fg.year + AND grouped.isNormal=true + AND grouped.stateId NOT IN ($auditFailStates)) AS groupCount, + (SELECT COUNT(DISTINCT grouped.loginName) + FROM the_rapy_recuperation_enroll grouped + WHERE grouped.takePartInTravelAgencyId=fg.travelAgencyId + AND YEAR(grouped.signingUptime)=fg.year + AND grouped.isNormal=true + AND grouped.stateId NOT IN ($auditFailStates)) AS signCount + FROM the_rapy_recuperation_province_flexible_group fg + LEFT JOIN the_rapy_recuperation_travel_agency ta ON ta.id=fg.travelAgencyId + LEFT JOIN the_rapy_recuperation_enroll enroll + ON enroll.takePartInTravelAgencyId=fg.travelAgencyId + AND YEAR(enroll.signingUptime)=fg.year + AND enroll.isNormal=true + AND enroll.stateId NOT IN ($auditFailStates) + $condition + """); + Cnd cnd = Cnd.where("ta.signUpTravelAgency", "=", true) + .andEX("fg.year", ">=", startYear) + .andEX("fg.year", "<=", endYear) + .andEX("fg.travelAgencyId", "=", travelAgencyId) + .and(Cnd.likeEX("fg.groupName", groupName)) + .and(Cnd.exps("enroll.userName", "like", "%" + searchKeyword + "%") + .or("enroll.loginName", "like", "%" + searchKeyword + "%")); + if (!AuthUtil.hasRoleOr("sysadmin", "A06") && AuthUtil.hasRoleOr("H04")) { + cnd.and("fg.createUnionId", "=", SecurityUtil.getUnionId()); + } + cnd.groupBy("fg.id", "enroll.id"); + cnd.desc("fg.year").asc("fg.groupName").asc("enroll.userName"); + sql.setVar("auditFailStates", auditFailStates()); + sql.setCondition(cnd); + return listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); + } + @Override public List queryGroupInfo(String groupId) { Sql sql = Sqls.create(""" @@ -462,11 +512,44 @@ public class RecuperationProvinceFlexibleGroupServiceImpl extends BaseServiceImp return listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); } + @Override + public Pagination queryAllSignUsers(PageForm pageForm, String groupId) { + Sql sql = Sqls.create(""" + SELECT enroll.id, enroll.loginName, enroll.userName, + CASE WHEN enroll.groupLeaderLoginName IS NOT NULL + AND enroll.groupLeaderLoginName<>'' + AND enroll.loginName=enroll.groupLeaderLoginName + THEN '团长' ELSE '队员' END AS identity, + enroll.unionName, enroll.unitName, enroll.sex, enroll.mobile, + (SELECT COUNT(1) FROM the_rapy_recuperation_enroll_companion WHERE trreId=enroll.id) AS isFamily + FROM the_rapy_recuperation_enroll enroll + WHERE enroll.takePartInTravelAgencyId=( + SELECT travelAgencyId FROM the_rapy_recuperation_province_flexible_group WHERE id=@groupId) + AND YEAR(enroll.signingUptime)=( + SELECT year FROM the_rapy_recuperation_province_flexible_group WHERE id=@groupId) + AND enroll.isNormal=true + AND enroll.stateId NOT IN ($auditFailStates) + ORDER BY enroll.groupLeaderUserName, + CASE WHEN enroll.groupLeaderLoginName IS NOT NULL + AND enroll.groupLeaderLoginName<>'' + AND enroll.loginName=enroll.groupLeaderLoginName + THEN 0 ELSE 1 END, + enroll.signingUptime + """); + sql.setParam("groupId", groupId).setVar("auditFailStates", auditFailStates()); + return listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); + } + /** 过滤浏览器可能传入的 undefined/null 文本,避免错误命中团长条件。 */ private boolean isValidGroupLeaderParam(String value) { return StrUtil.isNotBlank(value) && !"undefined".equalsIgnoreCase(value) && !"null".equalsIgnoreCase(value); } + /** 灵活组团查询排除分工会、线路工会和校工会审核失败状态。 */ + private String auditFailStates() { + return RecuperationState.UNITFAIL + "," + RecuperationState.LINEUNITFAIL + "," + RecuperationState.SCHOOLFAIL; + } + @Override public List queryTravelAgencyOptions(Integer startYear, Integer endYear) { Sql sql = Sqls.create(""" @@ -498,24 +581,52 @@ public class RecuperationProvinceFlexibleGroupServiceImpl extends BaseServiceImp Sql sql = Sqls.create(""" SELECT enroll.loginName, enroll.userName, enroll.mobile, enroll.idCard, enroll.unitName, enroll.unionName, ta.travelAgencyName, DATE_FORMAT(enroll.signingUptime,'%Y-%m-%d %H:%i:%s') AS signingUptime, - CONCAT(IFNULL(enroll.groupLeaderUserName,''), IF(enroll.groupLeaderLoginName IS NULL OR enroll.groupLeaderLoginName='', '', CONCAT('(',enroll.groupLeaderLoginName,')'))) AS leaderName, - CASE WHEN (SELECT COUNT(DISTINCT sameLeader.loginName) FROM the_rapy_recuperation_enroll sameLeader - WHERE sameLeader.takePartInTravelAgencyId=enroll.takePartInTravelAgencyId - AND sameLeader.groupLeaderLoginName=enroll.groupLeaderLoginName AND sameLeader.isNormal=true - AND YEAR(sameLeader.signingUptime)=YEAR(enroll.signingUptime))>=3 THEN '已成团' ELSE '未成团' END AS formedTeamState + CASE + WHEN (enroll.groupLeaderUserName IS NULL OR enroll.groupLeaderUserName='') + AND (enroll.groupLeaderLoginName IS NULL OR enroll.groupLeaderLoginName='') THEN '未选择' + WHEN enroll.groupLeaderLoginName IS NULL OR enroll.groupLeaderLoginName='' THEN enroll.groupLeaderUserName + WHEN enroll.groupLeaderUserName IS NULL OR enroll.groupLeaderUserName='' THEN enroll.groupLeaderLoginName + ELSE CONCAT(enroll.groupLeaderUserName,'(',enroll.groupLeaderLoginName,')') + END AS leaderName, + CASE WHEN ( + SELECT COUNT(DISTINCT sameLeader.loginName) + FROM the_rapy_recuperation_enroll sameLeader + WHERE sameLeader.takePartInTravelAgencyId=enroll.takePartInTravelAgencyId + AND ((enroll.groupLeaderUserId IS NOT NULL AND enroll.groupLeaderUserId<>'' + AND sameLeader.groupLeaderUserId=enroll.groupLeaderUserId) + OR (enroll.groupLeaderLoginName IS NOT NULL AND enroll.groupLeaderLoginName<>'' + AND sameLeader.groupLeaderLoginName=enroll.groupLeaderLoginName)) + AND YEAR(sameLeader.signingUptime)=YEAR(enroll.signingUptime) + AND sameLeader.isNormal=true + AND sameLeader.stateId NOT IN ($auditFailStates) + )>=3 THEN '已成团' ELSE '未成团' END AS formedTeamState FROM the_rapy_recuperation_enroll enroll LEFT JOIN the_rapy_recuperation_travel_agency ta ON ta.id=enroll.takePartInTravelAgencyId - LEFT JOIN the_rapy_recuperation_province_flexible_group fg ON fg.travelAgencyId=enroll.takePartInTravelAgencyId AND fg.year=YEAR(enroll.signingUptime) + LEFT JOIN the_rapy_recuperation_province_flexible_group fg ON fg.id=( + SELECT configured.id + FROM the_rapy_recuperation_province_flexible_group configured + WHERE configured.travelAgencyId=enroll.takePartInTravelAgencyId + AND configured.year=YEAR(enroll.signingUptime) + AND configured.isDisabled=false + ORDER BY configured.id + LIMIT 1) $condition """); - Cnd cnd = Cnd.where("fg.year", ">=", startYear).and("fg.year", "<=", endYear) - .and("enroll.isNormal", "=", true); + Cnd cnd = Cnd.where("ta.signUpTravelAgency", "=", true) + .and("fg.id", "is not", null) + .andEX("fg.year", ">=", startYear) + .andEX("fg.year", "<=", endYear) + .and("enroll.isNormal", "=", true) + .and("enroll.stateId", "not in", Lang.array(RecuperationState.UNITFAIL, + RecuperationState.LINEUNITFAIL, RecuperationState.SCHOOLFAIL)); cnd.andEX("fg.travelAgencyId", "=", travelAgencyId).and(Cnd.likeEX("fg.groupName", groupName)); if (StrUtil.isNotBlank(searchKeyword)) { cnd.and(Cnd.exps("enroll.userName", "like", "%" + searchKeyword + "%").or("enroll.loginName", "like", "%" + searchKeyword + "%")); } if (!AuthUtil.hasRoleOr("sysadmin", "A06") && AuthUtil.hasRoleOr("H04")) cnd.and("fg.createUnionId", "=", SecurityUtil.getUnionId()); - cnd.asc("fg.year").asc("ta.serialNumber * 1").asc("enroll.groupLeaderUserName").asc("enroll.signingUptime"); + cnd.asc("ta.serialNumber * 1").asc("ta.travelAgencyName").asc("enroll.groupLeaderUserName") + .asc("enroll.groupLeaderLoginName").asc("fg.year").asc("enroll.signingUptime"); + sql.setVar("auditFailStates", auditFailStates()); sql.setCondition(cnd); List list = listMap(sql); for (int i = 0; i < list.size(); i++) list.get(i).setv("no", i + 1); diff --git a/src/main/resources/views/platform/zhgh/staffbenefit/recuperation/flexibleGroupQuery/index.html b/src/main/resources/views/platform/zhgh/staffbenefit/recuperation/flexibleGroupQuery/index.html index 2bf9189..0f70742 100644 --- a/src/main/resources/views/platform/zhgh/staffbenefit/recuperation/flexibleGroupQuery/index.html +++ b/src/main/resources/views/platform/zhgh/staffbenefit/recuperation/flexibleGroupQuery/index.html @@ -1,43 +1,289 @@ +
+ + + + + + + + + + + + + + + + + 取 消 - - - + + + + + + + + + 取 消
diff --git a/src/main/resources/views/platform/zhgh/staffbenefit/recuperation/lineStatistics/index.html b/src/main/resources/views/platform/zhgh/staffbenefit/recuperation/lineStatistics/index.html index 79ebcbe..4d7c681 100644 --- a/src/main/resources/views/platform/zhgh/staffbenefit/recuperation/lineStatistics/index.html +++ b/src/main/resources/views/platform/zhgh/staffbenefit/recuperation/lineStatistics/index.html @@ -1,26 +1,431 @@ +
- - - - - - - - - - - - -
查询
+ + + + +
diff --git a/src/main/resources/views/platform/zhgh/staffbenefit/recuperation/statistics/index.html b/src/main/resources/views/platform/zhgh/staffbenefit/recuperation/statistics/index.html index 4322c7d..6467db0 100644 --- a/src/main/resources/views/platform/zhgh/staffbenefit/recuperation/statistics/index.html +++ b/src/main/resources/views/platform/zhgh/staffbenefit/recuperation/statistics/index.html @@ -1,19 +1,688 @@ - + + + + +
- 统计年度: - - - - {{feedbackDetail.typeName}}{{feedbackDetail.compositeScore}}{{feedbackDetail.evaluationForTravelAgency}}{{feedbackDetail.evaluationForAccommodation}}{{feedbackDetail.evaluationForJourney}}{{feedbackDetail.evaluationForDining}}{{feedbackDetail.evaluationForTransportation}}{{feedbackDetail.schemeName}} + + + + + + + + + + +
+
+
+ {{item.userName || '匿名评价人'}} + {{item.unitName || '暂无所属单位'}} +
+
{{item.feedbackContent}}
+
+
+
当前方案暂无评价建议
+
+ + - + + +