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 104984e2..02913aec 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 @@ -667,6 +667,14 @@ public class TourMySignupController { } } if (isInProvinceLine(line.getLineType())) { + // 修改报名时排除当前台账,再按实际参加记录校验省内线路间隔。 + String inProvinceMessage = tourLedgerService.checkInProvinceParticipation( + jobNo, + setting.getInProvinceYears(), + oldLedger == null ? null : oldLedger.getId()); + if (StrUtil.isNotBlank(inProvinceMessage)) { + return Result.error(inProvinceMessage); + } Cnd sameYearCnd = Cnd.where(TourLedger::getDelFlag, "=", false) .and(TourLedger::getJobNo, "=", jobNo) .and(TourLedger::getYear, "=", matter.getYear()); 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 a91a061d..67aa165c 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 @@ -241,6 +241,9 @@ public class TourSettingController { && tourSetting.getMinGroupPeople() > tourSetting.getMaxGroupPeople()) { return Result.error("最少成团人数不能大于最多成团人数"); } + if (tourSetting.getInProvinceYears() != null && tourSetting.getInProvinceYears() < 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 53bf71d6..846ed2dd 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 @@ -531,6 +531,21 @@ public class TourSignupController { .addv("currentLineCost", cycleTotalCost.currentCost()) .addv("message", buildCycleTotalCostNotice(cycleTotalCost))); } + if (isInProvinceLine(line.getLineType())) { + // 进入报名表单前先校验省内参加间隔,最终提交时还会再次执行相同规则。 + String inProvinceMessage = tourLedgerService.checkInProvinceParticipation( + currentJobNo(), + setting.getInProvinceYears(), + oldLedger == null ? null : oldLedger.getId()); + if (StrUtil.isNotBlank(inProvinceMessage)) { + return Result.success(NutMap.NEW() + .addv("canApply", false) + .addv("noticeRequired", true) + .addv("noticeType", "inProvinceYears") + .addv("message", inProvinceMessage)); + } + return Result.success(NutMap.NEW().addv("canApply", true).addv("noticeRequired", false)); + } if (!isOutProvinceLine(line.getLineType())) { return Result.success(NutMap.NEW().addv("canApply", true).addv("noticeRequired", false)); } @@ -940,6 +955,14 @@ public class TourSignupController { } } if (isInProvinceLine(line.getLineType())) { + // 最终提交以台账中的实际参加记录为准,避免绕过资格提示接口直接报名。 + String inProvinceMessage = tourLedgerService.checkInProvinceParticipation( + jobNo, + setting.getInProvinceYears(), + oldLedger == null ? null : oldLedger.getId()); + if (StrUtil.isNotBlank(inProvinceMessage)) { + return Result.error(inProvinceMessage); + } Cnd sameYearCnd = Cnd.where(TourLedger::getDelFlag, "=", false) .and(TourLedger::getJobNo, "=", jobNo) .and(TourLedger::getYear, "=", matter.getYear()); 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 d910d4aa..8b0b1db8 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 @@ -69,6 +69,11 @@ public class TourSetting extends BaseModel implements Serializable { @ColDefine(type = ColType.INT) private Integer maxGroupPeople; + @Column + @Comment("省内几年去一次") + @ColDefine(type = ColType.INT) + private Integer inProvinceYears; + @Column @Comment("省外几年去一次") @ColDefine(type = ColType.INT) diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/service/TourLedgerService.java b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/service/TourLedgerService.java index f8cea93f..296c95dc 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/service/TourLedgerService.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/service/TourLedgerService.java @@ -8,6 +8,18 @@ import com.budwk.app.zhgh.dayofficework.tour.models.TourLedger; */ public interface TourLedgerService extends BaseService { + /** + * 校验当前人员在省内间隔周期内是否已经实际参加过省内线路。 + * + * @param jobNo 当前登录人工号 + * @param inProvinceYears 包含当前年份在内的省内限制年数,小于等于0表示不限制 + * @param excludeLedgerId 修改报名时需要排除的当前台账ID,新增时允许为空 + * @return 校验通过返回空字符串,否则返回不能报名的业务提示 + */ + String checkInProvinceParticipation(String jobNo, + Integer inProvinceYears, + String excludeLedgerId); + /** * 在同一事务中锁定分工会名额、校验并发容量并写入报名台账。 * diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/service/impl/TourLedgerServiceImpl.java b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/service/impl/TourLedgerServiceImpl.java index ff9820db..0b63a786 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/service/impl/TourLedgerServiceImpl.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/service/impl/TourLedgerServiceImpl.java @@ -14,6 +14,8 @@ import org.nutz.ioc.aop.Aop; import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.lang.util.NutMap; +import java.time.LocalDate; + /** * 疗休养报名台账服务实现。 */ @@ -24,6 +26,46 @@ public class TourLedgerServiceImpl extends BaseServiceImpl implement super(dao); } + @Override + public String checkInProvinceParticipation(String jobNo, + Integer inProvinceYears, + String excludeLedgerId) { + if (inProvinceYears == null || inProvinceYears <= 0) { + return ""; + } + if (StrUtil.isBlank(jobNo)) { + return "未查询到当前登录人工号,不能校验省内线路报名资格"; + } + int currentYear = LocalDate.now().getYear(); + // N年按包含当前年份在内的N个自然年度计算,例如2026年的3年周期为2024至2026年。 + long calculatedStartYear = (long) currentYear - inProvinceYears + 1L; + int startYear = calculatedStartYear < 0 ? 0 : (int) calculatedStartYear; + String excludeSql = StrUtil.isBlank(excludeLedgerId) ? "" : " AND id <> @excludeLedgerId"; + Sql sql = Sqls.create(""" + SELECT COUNT(1) + FROM tour_ledger + WHERE delFlag = 0 + AND joined = 1 + AND jobNo = @jobNo + AND `year` >= @startYear + AND `year` <= @currentYear + AND lineType IN ('省内线路', '省内') + """ + excludeSql); + sql.setParam("jobNo", jobNo); + sql.setParam("startYear", startYear); + sql.setParam("currentYear", currentYear); + if (StrUtil.isNotBlank(excludeLedgerId)) { + sql.setParam("excludeLedgerId", excludeLedgerId); + } + sql.setCallback(Sqls.callback.integer()); + dao().execute(sql); + if (sql.getInt() <= 0) { + return ""; + } + return "您在 " + startYear + " 至 " + currentYear + + " 年内已参加过省内线路,省内线路每 " + inProvinceYears + " 年可参加一次,当前不能报名"; + } + @Override @Aop(TransAop.READ_COMMITTED) public String saveWithUnionSignupQuota(TourLedger ledger, diff --git a/src/main/resources/db/tour_setting_create.sql b/src/main/resources/db/tour_setting_create.sql index 4dd97880..8e41e475 100644 --- a/src/main/resources/db/tour_setting_create.sql +++ b/src/main/resources/db/tour_setting_create.sql @@ -9,6 +9,7 @@ CREATE TABLE IF NOT EXISTS `tour_setting` ( `sortNo` int DEFAULT NULL COMMENT '排序编号', `minGroupPeople` int DEFAULT NULL COMMENT '最少成团人数', `maxGroupPeople` int DEFAULT NULL COMMENT '最多成团人数', + `inProvinceYears` int DEFAULT 0 COMMENT '省内几年去一次', `outProvinceYears` int DEFAULT NULL COMMENT '省外几年去一次', `outProvinceRatio` decimal(10,2) DEFAULT NULL COMMENT '省外人数占比', `outProvinceRatioType` varchar(50) DEFAULT '当年报名人数' COMMENT '省外人数占比类型', diff --git a/src/main/resources/views/platform/zhgh/dayofficework/Tour/setting/index.html b/src/main/resources/views/platform/zhgh/dayofficework/Tour/setting/index.html index 77e9777f..6cee45b5 100644 --- a/src/main/resources/views/platform/zhgh/dayofficework/Tour/setting/index.html +++ b/src/main/resources/views/platform/zhgh/dayofficework/Tour/setting/index.html @@ -154,6 +154,14 @@ layout("/layouts/platform.html"){
+ + + + + + +
+
@@ -364,6 +372,14 @@ layout("/layouts/platform.html"){ callback() } } + const checkInProvinceYears = (rule, value, callback) => { + if (value !== null && value !== undefined && value !== "" + && (!Number.isInteger(Number(value)) || Number(value) < 0)) { + callback(new Error("省内间隔年限必须为非负整数")) + } else { + callback() + } + } return { title: "", dialogVisible: false, @@ -388,6 +404,7 @@ layout("/layouts/platform.html"){ travelPeopleQuota: [{required: true, message: "必填", trigger: ["blur", "change"]}], minGroupPeople: [{validator: checkGroupPeople, trigger: ["blur", "change"]}], maxGroupPeople: [{validator: checkGroupPeople, trigger: ["blur", "change"]}], + inProvinceYears: [{validator: checkInProvinceYears, trigger: ["blur", "change"]}], outProvinceRatioType: [{required: true, message: "必填", trigger: ["blur", "change"]}], outProvinceFixedPeople: [{validator: checkOutProvinceFixedPeople, trigger: ["blur", "change"]}], cycleStartYear: [{validator: checkCycleYear, trigger: ["blur", "change"]}], @@ -539,6 +556,7 @@ layout("/layouts/platform.html"){ sortNo: 0, minGroupPeople: 0, maxGroupPeople: 0, + inProvinceYears: 0, outProvinceYears: 0, outProvinceRatio: 0, outProvinceRatioType: "当年报名人数", @@ -632,6 +650,7 @@ layout("/layouts/platform.html"){ this.formData = Object.assign({ travelPeopleQuota: 0, activityGroupId: "", + inProvinceYears: 0, outProvinceRatioType: "当年报名人数", outProvinceFixedPeople: 0, cycleStartYear: "",