diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourGroupController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourGroupController.java index f49ffef..d67bc2b 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourGroupController.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourGroupController.java @@ -83,7 +83,10 @@ public class TourGroupController { m.`year`, m.matterName, m.unionId, - COALESCE(u.name, '校工会') AS unionName, + CASE + WHEN IFNULL(NULLIF(m.undertakeStatus, ''), 'unclaimed') = 'claimed' THEN COALESCE(u.name, '校工会') + ELSE '' + END AS unionName, m.lineId, l.lineName, l.lineType, @@ -632,7 +635,7 @@ public class TourGroupController { return "m.matterName"; } if ("unionName".equals(orderName)) { - return "u.name"; + return "CASE WHEN IFNULL(NULLIF(m.undertakeStatus, ''), 'unclaimed') = 'claimed' THEN COALESCE(u.name, '校工会') ELSE '' END"; } if ("lineType".equals(orderName)) { return "l.lineType"; diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourLineController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourLineController.java index b6758ac..f2085e6 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourLineController.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourLineController.java @@ -36,6 +36,8 @@ import java.util.stream.Collectors; @At("/platform/tour/route") public class TourLineController { + private static final String SORT_CODE_PATTERN = "^\\d+$"; + @Inject private TourLineService tourLineService; @@ -52,7 +54,7 @@ public class TourLineController { @SaCheckPermission("tour.route") public Result pageData(PageForm pageForm, Integer year, String lineName, String lotId) { if (StrUtil.isBlank(pageForm.getPageOrderName())) { - pageForm.defaultSortDesc("enabled"); + pageForm.defaultSortAsc("lineCode"); } Cnd cnd = Cnd.NEW(); @@ -91,7 +93,7 @@ public class TourLineController { LEFT JOIN tour_setting_lot lot ON lot.id = l.lotId $creatorJoin $condition - ORDER BY $orderColumn $orderBy, l.`year` DESC, l.lineCode ASC, l.createdAt DESC + ORDER BY $orderColumn $orderBy, l.`year` DESC, CAST(l.lineCode AS UNSIGNED) ASC, l.createdAt DESC """); listSql.setVar("creatorJoin", creatorJoin); listSql.setCondition(cnd); @@ -168,7 +170,7 @@ public class TourLineController { sameCodeCnd.and(TourLine::getId, "<>", line.getId()); } if (tourLineService.count(sameCodeCnd) > 0) { - return Result.error("同年度下线路编号已存在"); + return Result.error("同年度下排序编号已存在"); } if (line.getEnabled() == null) { line.setEnabled(true); @@ -197,10 +199,47 @@ public class TourLineController { if (StrUtil.isBlank(id)) { return Result.error("参数错误"); } + TourLine line = tourLineService.fetch(id); + if (line == null) { + return Result.error("线路不存在"); + } + if (countLineSignup(id) > 0) { + return Result.error("当前线路已有人员报名,不能删除"); + } + if (countLineMatter(id) > 0) { + return Result.error("当前线路已关联事项,不能删除"); + } tourLineService.delete(id); return Result.success(); } + private int countLineSignup(String lineId) { + Sql sql = Sqls.create(""" + SELECT COUNT(1) + FROM tour_ledger t + LEFT JOIN tour_matter m ON m.id = t.matterId + WHERE t.delFlag = 0 + AND (t.lineId = @lineId OR m.lineId = @lineId) + """); + sql.setParam("lineId", lineId); + sql.setCallback(Sqls.callback.integer()); + tourLineService.dao().execute(sql); + return sql.getInt(); + } + + private int countLineMatter(String lineId) { + Sql sql = Sqls.create(""" + SELECT COUNT(1) + FROM tour_matter + WHERE delFlag = 0 + AND lineId = @lineId + """); + sql.setParam("lineId", lineId); + sql.setCallback(Sqls.callback.integer()); + tourLineService.dao().execute(sql); + return sql.getInt(); + } + private Result check(TourLine line) { if (line == null) { return Result.error("参数错误"); @@ -215,7 +254,10 @@ public class TourLineController { return Result.error("线路名称不能为空"); } if (StrUtil.isBlank(line.getLineCode())) { - return Result.error("线路编号不能为空"); + return Result.error("排序编号不能为空"); + } + if (!line.getLineCode().matches(SORT_CODE_PATTERN)) { + return Result.error("排序编号必须为整数"); } if (StrUtil.isBlank(line.getLineType())) { return Result.error("线路类型不能为空"); @@ -281,7 +323,7 @@ public class TourLineController { return "l.`year`"; } if ("lineCode".equals(orderName)) { - return "l.lineCode"; + return "CAST(l.lineCode AS UNSIGNED)"; } if ("lotName".equals(orderName)) { return "lot.lotName"; diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourMatterController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourMatterController.java index 9905aaa..5ca291e 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourMatterController.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourMatterController.java @@ -76,7 +76,10 @@ public class TourMatterController { SELECT m.*, s.configName AS settingName, - u.name AS unionName, + CASE + WHEN IFNULL(NULLIF(m.undertakeStatus, ''), 'unclaimed') = 'claimed' THEN COALESCE(u.name, '校工会') + ELSE '' + END AS unionName, d.name AS organizationTypeName, l.lineName AS lineName, l.lineType AS lineType, @@ -157,6 +160,35 @@ public class TourMatterController { return Result.success(sql.getList(NutMap.class)); } + @At + @SaCheckPermission("tour.matter") + public Result lineInfo(String lineId) { + if (StrUtil.isBlank(lineId)) { + return Result.error("参数错误"); + } + Cnd cnd = Cnd.NEW(); + cnd.and("l.delFlag", "=", false); + cnd.and("l.enabled", "=", true); + cnd.and("l.id", "=", lineId); + + Sql sql = Sqls.create(""" + SELECT + l.*, + lot.lotName AS lotName, + lot.lotValue AS lotValue, + lot.lotValue AS lotDays, + lot.activityCost AS activityCost + FROM tour_line l + LEFT JOIN tour_setting_lot lot ON lot.id = l.lotId + $condition + """); + sql.setCondition(cnd); + sql.setCallback(Sqls.callback.map()); + tourMatterService.dao().execute(sql); + NutMap line = sql.getObject(NutMap.class); + return line == null || line.isEmpty() ? Result.error("线路不存在") : Result.success(line); + } + @At @SaCheckPermission("tour.matter") public Result organizationTypeOptions() { @@ -194,7 +226,7 @@ public class TourMatterController { } else { tourMatterService.updateIgnoreNull(matter); } - return Result.success(); + return Result.success(NutMap.NEW().addv("id", matter.getId())); } @At @@ -246,21 +278,31 @@ public class TourMatterController { @At @SaCheckPermission("tour.matter") - public Result settingPeople(String matterId) { - if (StrUtil.isBlank(matterId)) { + public Result settingPeople(String matterId, Integer year) { + if (StrUtil.isBlank(matterId) && year == null) { return Result.error("参数错误"); } - TourMatter matter = tourMatterService.fetch(matterId); - if (matter == null || StrUtil.isBlank(matter.getSettingId())) { - return Result.success(NutMap.NEW()); + return Result.success(settingDefaults(year, matterId)); + } + + private NutMap settingDefaults(Integer year, String matterId) { + TourMatter matter = null; + if (StrUtil.isNotBlank(matterId)) { + matter = tourMatterService.fetch(matterId); + } + Integer settingYear = year != null ? year : (matter == null ? null : matter.getYear()); + TourSetting setting = fetchSettingByYear(settingYear); + if (setting == null && matter != null && StrUtil.isNotBlank(matter.getSettingId())) { + setting = tourMatterService.dao().fetch(TourSetting.class, matter.getSettingId()); } - TourSetting setting = tourMatterService.dao().fetch(TourSetting.class, matter.getSettingId()); if (setting == null) { - return Result.success(NutMap.NEW()); + return NutMap.NEW(); } - return Result.success(NutMap.NEW() + return NutMap.NEW() .addv("minGroupPeople", setting.getMinGroupPeople()) - .addv("maxGroupPeople", setting.getMaxGroupPeople())); + .addv("maxGroupPeople", setting.getMaxGroupPeople()) + .addv("signupStartTime", setting.getSignupStartTime()) + .addv("signupEndTime", setting.getSignupEndTime()); } @At @@ -268,6 +310,7 @@ public class TourMatterController { @SaCheckPermission("tour.matter") @SLog(type = "tour", tag = "疗休养事项", msg = "保存事项线路配置") public Result lineConfigDoSubmit(TourMatter matter) { + fillLineConfigFromSetting(matter); Result checkResult = checkLineConfig(matter); if (checkResult != null) { return checkResult; @@ -290,6 +333,48 @@ public class TourMatterController { return Result.success(); } + private void fillLineConfigFromSetting(TourMatter matter) { + if (matter == null || StrUtil.isBlank(matter.getId())) { + return; + } + TourMatter oldMatter = tourMatterService.fetch(matter.getId()); + if (oldMatter == null) { + return; + } + TourSetting setting = fetchSettingByYear(oldMatter.getYear()); + if (setting == null && StrUtil.isNotBlank(oldMatter.getSettingId())) { + setting = tourMatterService.dao().fetch(TourSetting.class, oldMatter.getSettingId()); + } + if (setting == null) { + return; + } + if (setting.getMinGroupPeople() != null) { + matter.setMinGroupPeople(setting.getMinGroupPeople()); + } + if (setting.getMaxGroupPeople() != null) { + matter.setMaxGroupPeople(setting.getMaxGroupPeople()); + } + if (StrUtil.isNotBlank(setting.getSignupStartTime())) { + matter.setSignupStartTime(setting.getSignupStartTime()); + } + if (StrUtil.isNotBlank(setting.getSignupEndTime())) { + matter.setSignupEndTime(setting.getSignupEndTime()); + } + } + + private TourSetting fetchSettingByYear(Integer year) { + if (year == null) { + return null; + } + Cnd cnd = Cnd.where(TourSetting::getEnabled, "=", true); + cnd.and("delFlag", "=", false); + cnd.and(TourSetting::getYear, "=", year); + cnd.desc(TourSetting::getCreatedAt); + cnd.desc(TourSetting::getUpdatedAt); + cnd.asc(TourSetting::getConfigName); + return tourMatterService.dao().fetch(TourSetting.class, cnd); + } + private Result check(TourMatter matter) { if (matter == null) { return Result.error("参数错误"); @@ -422,7 +507,7 @@ public class TourMatterController { return "m.matterName"; } if ("unionName".equals(orderName)) { - return "u.name"; + return "CASE WHEN IFNULL(NULLIF(m.undertakeStatus, ''), 'unclaimed') = 'claimed' THEN COALESCE(u.name, '校工会') ELSE '' END"; } if ("lineName".equals(orderName)) { return "l.lineName"; diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourMySignupController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourMySignupController.java index bbe52fe..44bba94 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourMySignupController.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourMySignupController.java @@ -55,7 +55,6 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.math.BigDecimal; -import java.math.RoundingMode; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; @@ -146,6 +145,10 @@ public class TourMySignupController { IFNULL(GROUP_CONCAT(DISTINCT task.displayName), IF(ins.id IS NULL, '', '结束')) AS curTaskName, IFNULL(f.familyCount, 0) AS familyCount, COALESCE(m.travelEndTime, tp.travelEndTime) AS travelEndTime, + CASE + WHEN IFNULL(NULLIF(m.undertakeStatus, ''), 'unclaimed') = 'claimed' THEN COALESCE(u.name, '校工会') + ELSE '' + END AS matterUnionName, CASE WHEN IFNULL(m.travelStartTime, '') <> '' AND IFNULL(m.travelEndTime, '') <> '' THEN CONCAT(m.travelStartTime, ' 至 ', m.travelEndTime) @@ -163,6 +166,7 @@ public class TourMySignupController { GROUP BY ledgerId ) f ON f.ledgerId = t.id LEFT JOIN tour_matter m ON m.id = t.matterId AND m.delFlag = 0 + LEFT JOIN sys_union u ON u.id = m.unionId LEFT JOIN ( SELECT `year`, @@ -213,7 +217,7 @@ public class TourMySignupController { .and(TourLedgerDirectRelative::getLedgerId, "=", ledger.getId())); NutMap signupConfig = getSignupConfig(ledger); return Result.success(NutMap.NEW() - .addv("ledger", ledger) + .addv("ledger", buildLedgerView(ledger)) .addv("travelPeriod", getTravelPeriod(ledger)) .addv("families", tourLedgerFamilyService.query(familyCnd)) .addv("directRelative", directRelative) @@ -326,11 +330,18 @@ public class TourMySignupController { .and(TourLedgerDirectRelative::getLedgerId, "=", ledger.getId())); return Result.success(NutMap.NEW() .addv("matter", matter) - .addv("ledger", ledger) + .addv("ledger", buildLedgerView(ledger)) .addv("families", tourLedgerFamilyService.query(familyCnd)) .addv("directRelative", directRelative)); } + private NutMap buildLedgerView(TourLedger ledger) { + NutMap map = Lang.obj2nutmap(ledger); + View_user user = tourLedgerService.dao().fetch(View_user.class, Cnd.where("loginname", "=", ledger.getJobNo())); + map.addv("mobile", defaultIfBlank(ledger.getMobile(), user == null ? "" : defaultIfBlank(user.getMobile(), ""))); + return map; + } + @At @SaCheckPermission(value = {"tour.mysignup", "h5.tour.mysignup"}, mode = SaMode.OR) public Result directRelativeOptions() { @@ -587,6 +598,9 @@ public class TourMySignupController { if (StrUtil.isBlank(ledger.getLineName())) { return Result.error("报名线路不能为空"); } + if (StrUtil.isBlank(ledger.getIdCard())) { + return Result.error("身份证号不能为空"); + } return null; } @@ -612,14 +626,16 @@ public class TourMySignupController { if (activityGroupId == null || !activityBasicScopeService.isUserInGroup(activityGroupId, SecurityUtil.getUserId())) { return Result.error("您不在本次疗休养报名范围内"); } - if (StrUtil.isBlank(matter.getSignupStartTime()) || StrUtil.isBlank(matter.getSignupEndTime())) { + String signupStartTime = defaultIfBlank(setting.getSignupStartTime(), matter.getSignupStartTime()); + String signupEndTime = defaultIfBlank(setting.getSignupEndTime(), matter.getSignupEndTime()); + if (StrUtil.isBlank(signupStartTime) || StrUtil.isBlank(signupEndTime)) { return Result.error("报名时间未配置"); } String now = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); - if (now.compareTo(normalizeDateTime(matter.getSignupStartTime(), false)) < 0) { + if (now.compareTo(normalizeDateTime(signupStartTime, false)) < 0) { return Result.error("报名未开始"); } - if (now.compareTo(normalizeDateTime(matter.getSignupEndTime(), true)) > 0) { + if (now.compareTo(normalizeDateTime(signupEndTime, true)) > 0) { return Result.error("报名已结束"); } CycleAllowedTimes cycleAllowedTimes = calculateCycleAllowedTimes(matter, setting, oldLedger); @@ -794,76 +810,35 @@ public class TourMySignupController { } private OutProvinceQuota calculateOutProvinceQuota(TourMatter matter, TourSetting setting, TourLedger oldLedger) { - String ratioType = normalizeOutProvinceRatioType(setting == null ? null : setting.getOutProvinceRatioType()); - BigDecimal originalRatio = setting == null ? null : setting.getOutProvinceRatio(); - boolean oneThirdRatio = isOneThirdRatio(originalRatio); - BigDecimal ratio = oneThirdRatio ? BigDecimal.ONE.divide(BigDecimal.valueOf(3), 12, RoundingMode.HALF_UP) - : (originalRatio == null ? BigDecimal.ZERO : originalRatio); int year = matter == null || matter.getYear() == null ? LocalDate.now().getYear() : matter.getYear(); String excludeLedgerId = oldLedger == null ? null : oldLedger.getId(); - int totalSignupPeople = countYearSignupPeople(year, excludeLedgerId); + int domesticSignupPeople = countYearDomesticSignupPeople(year, excludeLedgerId); int outProvinceSignupPeople = countYearOutProvinceSignupPeople(year, excludeLedgerId); - int basePeople; - if ("可参加教职工人数".equals(ratioType)) { - Integer groupId = parseInteger(setting == null ? null : setting.getActivityGroupId()); - basePeople = countActivityGroupPeople(groupId); - } else if ("固定人数".equals(ratioType)) { - basePeople = setting == null || setting.getOutProvinceFixedPeople() == null ? 0 : setting.getOutProvinceFixedPeople(); - } else { - basePeople = totalSignupPeople; - } - int quotaPeople = oneThirdRatio - ? basePeople / 3 - : ratio.multiply(BigDecimal.valueOf(basePeople)).setScale(0, RoundingMode.FLOOR).intValue(); - int allowPeople = quotaPeople - outProvinceSignupPeople; - return new OutProvinceQuota(ratioType, ratio, basePeople, totalSignupPeople, outProvinceSignupPeople, allowPeople); - } - - private boolean isOneThirdRatio(BigDecimal ratio) { - if (ratio == null) { - return false; - } - return ratio.compareTo(BigDecimal.valueOf(0.33)) >= 0 && ratio.compareTo(BigDecimal.valueOf(0.3333)) <= 0; - } - - private String normalizeOutProvinceRatioType(String ratioType) { - if ("当年参加人数".equals(ratioType) || StrUtil.isBlank(ratioType)) { - return "当年报名人数"; - } - if ("可参加教职工人数".equals(ratioType) || "固定人数".equals(ratioType)) { - return ratioType; - } - return "当年报名人数"; + int allowPeople = domesticSignupPeople / 2 - outProvinceSignupPeople; + return new OutProvinceQuota("当年省内报名人数", domesticSignupPeople, + domesticSignupPeople + outProvinceSignupPeople, outProvinceSignupPeople, allowPeople); } private String buildOutProvinceQuotaNotice(OutProvinceQuota quota) { String suffix = quota.canApply() ? "您可以报名,或您稍后报名" : "请稍后报名"; - if ("当年报名人数".equals(quota.ratioType())) { - return "当前报名人数是" + quota.totalSignupPeople() + "人,已经报名省外线路人数是" - + quota.outProvinceSignupPeople() + "人,按照省外人数不超过" + quota.ratioText() - + "的规则,当前时间允许报名人数是" + quota.allowPeople() + "人," + suffix; - } - if ("可参加教职工人数".equals(quota.ratioType())) { - return "今年有权限报名人数是" + quota.basePeople() + "人,已经报名省外线路人数是" - + quota.outProvinceSignupPeople() + "人,按照省外人数不超过" + quota.ratioText() - + "的规则,当前时间允许报名人数是" + quota.allowPeople() + "人," + suffix; - } - return "按照省外人数不超过" + quota.ratioText() + return "当前报省内线路教职工有效人数是" + quota.basePeople() + "人,已经报名省外线路教职工有效人数是" + + quota.outProvinceSignupPeople() + "人,按照省外人数不超过出行人数的1/3规则" + "的规则,当前时间允许报名人数是" + quota.allowPeople() + "人," + suffix; } - private int countYearSignupPeople(int year, String excludeLedgerId) { + private int countYearDomesticSignupPeople(int year, String excludeLedgerId) { String excludeSql = StrUtil.isBlank(excludeLedgerId) ? "" : " AND t.id <> @excludeLedgerId"; Sql sql = Sqls.create(""" - SELECT COUNT(1) + SELECT COUNT(DISTINCT t.id) FROM tour_ledger t LEFT JOIN wf_process_instance ins ON ins.businessNo = t.id WHERE t.delFlag = 0 AND t.`year` = @year - AND (ins.id IS NULL OR ins.state = @finishedState) + AND t.lineType IN ('省内线路', '省内', '国内线路', '国内') + AND (ins.id IS NULL OR ins.state <> @abandonState) """ + excludeSql); sql.setParam("year", year); - sql.setParam("finishedState", ProcessInstanceStateEnum.FINISHED.getCode()); + sql.setParam("abandonState", ProcessInstanceStateEnum.ABANDON.getCode()); if (StrUtil.isNotBlank(excludeLedgerId)) { sql.setParam("excludeLedgerId", excludeLedgerId); } @@ -875,16 +850,16 @@ public class TourMySignupController { private int countYearOutProvinceSignupPeople(int year, String excludeLedgerId) { String excludeSql = StrUtil.isBlank(excludeLedgerId) ? "" : " AND t.id <> @excludeLedgerId"; Sql sql = Sqls.create(""" - SELECT COUNT(1) + SELECT COUNT(DISTINCT t.id) FROM tour_ledger t LEFT JOIN wf_process_instance ins ON ins.businessNo = t.id WHERE t.delFlag = 0 AND t.`year` = @year AND t.lineType IN ('省外线路', '省外') - AND (ins.id IS NULL OR ins.state = @finishedState) + AND (ins.id IS NULL OR ins.state <> @abandonState) """ + excludeSql); sql.setParam("year", year); - sql.setParam("finishedState", ProcessInstanceStateEnum.FINISHED.getCode()); + sql.setParam("abandonState", ProcessInstanceStateEnum.ABANDON.getCode()); if (StrUtil.isNotBlank(excludeLedgerId)) { sql.setParam("excludeLedgerId", excludeLedgerId); } @@ -1089,7 +1064,6 @@ public class TourMySignupController { } private record OutProvinceQuota(String ratioType, - BigDecimal ratio, int basePeople, int totalSignupPeople, int outProvinceSignupPeople, @@ -1099,14 +1073,7 @@ public class TourMySignupController { } String ratioText() { - if (ratio == null || BigDecimal.ZERO.compareTo(ratio) == 0) { - return "0"; - } - BigDecimal oneThird = BigDecimal.ONE.divide(BigDecimal.valueOf(3), 8, RoundingMode.HALF_UP); - if (ratio.subtract(oneThird).abs().compareTo(BigDecimal.valueOf(0.01)) <= 0) { - return "1/3"; - } - return ratio.stripTrailingZeros().toPlainString(); + return "floor(省内有效人数/2)-省外有效人数"; } } @@ -1338,6 +1305,7 @@ public class TourMySignupController { .addv("applyDate", firstNotBlank(approvalTimes.getString("applyDate", ""), ledger.getSignupTime())) .addv("unionAuditorName", approvalTimes.getString("unionAuditorName", "")) .addv("unionAuditDate", approvalTimes.getString("unionAuditDate", "")) + .addv("schoolUnionAuditorName", approvalTimes.getString("schoolUnionAuditorName", "")) .addv("schoolUnionAuditDate", approvalTimes.getString("schoolUnionAuditDate", "")); } @@ -1389,6 +1357,7 @@ public class TourMySignupController { .addv("applyDate", firstNotBlank(approvalTimes.getString("applyDate", ""), ledger.getSignupTime())) .addv("unionAuditorName", approvalTimes.getString("unionAuditorName", "")) .addv("unionAuditDate", approvalTimes.getString("unionAuditDate", "")) + .addv("schoolUnionAuditorName", approvalTimes.getString("schoolUnionAuditorName", "")) .addv("schoolUnionAuditDate", approvalTimes.getString("schoolUnionAuditDate", "")) .addv("relativeUnitAuditDate", ""); } @@ -1444,6 +1413,7 @@ public class TourMySignupController { result.put("unionAuditorName", parseTaskUserName(item.getString("variable", ""))); } else if ("校工会审核".equals(displayName)) { result.put("schoolUnionAuditDate", finishDate); + result.put("schoolUnionAuditorName", parseTaskUserName(item.getString("variable", ""))); } } return result; @@ -1580,6 +1550,7 @@ public class TourMySignupController { drawPlainDateLine(writer, data.getString("unionAuditDate", ""), 330, paragraphEndY - 163, 18); writer.text("学校工会:盖章", 18, 300, paragraphEndY - 190, false); + writer.text(data.getString("schoolUnionAuditorName", ""), 18, 410, paragraphEndY - 190, false); drawPlainDateLine(writer, data.getString("schoolUnionAuditDate", ""), 330, paragraphEndY - 217, 18); } document.save(out); @@ -1644,6 +1615,7 @@ public class TourMySignupController { signY -= 78; writer.text("学校工会:盖章", 15, signX + 20, signY, false); + writer.text(data.getString("schoolUnionAuditorName", ""), 15, signX + 135, signY, false); drawPlainDateLine(writer, data.getString("schoolUnionAuditDate", ""), signX + 45, signY - 31, 15); signY -= 78; @@ -1823,6 +1795,9 @@ public class TourMySignupController { if ("travelPeriod".equals(orderName)) { return "COALESCE(m.travelStartTime, tp.travelPeriod)"; } + if ("matterUnionName".equals(orderName)) { + return "matterUnionName"; + } if ("lineType".equals(orderName)) { return "t.lineType"; } diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourSchoolUnionApprovalController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourSchoolUnionApprovalController.java index 1c6b746..e3977f2 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourSchoolUnionApprovalController.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourSchoolUnionApprovalController.java @@ -7,6 +7,7 @@ import com.budwk.app.base.page.Pagination; import com.budwk.app.base.param.PageForm; import com.budwk.app.base.result.Result; import com.budwk.app.flow.enums.ProcessTaskStateEnum; +import com.budwk.app.sys.views.View_user; import com.budwk.app.web.commons.auth.utils.SecurityUtil; import com.budwk.app.zhgh.dayofficework.tour.models.TourLedger; import com.budwk.app.zhgh.dayofficework.tour.models.TourLedgerDirectRelative; @@ -20,6 +21,7 @@ import org.nutz.dao.sql.Sql; import org.nutz.dao.util.cri.SqlExpressionGroup; import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.Lang; import org.nutz.lang.util.NutMap; import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.Ok; @@ -180,7 +182,7 @@ public class TourSchoolUnionApprovalController { .and(TourLedgerDirectRelative::getDelFlag, "=", false)); NutMap signupConfig = getSignupConfig(ledger); return Result.success(NutMap.NEW() - .addv("ledger", ledger) + .addv("ledger", buildLedgerView(ledger)) .addv("travelPeriod", getTravelPeriod(ledger)) .addv("families", tourLedgerFamilyService.query(familyCnd)) .addv("directRelative", directRelative) @@ -189,6 +191,13 @@ public class TourSchoolUnionApprovalController { .addv("directFamilyUnitLine", signupConfig.getBoolean("directFamilyUnitLine", false))); } + private NutMap buildLedgerView(TourLedger ledger) { + NutMap map = Lang.obj2nutmap(ledger); + View_user user = tourLedgerService.dao().fetch(View_user.class, Cnd.where("loginname", "=", ledger.getJobNo())); + map.addv("mobile", StrUtil.blankToDefault(ledger.getMobile(), user == null ? "" : StrUtil.blankToDefault(user.getMobile(), ""))); + return map; + } + @At @SaCheckPermission(value = {"tour.schoolUnionApproval", "h5.tour.schoolUnionApproval"}, mode = SaMode.OR) public Result unionOptions(Boolean audit, Integer startYear, Integer endYear, String keyword, String lineId, String travelPeriod, String lineType) { diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourSettingController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourSettingController.java index 08dab7e..2ad00ce 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourSettingController.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourSettingController.java @@ -209,6 +209,12 @@ public class TourSettingController { && tourSetting.getMinGroupPeople() > tourSetting.getMaxGroupPeople()) { return Result.error("最少成团人数不能大于最多成团人数"); } + if (StrUtil.isBlank(tourSetting.getSignupStartTime()) || StrUtil.isBlank(tourSetting.getSignupEndTime())) { + return Result.error("报名时间不能为空"); + } + if (tourSetting.getSignupStartTime().compareTo(tourSetting.getSignupEndTime()) >= 0) { + return Result.error("开始报名时间必须小于结束报名时间"); + } if (tourSetting.getCycleStartYear() != null && tourSetting.getCycleEndYear() != null && tourSetting.getCycleStartYear() > tourSetting.getCycleEndYear()) { return Result.error("周期开始年度不能大于周期结束年度"); diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourSignupController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourSignupController.java index fff48ec..bfd524a 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourSignupController.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourSignupController.java @@ -34,6 +34,7 @@ import org.nutz.aop.interceptor.ioc.TransAop; import org.nutz.dao.Cnd; import org.nutz.dao.Sqls; import org.nutz.dao.sql.Sql; +import org.nutz.dao.util.cri.SqlExpressionGroup; import org.nutz.ioc.aop.Aop; import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.IocBean; @@ -44,8 +45,6 @@ import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.Ok; import org.nutz.mvc.annotation.Param; -import java.math.BigDecimal; -import java.math.RoundingMode; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; @@ -368,6 +367,63 @@ public class TourSignupController { return Result.success(sql.getList(NutMap.class)); } + @At + @SaCheckPermission("tour.signup") + public Result signupPageData(PageForm pageForm, String matterId, String keyword, String unionId) { + return querySignupPageData(pageForm, matterId, keyword, unionId); + } + + @At("/h5/signupPageData") + @SaCheckPermission(value = {"tour.signup", "h5.tour.signup"}, mode = SaMode.OR) + public Result h5SignupPageData(PageForm pageForm, String matterId, String keyword, String unionId) { + return querySignupPageData(pageForm, matterId, keyword, unionId); + } + + private Result querySignupPageData(PageForm pageForm, String matterId, String keyword, String unionId) { + if (StrUtil.isBlank(matterId)) { + return Result.error("参数错误"); + } + if (StrUtil.isBlank(pageForm.getPageOrderName())) { + pageForm.defaultSortDesc("signupTime"); + } + Cnd cnd = buildSignupQueryCnd(matterId, keyword, unionId); + Sql countSql = Sqls.create(""" + SELECT COUNT(DISTINCT t.id) + FROM tour_ledger t + INNER JOIN tour_matter m ON m.id = t.matterId + INNER JOIN tour_line l ON l.id = m.lineId + $condition + """); + countSql.setCondition(cnd); + countSql.setCallback(Sqls.callback.integer()); + tourLedgerService.dao().execute(countSql); + int count = countSql.getInt(); + + Sql listSql = Sqls.create(""" + SELECT + t.id, + t.jobNo, + t.userName, + t.unionId, + t.unionName, + t.signupTime + FROM tour_ledger t + INNER JOIN tour_matter m ON m.id = t.matterId + INNER JOIN tour_line l ON l.id = m.lineId + $condition + ORDER BY $orderColumn $orderBy, t.signupTime DESC, t.createdAt DESC + """); + listSql.setCondition(cnd); + listSql.setVar("orderColumn", getSignupOrderColumn(pageForm.getPageOrderName())); + listSql.setVar("orderBy", "ascending".equals(pageForm.getPageOrderBy()) ? "asc" : "desc"); + listSql.setPager(tourLedgerService.dao().createPager(pageForm.getPageNumber(), pageForm.getPageSize())); + listSql.setCallback(Sqls.callback.maps()); + tourLedgerService.dao().execute(listSql); + + Pagination pagination = new Pagination<>(pageForm.getPageNumber(), pageForm.getPageSize(), count, listSql.getList(NutMap.class)); + return Result.success(pagination); + } + @At @SaCheckPermission(value = {"tour.signup", "h5.tour.signup"}, mode = SaMode.OR) public Result lineDetail(String lineId) { @@ -395,7 +451,7 @@ public class TourSignupController { @At @SaCheckPermission(value = {"tour.signup", "h5.tour.signup"}, mode = SaMode.OR) - public Result signupDetail(String matterId) { + public Result signupDetail(String matterId, Boolean noticeChecked) { if (StrUtil.isBlank(matterId)) { return Result.error("参数错误"); } @@ -420,6 +476,8 @@ public class TourSignupController { l.travelAgencyId, a.agencyName AS travelAgencyName, IFNULL(lot.allowOverReimbursement, 0) AS allowOverReimbursement, + IFNULL(sc.signupCount, 0) AS signupCount, + IFNULL(sc.familyCount, 0) AS familyCount, s.allowFamily, IFNULL(s.fillBedInfo, 1) AS fillBedInfo FROM tour_matter m @@ -427,6 +485,23 @@ public class TourSignupController { LEFT JOIN tour_travel_agency a ON a.id = l.travelAgencyId LEFT JOIN tour_setting_lot lot ON lot.id = l.lotId LEFT JOIN tour_setting s ON s.id = m.settingId + LEFT JOIN ( + SELECT + t.matterId, + COUNT(1) + SUM(IFNULL(f.familyCount, 0)) AS signupCount, + SUM(IFNULL(f.familyCount, 0)) AS familyCount + FROM tour_ledger t + LEFT JOIN ( + SELECT ledgerId, COUNT(1) AS familyCount + FROM tour_ledger_family + WHERE delFlag = 0 + GROUP BY ledgerId + ) f ON f.ledgerId = t.id + WHERE t.delFlag = 0 + AND t.matterId IS NOT NULL + AND t.matterId <> '' + GROUP BY t.matterId + ) sc ON sc.matterId = m.id WHERE m.delFlag = 0 AND m.enabled = 1 AND m.id = @matterId @@ -461,9 +536,11 @@ public class TourSignupController { ruleLedger.setMatterId(matter.getString("matterId")); ruleLedger.setLineId(matter.getString("lineId")); ruleLedger.setLineName(matter.getString("lineName")); - Result ruleResult = checkSignupRule(ruleLedger, matterEntity, ledger); - if (ruleResult != null) { - return ruleResult; + if (!Boolean.TRUE.equals(noticeChecked)) { + Result ruleResult = checkSignupRule(ruleLedger, matterEntity, ledger); + if (ruleResult != null) { + return ruleResult; + } } List families = Collections.emptyList(); TourLedgerDirectRelative directRelative = null; @@ -591,26 +668,39 @@ public class TourSignupController { @At @SaCheckPermission(value = {"tour.signup", "h5.tour.signup"}, mode = SaMode.OR) public Result directRelativeOptions() { - List list = sysDictService.getSubListByCode("directRelative"); - if (list == null) { - return Result.success(Collections.emptyList()); - } - return Result.success(list.stream().filter(item -> !item.isDisabled()).collect(Collectors.toList())); + return Result.success(getEnabledDictOptions("directRelative")); + } + + @At + @SaCheckPermission(value = {"tour.signup", "h5.tour.signup"}, mode = SaMode.OR) + public Result signupOptions() { + return Result.success(NutMap.NEW() + .addv("bedTypeOptions", getEnabledDictOptions("bedType")) + .addv("familyRelationshipOptions", getFamilyRelationshipOptions()) + .addv("directRelativeOptions", getEnabledDictOptions("directRelative"))); } @At @SaCheckPermission(value = {"tour.signup", "h5.tour.signup"}, mode = SaMode.OR) public Result bedTypeOptions() { - List list = sysDictService.getSubListByCode("bedType"); - if (list == null) { - return Result.success(Collections.emptyList()); - } - return Result.success(list.stream().filter(item -> !item.isDisabled()).collect(Collectors.toList())); + return Result.success(getEnabledDictOptions("bedType")); } @At @SaCheckPermission(value = {"tour.signup", "h5.tour.signup"}, mode = SaMode.OR) public Result familyRelationshipOptions() { + return Result.success(getFamilyRelationshipOptions()); + } + + private List getEnabledDictOptions(String code) { + List list = sysDictService.getSubListByCode(code); + if (list == null) { + return Collections.emptyList(); + } + return list.stream().filter(item -> !item.isDisabled()).collect(Collectors.toList()); + } + + private List getFamilyRelationshipOptions() { Sql sql = Sqls.create(""" SELECT d.* FROM sys_dict p @@ -624,7 +714,7 @@ public class TourSignupController { sql.setCallback(Sqls.callback.entities()); sql.setEntity(tourLedgerService.dao().getEntity(Sys_dict.class)); tourLedgerService.dao().execute(sql); - return Result.success(sql.getList(Sys_dict.class)); + return sql.getList(Sys_dict.class); } @At @@ -772,6 +862,26 @@ public class TourSignupController { return cnd; } + private Cnd buildSignupQueryCnd(String matterId, String keyword, String unionId) { + Cnd cnd = Cnd.NEW(); + cnd.and("t.delFlag", "=", false); + cnd.and("t.matterId", "=", matterId); + cnd.and("m.delFlag", "=", false); + cnd.and("m.enabled", "=", true); + cnd.and("m.lineId", "IS NOT", null); + cnd.and("m.lineId", "<>", ""); + cnd.and("l.delFlag", "=", false); + cnd.and("l.enabled", "=", true); + if (StrUtil.isNotBlank(keyword)) { + SqlExpressionGroup keywordGroup = new SqlExpressionGroup(); + keywordGroup.orLike("t.userName", keyword.trim()); + keywordGroup.orLike("t.jobNo", keyword.trim()); + cnd.and(keywordGroup); + } + cnd.andEX("t.unionId", "=", unionId); + return cnd; + } + private Result checkSignup(TourLedger ledger) { if (ledger == null) { return Result.error("参数错误"); @@ -788,6 +898,9 @@ public class TourSignupController { if (StrUtil.isBlank(ledger.getLineName())) { return Result.error("报名线路不能为空"); } + if (StrUtil.isBlank(ledger.getIdCard())) { + return Result.error("身份证号不能为空"); + } return null; } @@ -887,14 +1000,16 @@ public class TourSignupController { if (activityGroupId == null || !activityBasicScopeService.isUserInGroup(activityGroupId, SecurityUtil.getUserId())) { return Result.error("您不在本次疗休养报名范围内"); } - if (StrUtil.isBlank(matter.getSignupStartTime()) || StrUtil.isBlank(matter.getSignupEndTime())) { + String signupStartTime = defaultIfBlank(setting.getSignupStartTime(), matter.getSignupStartTime()); + String signupEndTime = defaultIfBlank(setting.getSignupEndTime(), matter.getSignupEndTime()); + if (StrUtil.isBlank(signupStartTime) || StrUtil.isBlank(signupEndTime)) { return Result.error("报名时间未配置"); } String now = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); - if (now.compareTo(normalizeDateTime(matter.getSignupStartTime(), false)) < 0) { + if (now.compareTo(normalizeDateTime(signupStartTime, false)) < 0) { return Result.error("报名未开始"); } - if (now.compareTo(normalizeDateTime(matter.getSignupEndTime(), true)) > 0) { + if (now.compareTo(normalizeDateTime(signupEndTime, true)) > 0) { return Result.error("报名已结束"); } CycleAllowedTimes cycleAllowedTimes = calculateCycleAllowedTimes(matter, setting, oldLedger); @@ -1069,76 +1184,35 @@ public class TourSignupController { } private OutProvinceQuota calculateOutProvinceQuota(TourMatter matter, TourSetting setting, TourLedger oldLedger) { - String ratioType = normalizeOutProvinceRatioType(setting == null ? null : setting.getOutProvinceRatioType()); - BigDecimal originalRatio = setting == null ? null : setting.getOutProvinceRatio(); - boolean oneThirdRatio = isOneThirdRatio(originalRatio); - BigDecimal ratio = oneThirdRatio ? BigDecimal.ONE.divide(BigDecimal.valueOf(3), 12, RoundingMode.HALF_UP) - : (originalRatio == null ? BigDecimal.ZERO : originalRatio); int year = matter == null || matter.getYear() == null ? LocalDate.now().getYear() : matter.getYear(); String excludeLedgerId = oldLedger == null ? null : oldLedger.getId(); - int totalSignupPeople = countYearSignupPeople(year, excludeLedgerId); + int domesticSignupPeople = countYearDomesticSignupPeople(year, excludeLedgerId); int outProvinceSignupPeople = countYearOutProvinceSignupPeople(year, excludeLedgerId); - int basePeople; - if ("可参加教职工人数".equals(ratioType)) { - Integer groupId = parseInteger(setting == null ? null : setting.getActivityGroupId()); - basePeople = countActivityGroupPeople(groupId); - } else if ("固定人数".equals(ratioType)) { - basePeople = setting == null || setting.getOutProvinceFixedPeople() == null ? 0 : setting.getOutProvinceFixedPeople(); - } else { - basePeople = totalSignupPeople; - } - int quotaPeople = oneThirdRatio - ? basePeople / 3 - : ratio.multiply(BigDecimal.valueOf(basePeople)).setScale(0, RoundingMode.FLOOR).intValue(); - int allowPeople = quotaPeople - outProvinceSignupPeople; - return new OutProvinceQuota(ratioType, ratio, basePeople, totalSignupPeople, outProvinceSignupPeople, allowPeople); - } - - private boolean isOneThirdRatio(BigDecimal ratio) { - if (ratio == null) { - return false; - } - return ratio.compareTo(BigDecimal.valueOf(0.33)) >= 0 && ratio.compareTo(BigDecimal.valueOf(0.3333)) <= 0; - } - - private String normalizeOutProvinceRatioType(String ratioType) { - if ("当年参加人数".equals(ratioType) || StrUtil.isBlank(ratioType)) { - return "当年报名人数"; - } - if ("可参加教职工人数".equals(ratioType) || "固定人数".equals(ratioType)) { - return ratioType; - } - return "当年报名人数"; + int allowPeople = domesticSignupPeople / 2 - outProvinceSignupPeople; + return new OutProvinceQuota("当年省内报名人数", domesticSignupPeople, + domesticSignupPeople + outProvinceSignupPeople, outProvinceSignupPeople, allowPeople); } private String buildOutProvinceQuotaNotice(OutProvinceQuota quota) { String suffix = quota.canApply() ? "您可以报名,或您稍后报名" : "请稍后报名"; - if ("当年报名人数".equals(quota.ratioType())) { - return "当前报名人数是" + quota.totalSignupPeople() + "人,已经报名省外线路人数是" - + quota.outProvinceSignupPeople() + "人,按照省外人数不超过" + quota.ratioText() - + "的规则,当前时间允许报名人数是" + quota.allowPeople() + "人," + suffix; - } - if ("可参加教职工人数".equals(quota.ratioType())) { - return "今年有权限报名人数是" + quota.basePeople() + "人,已经报名省外线路人数是" - + quota.outProvinceSignupPeople() + "人,按照省外人数不超过" + quota.ratioText() - + "的规则,当前时间允许报名人数是" + quota.allowPeople() + "人," + suffix; - } - return "按照省外人数不超过" + quota.ratioText() + return "当前报省内线路教职工有效人数是" + quota.basePeople() + "人,已经报名省外线路教职工有效人数是" + + quota.outProvinceSignupPeople() + "人,按照省外人数不超过出行人数的1/3规则" + "的规则,当前时间允许报名人数是" + quota.allowPeople() + "人," + suffix; } - private int countYearSignupPeople(int year, String excludeLedgerId) { + private int countYearDomesticSignupPeople(int year, String excludeLedgerId) { String excludeSql = StrUtil.isBlank(excludeLedgerId) ? "" : " AND t.id <> @excludeLedgerId"; Sql sql = Sqls.create(""" - SELECT COUNT(1) + SELECT COUNT(DISTINCT t.id) FROM tour_ledger t LEFT JOIN wf_process_instance ins ON ins.businessNo = t.id WHERE t.delFlag = 0 AND t.`year` = @year - AND (ins.id IS NULL OR ins.state = @finishedState) + AND t.lineType IN ('省内线路', '省内', '国内线路', '国内') + AND (ins.id IS NULL OR ins.state <> @abandonState) """ + excludeSql); sql.setParam("year", year); - sql.setParam("finishedState", ProcessInstanceStateEnum.FINISHED.getCode()); + sql.setParam("abandonState", ProcessInstanceStateEnum.ABANDON.getCode()); if (StrUtil.isNotBlank(excludeLedgerId)) { sql.setParam("excludeLedgerId", excludeLedgerId); } @@ -1150,16 +1224,16 @@ public class TourSignupController { private int countYearOutProvinceSignupPeople(int year, String excludeLedgerId) { String excludeSql = StrUtil.isBlank(excludeLedgerId) ? "" : " AND t.id <> @excludeLedgerId"; Sql sql = Sqls.create(""" - SELECT COUNT(1) + SELECT COUNT(DISTINCT t.id) FROM tour_ledger t LEFT JOIN wf_process_instance ins ON ins.businessNo = t.id WHERE t.delFlag = 0 AND t.`year` = @year AND t.lineType IN ('省外线路', '省外') - AND (ins.id IS NULL OR ins.state = @finishedState) + AND (ins.id IS NULL OR ins.state <> @abandonState) """ + excludeSql); sql.setParam("year", year); - sql.setParam("finishedState", ProcessInstanceStateEnum.FINISHED.getCode()); + sql.setParam("abandonState", ProcessInstanceStateEnum.ABANDON.getCode()); if (StrUtil.isNotBlank(excludeLedgerId)) { sql.setParam("excludeLedgerId", excludeLedgerId); } @@ -1267,7 +1341,6 @@ public class TourSignupController { } private record OutProvinceQuota(String ratioType, - BigDecimal ratio, int basePeople, int totalSignupPeople, int outProvinceSignupPeople, @@ -1277,14 +1350,7 @@ public class TourSignupController { } String ratioText() { - if (ratio == null || BigDecimal.ZERO.compareTo(ratio) == 0) { - return "0"; - } - BigDecimal oneThird = BigDecimal.ONE.divide(BigDecimal.valueOf(3), 8, RoundingMode.HALF_UP); - if (ratio.subtract(oneThird).abs().compareTo(BigDecimal.valueOf(0.01)) <= 0) { - return "1/3"; - } - return ratio.stripTrailingZeros().toPlainString(); + return "floor(省内有效人数/2)-省外有效人数"; } } @@ -1457,6 +1523,19 @@ public class TourSignupController { return user == null ? SecurityUtil.getUserLoginname() : defaultIfBlank(user.getLoginname(), SecurityUtil.getUserLoginname()); } + private String getSignupOrderColumn(String orderName) { + if ("jobNo".equals(orderName)) { + return "t.jobNo"; + } + if ("userName".equals(orderName)) { + return "t.userName"; + } + if ("unionName".equals(orderName)) { + return "t.unionName"; + } + return "t.signupTime"; + } + private String getOrderColumn(String orderName) { if ("lineName".equals(orderName)) { return "l.lineName"; diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourTravelAgencyController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourTravelAgencyController.java index 900a571..926c486 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourTravelAgencyController.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourTravelAgencyController.java @@ -23,6 +23,7 @@ public class TourTravelAgencyController { private static final String MOBILE_PATTERN = "^1[3-9]\\d{9}$"; private static final String EMAIL_PATTERN = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$"; + private static final String SORT_CODE_PATTERN = "^\\d+$"; @Inject private TourTravelAgencyService travelAgencyService; @@ -77,7 +78,7 @@ public class TourTravelAgencyController { sameCodeCnd.and(TourTravelAgency::getId, "<>", agency.getId()); } if (travelAgencyService.count(sameCodeCnd) > 0) { - return Result.error("同年度下旅行社编号已存在"); + return Result.error("同年度下排序编号已存在"); } if (agency.getEnabled() == null) { agency.setEnabled(true); @@ -113,7 +114,10 @@ public class TourTravelAgencyController { return Result.error("旅行社名称不能为空"); } if (StrUtil.isBlank(agency.getAgencyCode())) { - return Result.error("旅行社编号不能为空"); + return Result.error("排序编号不能为空"); + } + if (!agency.getAgencyCode().matches(SORT_CODE_PATTERN)) { + return Result.error("排序编号必须为整数"); } if (StrUtil.isBlank(agency.getContactName())) { return Result.error("联系人不能为空"); diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourUndertakeController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourUndertakeController.java new file mode 100644 index 0000000..1166b2d --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourUndertakeController.java @@ -0,0 +1,530 @@ +package com.budwk.app.zhgh.dayofficework.tour.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.util.StrUtil; +import com.budwk.app.base.constant.RoleConstant; +import com.budwk.app.base.page.Pagination; +import com.budwk.app.base.param.PageForm; +import com.budwk.app.base.result.Result; +import com.budwk.app.sys.models.Sys_union; +import com.budwk.app.web.commons.auth.utils.AuthUtil; +import com.budwk.app.web.commons.auth.utils.SecurityUtil; +import com.budwk.app.zhgh.dayofficework.tour.models.TourMatter; +import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerService; +import com.budwk.app.zhgh.dayofficework.tour.service.TourMatterService; +import org.nutz.dao.Cnd; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.dao.util.cri.SqlExpressionGroup; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.util.NutMap; +import org.nutz.mvc.annotation.At; +import org.nutz.mvc.annotation.Ok; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@IocBean +@Ok("json:full") +@At("/platform/tour/undertake") +public class TourUndertakeController { + + @Inject + private TourMatterService tourMatterService; + + @Inject + private TourLedgerService tourLedgerService; + + @At("") + @Ok("beetl:/platform/zhgh/dayofficework/Tour/undertake/index.html") + @SaCheckPermission("tour.undertake") + public void index() { + } + + @At + @SaCheckPermission("tour.undertake") + public Result pageData(PageForm pageForm, Integer year, String lineName, String lineType, String unionId, String undertakeStatus) { + if (StrUtil.isBlank(pageForm.getPageOrderName())) { + pageForm.defaultSortAsc("lineName"); + } + Cnd cnd = buildQueryCnd(year, lineName, lineType, unionId, undertakeStatus); + boolean sysAdmin = AuthUtil.hasRole(RoleConstant.SYSADMIN.name()); + boolean showCurrentUnionSignupCount = !AuthUtil.hasRole(RoleConstant.SYSADMIN.name()) + && StrUtil.isNotBlank(SecurityUtil.getUnionId()); + String currentUnionId = showCurrentUnionSignupCount ? SecurityUtil.getUnionId() : ""; + + Sql countSql = Sqls.create(""" + SELECT COUNT(1) + FROM tour_matter m + INNER JOIN tour_line l ON l.id = m.lineId + LEFT JOIN sys_union u ON u.id = m.unionId + $condition + """); + countSql.setCondition(cnd); + countSql.setCallback(Sqls.callback.integer()); + tourMatterService.dao().execute(countSql); + int count = countSql.getInt(); + + Sql listSql = Sqls.create(""" + SELECT + m.id AS matterId, + m.`year`, + m.matterName, + m.unionId, + CASE + WHEN IFNULL(NULLIF(m.undertakeStatus, ''), 'unclaimed') = 'claimed' THEN COALESCE(u.name, '校工会') + ELSE '' + END AS unionName, + IFNULL(NULLIF(m.undertakeStatus, ''), 'unclaimed') AS undertakeStatus, + CASE + WHEN IFNULL(NULLIF(m.undertakeStatus, ''), 'unclaimed') = 'claimed' THEN '已领' + ELSE '未领' + END AS undertakeStatusName, + m.lineId, + l.lineName, + l.lineType, + l.directFamilyUnitLine, + m.travelStartTime, + m.travelEndTime, + CASE + WHEN IFNULL(m.travelStartTime, '') <> '' AND IFNULL(m.travelEndTime, '') <> '' + THEN CONCAT(m.travelStartTime, ' 至 ', m.travelEndTime) + ELSE '' + END AS travelPeriod, + m.minGroupPeople, + m.maxGroupPeople, + IFNULL(sc.signupCount, 0) AS signupCount, + IFNULL(usc.currentUnionSignupCount, 0) AS currentUnionSignupCount, + CASE + WHEN m.maxGroupPeople IS NOT NULL AND m.maxGroupPeople > 0 AND IFNULL(sc.signupCount, 0) > m.maxGroupPeople THEN 'over' + WHEN m.minGroupPeople IS NOT NULL AND m.minGroupPeople > 0 AND IFNULL(sc.signupCount, 0) >= m.minGroupPeople THEN 'formed' + ELSE 'unformed' + END AS groupStatus, + CASE + WHEN m.maxGroupPeople IS NOT NULL AND m.maxGroupPeople > 0 AND IFNULL(sc.signupCount, 0) > m.maxGroupPeople THEN '超员' + WHEN m.minGroupPeople IS NOT NULL AND m.minGroupPeople > 0 AND IFNULL(sc.signupCount, 0) >= m.minGroupPeople THEN '已成团' + ELSE '未成团' + END AS groupStatusName + FROM tour_matter m + INNER JOIN tour_line l ON l.id = m.lineId + LEFT JOIN sys_union u ON u.id = m.unionId + LEFT JOIN ( + SELECT t.matterId, SUM(1 + IFNULL(f.familyCount, 0)) AS signupCount + FROM tour_ledger t + LEFT JOIN ( + SELECT ledgerId, COUNT(1) AS familyCount + FROM tour_ledger_family + WHERE delFlag = 0 + GROUP BY ledgerId + ) f ON f.ledgerId = t.id + WHERE t.delFlag = 0 + AND t.matterId IS NOT NULL + AND t.matterId <> '' + GROUP BY t.matterId + ) sc ON sc.matterId = m.id + LEFT JOIN ( + SELECT t.matterId, SUM(1 + IFNULL(f.familyCount, 0)) AS currentUnionSignupCount + FROM tour_ledger t + LEFT JOIN ( + SELECT ledgerId, COUNT(1) AS familyCount + FROM tour_ledger_family + WHERE delFlag = 0 + GROUP BY ledgerId + ) f ON f.ledgerId = t.id + WHERE t.delFlag = 0 + AND t.matterId IS NOT NULL + AND t.matterId <> '' + AND t.unionId = @currentUnionId + GROUP BY t.matterId + ) usc ON usc.matterId = m.id + $condition + ORDER BY $orderColumn $orderBy, m.`year` DESC, m.travelStartTime ASC, l.lineName ASC, m.createdAt DESC + """); + listSql.setCondition(cnd); + listSql.setParam("currentUnionId", currentUnionId); + listSql.setVar("orderColumn", getOrderColumn(pageForm.getPageOrderName())); + listSql.setVar("orderBy", "descending".equals(pageForm.getPageOrderBy()) ? "desc" : "asc"); + listSql.setPager(tourMatterService.dao().createPager(pageForm.getPageNumber(), pageForm.getPageSize())); + listSql.setCallback(Sqls.callback.maps()); + tourMatterService.dao().execute(listSql); + + List list = listSql.getList(NutMap.class); + for (NutMap item : list) { + item.put("showCurrentUnionSignupCount", showCurrentUnionSignupCount); + item.put("canRelease", sysAdmin && "claimed".equals(item.getString("undertakeStatus", ""))); + } + Pagination pagination = new Pagination<>(pageForm.getPageNumber(), pageForm.getPageSize(), count, list); + return Result.success(pagination); + } + + @At + @SaCheckPermission("tour.undertake") + public Result unionOptions() { + Cnd cnd = Cnd.NEW(); + cnd.asc("unionCode"); + cnd.asc("name"); + return Result.success(tourMatterService.dao().query(Sys_union.class, cnd)); + } + + @At + @SaCheckPermission("tour.undertake") + public Result currentUnion() { + NutMap unionInfo = currentUnionInfo(); + if (unionInfo.isEmpty()) { + return Result.error("未获取到当前登录人工会"); + } + return Result.success(unionInfo); + } + + @At + @SaCheckPermission("tour.undertake") + public Result undertakeLine(String matterId) { + if (StrUtil.isBlank(matterId)) { + return Result.error("参数错误"); + } + NutMap unionInfo = currentUnionInfo(); + if (unionInfo.isEmpty()) { + return Result.error("未获取到当前登录人工会"); + } + TourMatter matter = tourMatterService.fetch(matterId); + if (matter == null || Boolean.TRUE.equals(matter.getDelFlag())) { + return Result.error("事项不存在"); + } + if ("claimed".equals(matter.getUndertakeStatus())) { + return Result.error("当前线路已领办,不允许修改"); + } + matter.setUnionId(unionInfo.getString("unionId")); + matter.setUndertakeStatus("claimed"); + tourMatterService.update(matter); + return Result.success(unionInfo); + } + + @At + @SaCheckPermission("tour.undertake") + public Result releaseUndertakeLine(String matterId) { + if (!AuthUtil.hasRole(RoleConstant.SYSADMIN.name())) { + return Result.error("仅系统管理员可以解除领办"); + } + if (StrUtil.isBlank(matterId)) { + return Result.error("参数错误"); + } + TourMatter matter = tourMatterService.fetch(matterId); + if (matter == null || Boolean.TRUE.equals(matter.getDelFlag())) { + return Result.error("事项不存在"); + } + if (!"claimed".equals(matter.getUndertakeStatus())) { + return Result.error("当前线路未领办,无需解除"); + } + matter.setUnionId(""); + matter.setUndertakeStatus("unclaimed"); + tourMatterService.update(matter); + return Result.success(); + } + + @At + @SaCheckPermission("tour.undertake") + public Result lineTypeOptions(Integer year) { + Cnd cnd = buildQueryCnd(year, null, null, null, null); + Sql sql = Sqls.create(""" + SELECT DISTINCT l.lineType + FROM tour_matter m + INNER JOIN tour_line l ON l.id = m.lineId + LEFT JOIN sys_union u ON u.id = m.unionId + $condition + ORDER BY l.lineType ASC + """); + sql.setCondition(cnd); + sql.setCallback(Sqls.callback.maps()); + tourMatterService.dao().execute(sql); + return Result.success(sql.getList(NutMap.class)); + } + + private NutMap currentUnionInfo() { + String unionId = SecurityUtil.getUnionId(); + if (StrUtil.isBlank(unionId)) { + return NutMap.NEW(); + } + Sys_union union = tourMatterService.dao().fetch(Sys_union.class, unionId); + if (union == null) { + return NutMap.NEW(); + } + return NutMap.NEW() + .addv("unionId", union.getId()) + .addv("unionName", union.getName()); + } + + @At + @SaCheckPermission("tour.undertake") + public Result signupPageData(PageForm pageForm, String matterId, String keyword, String unionId) { + if (StrUtil.isBlank(matterId)) { + return Result.error("参数错误"); + } + if (StrUtil.isBlank(pageForm.getPageOrderName())) { + pageForm.defaultSortDesc("signupTime"); + } + Cnd cnd = buildSignupQueryCnd(matterId, keyword, unionId); + Sql countSql = Sqls.create(""" + SELECT COUNT(1) + FROM tour_ledger t + INNER JOIN tour_matter m ON m.id = t.matterId + INNER JOIN tour_line l ON l.id = m.lineId + $condition + """); + countSql.setCondition(cnd); + countSql.setCallback(Sqls.callback.integer()); + tourLedgerService.dao().execute(countSql); + int count = countSql.getInt(); + + Sql listSql = Sqls.create(""" + SELECT + t.id, + t.jobNo, + t.userName, + '' AS mobile, + t.idCard, + t.unionId, + t.unionName, + t.signupTime + FROM tour_ledger t + INNER JOIN tour_matter m ON m.id = t.matterId + INNER JOIN tour_line l ON l.id = m.lineId + $condition + ORDER BY $orderColumn $orderBy, t.signupTime DESC, t.createdAt DESC + """); + listSql.setCondition(cnd); + listSql.setVar("orderColumn", getSignupOrderColumn(pageForm.getPageOrderName())); + listSql.setVar("orderBy", "ascending".equals(pageForm.getPageOrderBy()) ? "asc" : "desc"); + listSql.setPager(tourLedgerService.dao().createPager(pageForm.getPageNumber(), pageForm.getPageSize())); + listSql.setCallback(Sqls.callback.maps()); + tourLedgerService.dao().execute(listSql); + + List list = listSql.getList(NutMap.class); + fillSignupMobile(list); + fillSignupFamilies(list); + Pagination pagination = new Pagination<>(pageForm.getPageNumber(), pageForm.getPageSize(), count, list); + return Result.success(pagination); + } + + private Cnd buildSignupQueryCnd(String matterId, String keyword, String unionId) { + Cnd cnd = Cnd.NEW(); + cnd.and("t.delFlag", "=", false); + cnd.and("t.matterId", "=", matterId); + cnd.and("m.delFlag", "=", false); + cnd.and("m.enabled", "=", true); + cnd.and("m.lineId", "IS NOT", null); + cnd.and("m.lineId", "<>", ""); + cnd.and("l.delFlag", "=", false); + cnd.and("l.enabled", "=", true); + if (StrUtil.isNotBlank(keyword)) { + SqlExpressionGroup keywordGroup = new SqlExpressionGroup(); + keywordGroup.orLike("t.userName", keyword.trim()); + keywordGroup.orLike("t.jobNo", keyword.trim()); + cnd.and(keywordGroup); + } + cnd.andEX("t.unionId", "=", unionId); + applyMatterDataScope(cnd); + return cnd; + } + + private void fillSignupMobile(List list) { + if (list == null || list.isEmpty()) { + return; + } + List jobNos = new ArrayList<>(); + for (NutMap item : list) { + String jobNo = item.getString("jobNo", ""); + if (StrUtil.isNotBlank(jobNo) && !jobNos.contains(jobNo)) { + jobNos.add(jobNo); + } + } + if (jobNos.isEmpty()) { + return; + } + + Sql sql = Sqls.create("SELECT loginname, mobile FROM vw_user WHERE loginname IN (@jobNos)"); + sql.setParam("jobNos", jobNos.toArray(new String[0])); + sql.setCallback(Sqls.callback.maps()); + tourLedgerService.dao().execute(sql); + + Map mobileMap = new HashMap<>(); + for (NutMap user : sql.getList(NutMap.class)) { + mobileMap.put(user.getString("loginname", ""), user.getString("mobile", "")); + } + for (NutMap item : list) { + item.put("mobile", mobileMap.getOrDefault(item.getString("jobNo", ""), "")); + } + } + + /** + * 查看成团报名人员时按台账ID带出家属子列表,避免前端逐行请求家属信息。 + */ + private void fillSignupFamilies(List list) { + if (list == null || list.isEmpty()) { + return; + } + List ledgerIds = new ArrayList<>(); + for (NutMap item : list) { + String ledgerId = item.getString("id", ""); + if (StrUtil.isNotBlank(ledgerId) && !ledgerIds.contains(ledgerId)) { + ledgerIds.add(ledgerId); + } + } + if (ledgerIds.isEmpty()) { + return; + } + + Sql sql = Sqls.create(""" + SELECT + ledgerId, + staffJobNo AS jobNo, + familyName AS userName, + '' AS mobile, + idCard, + relationship + FROM tour_ledger_family + WHERE delFlag = 0 + AND ledgerId IN (@ledgerIds) + ORDER BY createdAt ASC + """); + sql.setParam("ledgerIds", ledgerIds.toArray(new String[0])); + sql.setCallback(Sqls.callback.maps()); + tourLedgerService.dao().execute(sql); + + Map> familyMap = new HashMap<>(); + for (NutMap family : sql.getList(NutMap.class)) { + familyMap.computeIfAbsent(family.getString("ledgerId", ""), key -> new ArrayList<>()).add(family); + } + for (NutMap item : list) { + item.put("families", familyMap.getOrDefault(item.getString("id", ""), List.of())); + } + } + + private Cnd buildQueryCnd(Integer year, String lineName, String lineType, String unionId, String undertakeStatus) { + Cnd cnd = Cnd.NEW(); + cnd.and("m.delFlag", "=", false); + cnd.and("m.enabled", "=", true); + cnd.and("m.lineId", "IS NOT", null); + cnd.and("m.lineId", "<>", ""); + cnd.and("l.delFlag", "=", false); + cnd.and("l.enabled", "=", true); + cnd.andEX("m.`year`", "=", year == null ? LocalDate.now().getYear() : year); + cnd.and(Cnd.likeEX("l.lineName", lineName)); + cnd.andEX("l.lineType", "=", lineType); + cnd.andEX("m.unionId", "=", unionId); + if ("claimed".equals(undertakeStatus)) { + cnd.and("m.undertakeStatus", "=", "claimed"); + } else if ("unclaimed".equals(undertakeStatus)) { + SqlExpressionGroup statusGroup = new SqlExpressionGroup(); + statusGroup.or("m.undertakeStatus", "=", "unclaimed"); + statusGroup.or("m.undertakeStatus", "IS", null); + statusGroup.or("m.undertakeStatus", "=", ""); + cnd.and(statusGroup); + } + applyMatterDataScope(cnd); + return cnd; + } + + /** + * 线路成团按事项归属控制数据范围:校工会查看全部;分工会查看本工会事项;其它角色仅查看自己创建的事项。 + */ + private void applyMatterDataScope(Cnd cnd) { + if (hasSchoolUnionScope() || AuthUtil.hasRole(RoleConstant.BRANCH_UNION_CHAIRMAN.name())) { + return; + } + if (hasBranchUnionScope()) { + cnd.and("m.unionId", "=", SecurityUtil.getUnionId()); + return; + } + SqlExpressionGroup creatorGroup = new SqlExpressionGroup(); + creatorGroup.or("m.creatorUserId", "=", SecurityUtil.getUserId()); + creatorGroup.or("m.createdBy", "=", SecurityUtil.getUserId()); + cnd.and(creatorGroup); + } + + private boolean hasSchoolUnionScope() { + return AuthUtil.hasRole(RoleConstant.SYSADMIN.name()) + || AuthUtil.hasRole(RoleConstant.SCHOOL_UNION_ADMIN.name()) + || AuthUtil.hasRole(RoleConstant.SCHOOL_UNION_CHAIRMAN.name()) + || AuthUtil.hasRole(RoleConstant.SCHOOL_UNION_VICE_CHAIRMAN.name()) + || AuthUtil.hasRole(RoleConstant.SCHOOL_UNION_WELFARE_ADMIN.name()) + || AuthUtil.hasRole(RoleConstant.SCHOOL_UNION_MEMBER_ADMIN.name()) + || AuthUtil.hasRole(RoleConstant.SCHOOL_UNION_TC_ADMIN.name()) + || AuthUtil.hasRole(RoleConstant.SCHOOL_UNION_WC_ADMIN.name()) + || AuthUtil.hasRole(RoleConstant.SCHOOL_UNION_DC_ADMIN.name()) + || AuthUtil.hasRole(RoleConstant.SCHOOL_UNION_PROPOSAL_ADMIN.name()) + || AuthUtil.hasRole(RoleConstant.SCHOOL_UNION_CLUB_ADMIN.name()) + || AuthUtil.hasRole(RoleConstant.SCHOOL_UNION_ACTIVITY_ADMIN.name()); + } + + private boolean hasBranchUnionScope() { + return AuthUtil.hasRole(RoleConstant.BRANCH_UNION_ADMIN.name()) + || AuthUtil.hasRole(RoleConstant.BRANCH_UNION_CHAIRMAN.name()) + || AuthUtil.hasRole(RoleConstant.BRANCH_UNION_VICE_CHAIRMAN.name()) + || AuthUtil.hasRole(RoleConstant.BRANCH_UNION_OPERATOR.name()) + || AuthUtil.hasRole(RoleConstant.BRANCH_UNION_GROUP_LEADER.name()) + || AuthUtil.hasRole(RoleConstant.BRANCH_UNION_ARTICLE_WRITER.name()) + || AuthUtil.hasRole(RoleConstant.BRANCH_UNION_WY.name()) + || AuthUtil.hasRole(RoleConstant.BRANCH_UNION_ZUZHI_WY.name()) + || AuthUtil.hasRole(RoleConstant.BRANCH_UNION_XUANCHUAN_WY.name()) + || AuthUtil.hasRole(RoleConstant.BRANCH_UNION_NVGONG_WY.name()) + || AuthUtil.hasRole(RoleConstant.BRANCH_UNION_QINGNIAN_WY.name()) + || AuthUtil.hasRole(RoleConstant.BRANCH_UNION_WENTI_WY.name()) + || AuthUtil.hasRole(RoleConstant.BRANCH_UNION_SHENGGHUO_WY.name()) + || AuthUtil.hasRole(RoleConstant.BRANCH_UNION_TIAOJIE_WY.name()) + || AuthUtil.hasRole(RoleConstant.BRANCH_UNION_WENTI_SPORTS.name()); + } + + private String getOrderColumn(String orderName) { + if ("lineName".equals(orderName)) { + return "l.lineName"; + } + if ("travelPeriod".equals(orderName)) { + return "m.travelStartTime"; + } + if ("matterName".equals(orderName)) { + return "m.matterName"; + } + if ("unionName".equals(orderName)) { + return "u.name"; + } + if ("undertakeStatusName".equals(orderName)) { + return "undertakeStatus"; + } + if ("lineType".equals(orderName)) { + return "l.lineType"; + } + if ("signupCount".equals(orderName)) { + return "signupCount"; + } + if ("minGroupPeople".equals(orderName)) { + return "m.minGroupPeople"; + } + if ("maxGroupPeople".equals(orderName)) { + return "m.maxGroupPeople"; + } + if ("groupStatusName".equals(orderName)) { + return "groupStatus"; + } + return "l.lineName"; + } + + private String getSignupOrderColumn(String orderName) { + if ("jobNo".equals(orderName)) { + return "t.jobNo"; + } + if ("userName".equals(orderName)) { + return "t.userName"; + } + if ("idCard".equals(orderName)) { + return "t.idCard"; + } + if ("unionName".equals(orderName)) { + return "t.unionName"; + } + return "t.signupTime"; + } +} diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourUnionApprovalController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourUnionApprovalController.java index 4a222e6..d64a39c 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourUnionApprovalController.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourUnionApprovalController.java @@ -7,6 +7,7 @@ import com.budwk.app.base.page.Pagination; import com.budwk.app.base.param.PageForm; import com.budwk.app.base.result.Result; import com.budwk.app.flow.enums.ProcessTaskStateEnum; +import com.budwk.app.sys.views.View_user; import com.budwk.app.web.commons.auth.utils.SecurityUtil; import com.budwk.app.zhgh.dayofficework.tour.models.TourLedger; import com.budwk.app.zhgh.dayofficework.tour.models.TourLedgerDirectRelative; @@ -20,6 +21,7 @@ import org.nutz.dao.sql.Sql; import org.nutz.dao.util.cri.SqlExpressionGroup; import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.Lang; import org.nutz.lang.util.NutMap; import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.Ok; @@ -180,7 +182,7 @@ public class TourUnionApprovalController { .and(TourLedgerDirectRelative::getDelFlag, "=", false)); NutMap signupConfig = getSignupConfig(ledger); return Result.success(NutMap.NEW() - .addv("ledger", ledger) + .addv("ledger", buildLedgerView(ledger)) .addv("travelPeriod", getTravelPeriod(ledger)) .addv("families", tourLedgerFamilyService.query(familyCnd)) .addv("directRelative", directRelative) @@ -189,6 +191,13 @@ public class TourUnionApprovalController { .addv("directFamilyUnitLine", signupConfig.getBoolean("directFamilyUnitLine", false))); } + private NutMap buildLedgerView(TourLedger ledger) { + NutMap map = Lang.obj2nutmap(ledger); + View_user user = tourLedgerService.dao().fetch(View_user.class, Cnd.where("loginname", "=", ledger.getJobNo())); + map.addv("mobile", StrUtil.blankToDefault(ledger.getMobile(), user == null ? "" : StrUtil.blankToDefault(user.getMobile(), ""))); + return map; + } + @At @SaCheckPermission(value = {"tour.unionApproval", "h5.tour.unionApproval"}, mode = SaMode.OR) public Result unionOptions(Boolean audit, Integer startYear, Integer endYear, String keyword, String lineId, String travelPeriod, String lineType) { diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/models/TourLedger.java b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/models/TourLedger.java index 0e1af54..fd34f70 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/models/TourLedger.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/models/TourLedger.java @@ -51,6 +51,11 @@ public class TourLedger extends BaseModel implements Serializable { @ColDefine(type = ColType.VARCHAR, width = 30) private String idCard; + @Column + @Comment("手机号") + @ColDefine(type = ColType.VARCHAR, width = 30) + private String mobile; + @Column @Comment("所在单位ID") @ColDefine(type = ColType.VARCHAR, width = 32) diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/models/TourLine.java b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/models/TourLine.java index 9fbfaef..007999a 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/models/TourLine.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/models/TourLine.java @@ -32,7 +32,7 @@ public class TourLine extends BaseModel implements Serializable { private Integer year; @Column - @Comment("线路编号") + @Comment("排序编号") @ColDefine(type = ColType.VARCHAR, width = 50) private String lineCode; diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/models/TourMatter.java b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/models/TourMatter.java index f06aec8..1e0a28b 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/models/TourMatter.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/models/TourMatter.java @@ -56,6 +56,12 @@ public class TourMatter extends BaseModel implements Serializable { @ColDefine(type = ColType.VARCHAR, width = 32) private String unionId; + @Column + @Comment("领办状态") + @ColDefine(type = ColType.VARCHAR, width = 20) + @Default("unclaimed") + private String undertakeStatus; + @Column @Comment("组织形式") @ColDefine(type = ColType.VARCHAR, width = 100) diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/models/TourSetting.java b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/models/TourSetting.java index 37e212d..52d0f71 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/models/TourSetting.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/models/TourSetting.java @@ -63,6 +63,16 @@ public class TourSetting extends BaseModel implements Serializable { @ColDefine(type = ColType.INT) private Integer maxGroupPeople; + @Column + @Comment("报名开始时间") + @ColDefine(type = ColType.VARCHAR, width = 20) + private String signupStartTime; + + @Column + @Comment("报名结束时间") + @ColDefine(type = ColType.VARCHAR, width = 20) + private String signupEndTime; + @Column @Comment("省外几年去一次") @ColDefine(type = ColType.INT) diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/models/TourTravelAgency.java b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/models/TourTravelAgency.java index 88f0865..0eb1429 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/models/TourTravelAgency.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/models/TourTravelAgency.java @@ -32,7 +32,7 @@ public class TourTravelAgency extends BaseModel implements Serializable { private Integer year; @Column - @Comment("旅行社编号") + @Comment("排序编号") @ColDefine(type = ColType.VARCHAR, width = 50) private String agencyCode; diff --git a/src/main/resources/db/menu/init_tour_menu.sql b/src/main/resources/db/menu/init_tour_menu.sql index 0042dd6..d1b871d 100644 --- a/src/main/resources/db/menu/init_tour_menu.sql +++ b/src/main/resources/db/menu/init_tour_menu.sql @@ -99,6 +99,12 @@ FROM sys_menu p WHERE p.permission = 'tour' AND NOT EXISTS (SELECT 1 FROM (SELECT id FROM sys_menu WHERE permission = 'tour.group') t); +INSERT INTO sys_menu (id, parentId, path, name, aliasName, type, href, target, icon, showit, disabled, permission, note, location, hasChildren, createdBy, createdAt, updatedBy, updatedAt, delFlag, platform, moduleId, picIcon, initialPinyinName, isRecommendApp, isRecommendService) +SELECT 'b7c63f0c73a44a9a8c4f3d3bb1a10013', p.id, CONCAT(p.path, '0012'), '领办线路', 'Tour Undertake', 'menu', '/platform/tour/undertake', 'data-pjax', '', 1, 0, 'tour.undertake', NULL, 12, 0, '', UNIX_TIMESTAMP(NOW()) * 1000, '', UNIX_TIMESTAMP(NOW()) * 1000, 0, 'PC', NULL, NULL, 'l', 0, 0 +FROM sys_menu p +WHERE p.permission = 'tour' + AND NOT EXISTS (SELECT 1 FROM (SELECT id FROM sys_menu WHERE permission = 'tour.undertake') t); + -- 给系统管理员默认授权,其他角色可在角色管理中按需分配。 INSERT INTO sys_role_menu (roleId, menuId) SELECT r.id, m.id @@ -111,6 +117,7 @@ JOIN sys_menu m ON m.permission IN ( 'tour.matter', 'tour.signup', 'tour.group', + 'tour.undertake', 'tour.mysignup', 'tour.unionledger', 'tour.unionApproval', @@ -120,3 +127,14 @@ JOIN sys_menu m ON m.permission IN ( LEFT JOIN sys_role_menu rm ON rm.roleId = r.id AND rm.menuId = m.id WHERE r.code = 'SYSADMIN' AND rm.roleId IS NULL; + +INSERT INTO sys_role_menu (roleId, menuId) +SELECT r.id, m.id +FROM sys_role r +JOIN sys_menu m ON m.permission IN ( + 'tour', + 'tour.undertake' +) +LEFT JOIN sys_role_menu rm ON rm.roleId = r.id AND rm.menuId = m.id +WHERE r.code = 'BRANCH_UNION_CHAIRMAN' + AND rm.roleId IS NULL; diff --git a/src/main/resources/db/tour_ledger_add_mobile.sql b/src/main/resources/db/tour_ledger_add_mobile.sql new file mode 100644 index 0000000..dea17b6 --- /dev/null +++ b/src/main/resources/db/tour_ledger_add_mobile.sql @@ -0,0 +1,2 @@ +ALTER TABLE `tour_ledger` + ADD COLUMN `mobile` varchar(30) DEFAULT NULL COMMENT '手机号' AFTER `idCard`; diff --git a/src/main/resources/db/tour_matter_add_undertake_status.sql b/src/main/resources/db/tour_matter_add_undertake_status.sql new file mode 100644 index 0000000..2dad488 --- /dev/null +++ b/src/main/resources/db/tour_matter_add_undertake_status.sql @@ -0,0 +1,6 @@ +ALTER TABLE `tour_matter` + ADD COLUMN `undertakeStatus` varchar(20) DEFAULT 'unclaimed' COMMENT '领办状态 claimed已领 unclaimed未领' AFTER `unionId`; + +UPDATE `tour_matter` +SET `undertakeStatus` = 'unclaimed' +WHERE `undertakeStatus` IS NULL OR `undertakeStatus` = ''; diff --git a/src/main/resources/db/tour_matter_create.sql b/src/main/resources/db/tour_matter_create.sql index 7a883bf..52667a1 100644 --- a/src/main/resources/db/tour_matter_create.sql +++ b/src/main/resources/db/tour_matter_create.sql @@ -7,6 +7,7 @@ CREATE TABLE IF NOT EXISTS `tour_matter` ( `creatorUserId` varchar(32) DEFAULT NULL COMMENT '创建人ID', `creatorName` varchar(100) DEFAULT NULL COMMENT '创建人', `unionId` varchar(32) DEFAULT NULL COMMENT '所属工会ID', + `undertakeStatus` varchar(20) DEFAULT 'unclaimed' COMMENT '领办状态 claimed已领 unclaimed未领', `organizationType` varchar(100) DEFAULT NULL COMMENT '组织形式', `mobileThumb` varchar(500) DEFAULT NULL COMMENT '移动端缩略图', `enabled` tinyint(1) DEFAULT 1 COMMENT '事项状态', diff --git a/src/main/resources/db/tour_setting_add_signup_time.sql b/src/main/resources/db/tour_setting_add_signup_time.sql new file mode 100644 index 0000000..6f925ce --- /dev/null +++ b/src/main/resources/db/tour_setting_add_signup_time.sql @@ -0,0 +1,4 @@ +-- 疗休养配置增加全局报名时间字段。 +ALTER TABLE `tour_setting` + ADD COLUMN `signupStartTime` varchar(20) DEFAULT NULL COMMENT '报名开始时间' AFTER `maxGroupPeople`, + ADD COLUMN `signupEndTime` varchar(20) DEFAULT NULL COMMENT '报名结束时间' AFTER `signupStartTime`; diff --git a/src/main/resources/db/tour_setting_create.sql b/src/main/resources/db/tour_setting_create.sql index 4dd9788..fe4e86a 100644 --- a/src/main/resources/db/tour_setting_create.sql +++ b/src/main/resources/db/tour_setting_create.sql @@ -9,6 +9,8 @@ CREATE TABLE IF NOT EXISTS `tour_setting` ( `sortNo` int DEFAULT NULL COMMENT '排序编号', `minGroupPeople` int DEFAULT NULL COMMENT '最少成团人数', `maxGroupPeople` int DEFAULT NULL COMMENT '最多成团人数', + `signupStartTime` varchar(20) DEFAULT NULL COMMENT '报名开始时间', + `signupEndTime` varchar(20) DEFAULT NULL COMMENT '报名结束时间', `outProvinceYears` int DEFAULT NULL COMMENT '省外几年去一次', `outProvinceRatio` decimal(10,2) DEFAULT NULL COMMENT '省外人数占比', `outProvinceRatioType` varchar(50) DEFAULT '当年报名人数' COMMENT '省外人数占比类型', @@ -116,6 +118,7 @@ CREATE TABLE IF NOT EXISTS `tour_matter` ( `creatorUserId` varchar(32) DEFAULT NULL COMMENT '创建人ID', `creatorName` varchar(100) DEFAULT NULL COMMENT '创建人', `unionId` varchar(32) DEFAULT NULL COMMENT '所属工会ID', + `undertakeStatus` varchar(20) DEFAULT 'unclaimed' COMMENT '领办状态 claimed已领 unclaimed未领', `organizationType` varchar(100) DEFAULT NULL COMMENT '组织形式', `mobileThumb` varchar(500) DEFAULT NULL COMMENT '移动端缩略图', `enabled` tinyint(1) DEFAULT 1 COMMENT '事项状态', diff --git a/src/main/resources/db/tour_undertake_menu.sql b/src/main/resources/db/tour_undertake_menu.sql new file mode 100644 index 0000000..9e7d9c3 --- /dev/null +++ b/src/main/resources/db/tour_undertake_menu.sql @@ -0,0 +1,16 @@ +INSERT INTO sys_menu (id, parentId, path, name, aliasName, type, href, target, icon, showit, disabled, permission, note, location, hasChildren, createdBy, createdAt, updatedBy, updatedAt, delFlag, platform, moduleId, picIcon, initialPinyinName, isRecommendApp, isRecommendService) +SELECT 'b7c63f0c73a44a9a8c4f3d3bb1a10013', p.id, CONCAT(p.path, '0012'), '领办线路', 'Tour Undertake', 'menu', '/platform/tour/undertake', 'data-pjax', '', 1, 0, 'tour.undertake', NULL, 12, 0, '', UNIX_TIMESTAMP(NOW()) * 1000, '', UNIX_TIMESTAMP(NOW()) * 1000, 0, 'PC', NULL, NULL, 'l', 0, 0 +FROM sys_menu p +WHERE p.permission = 'tour' + AND NOT EXISTS (SELECT 1 FROM (SELECT id FROM sys_menu WHERE permission = 'tour.undertake') t); + +INSERT INTO sys_role_menu (roleId, menuId) +SELECT r.id, m.id +FROM sys_role r +JOIN sys_menu m ON m.permission IN ( + 'tour', + 'tour.undertake' +) +LEFT JOIN sys_role_menu rm ON rm.roleId = r.id AND rm.menuId = m.id +WHERE r.code IN ('SYSADMIN', 'BRANCH_UNION_CHAIRMAN') + AND rm.roleId IS NULL; diff --git a/src/main/resources/views/platform/zhgh/dayofficework/Tour/ledger/index.html b/src/main/resources/views/platform/zhgh/dayofficework/Tour/ledger/index.html index 1dbbc14..a225591 100644 --- a/src/main/resources/views/platform/zhgh/dayofficework/Tour/ledger/index.html +++ b/src/main/resources/views/platform/zhgh/dayofficework/Tour/ledger/index.html @@ -173,8 +173,8 @@ layout("/layouts/platform.html"){ {{ detail.signupTime || '' }} {{ detail.lineName || '' }} {{ detail.lineType || '' }} - {{ detail.hotelName || '' }} - {{ detail.travelAgencyName || '' }} + {{ detail.hotelName || '' }} + {{ detail.travelAgencyName || '' }} {{ detail.travelPeriod || '' }} {{ detail.bedType || '' }} {{ detail.bedInfo || '' }} diff --git a/src/main/resources/views/platform/zhgh/dayofficework/Tour/matter/index.html b/src/main/resources/views/platform/zhgh/dayofficework/Tour/matter/index.html index ce7e8c9..3d6ea08 100644 --- a/src/main/resources/views/platform/zhgh/dayofficework/Tour/matter/index.html +++ b/src/main/resources/views/platform/zhgh/dayofficework/Tour/matter/index.html @@ -58,13 +58,13 @@ layout("/layouts/platform.html"){ @sort-change="pageOrder"> - - - - + + + + - + - +