diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourBranchUserAssignmentController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourBranchUserAssignmentController.java index 1dba1fd8..2d1cdbf1 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourBranchUserAssignmentController.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourBranchUserAssignmentController.java @@ -119,6 +119,21 @@ public class TourBranchUserAssignmentController { } } + /** + * 给当前分工会已分配正式人员补选分配路线,具体快照回写、代报名和最大成团人数校验由 service 统一处理。 + */ + @At + @Aop(TransAop.READ_COMMITTED) + @SaCheckPermission("tour.branchUserAssignment") + @SLog(type = "tour", tag = "疗休养分工会人员分配", msg = "选择分工会分配事项") + public Result selectMatter(String id, String matterId) { + try { + return Result.success(tourUserAssignmentService.selectCurrentBranchAssignmentMatter(id, matterId)); + } catch (IllegalArgumentException e) { + return Result.error(e.getMessage()); + } + } + /** * 恢复当前分工会已取消退出的人员分配记录,只恢复状态,不恢复已删除台账。 */ diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourLedgerController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourLedgerController.java index 35b2252b..3e97679d 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourLedgerController.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourLedgerController.java @@ -29,6 +29,7 @@ import com.budwk.app.zhgh.dayofficework.tour.models.TourTravelAgency; import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerDirectRelativeService; import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerFamilyService; import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerService; +import com.budwk.app.zhgh.dayofficework.tour.service.TourUserAssignmentService; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.BorderStyle; @@ -93,6 +94,9 @@ public class TourLedgerController { @Inject private TourLedgerDirectRelativeService tourLedgerDirectRelativeService; + @Inject + private TourUserAssignmentService tourUserAssignmentService; + @At("") @Ok("beetl:/platform/zhgh/dayofficework/Tour/ledger/index.html") @SaCheckPermission("tour.ledger") @@ -234,8 +238,11 @@ public class TourLedgerController { if (!canAccessLedgerUnion(ledger.getUnionId())) { return Result.error("无权删除该台账记录"); } + // 删除台账时同步清理台账明细和人员分配中的线路快照,避免人员分配列表继续显示已删除报名的路线信息。 tourLedgerFamilyService.clear(Cnd.where(TourLedgerFamily::getLedgerId, "=", id)); + tourLedgerDirectRelativeService.clear(Cnd.where(TourLedgerDirectRelative::getLedgerId, "=", id)); tourLedgerService.delete(id); + tourUserAssignmentService.clearExistingAssignmentMatterAfterLedgerDelete(ledger.getMatterId(), ledger.getJobNo()); return Result.success(); } 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 e28ee2d1..0034078d 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 @@ -139,11 +139,13 @@ public class TourSignupController { @At("/h5/pageData") @SaCheckPermission(value = {"tour.signup", "h5.tour.signup"}, mode = SaMode.OR) - public Result h5PageData(PageForm pageForm, Integer year, String lineName, String lineType, String unionId, Boolean directFamilyUnitLine) { + public Result h5PageData(PageForm pageForm, Integer year, String lineName, String lineType, String unionId, + String travelPeriod, Boolean directFamilyUnitLine) { if (StrUtil.isBlank(pageForm.getPageOrderName())) { pageForm.defaultSortAsc("lineName"); } Cnd cnd = buildQueryCnd(year, lineName, lineType, unionId); + appendTravelPeriodCnd(cnd, travelPeriod); cnd.andEX("l.directFamilyUnitLine", "=", directFamilyUnitLine); String currentJobNo = currentJobNo(); @@ -372,6 +374,34 @@ public class TourSignupController { return Result.success(sql.getList(NutMap.class)); } + /** + * 查询移动端选择路线页的出行时间筛选项,按 yyyyMMdd-yyyyMMdd 格式拼接事项出行起止时间并去重。 + */ + @At("/h5/travelPeriodOptions") + @SaCheckPermission(value = {"tour.signup", "h5.tour.signup"}, mode = SaMode.OR) + public Result h5TravelPeriodOptions(Integer year, String lineType, Boolean directFamilyUnitLine) { + Cnd cnd = buildQueryCnd(year, null, null, null); + cnd.andEX("l.lineType", "=", lineType); + cnd.andEX("l.directFamilyUnitLine", "=", directFamilyUnitLine); + cnd.and("m.travelStartTime", "IS NOT", null); + cnd.and("m.travelStartTime", "<>", ""); + cnd.and("m.travelEndTime", "IS NOT", null); + cnd.and("m.travelEndTime", "<>", ""); + Sql sql = Sqls.create(""" + SELECT DISTINCT $travelPeriodExpr AS travelPeriod + 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 travelPeriod ASC + """); + sql.setVar("travelPeriodExpr", travelPeriodKeyExpr()); + sql.setCondition(cnd); + sql.setCallback(Sqls.callback.maps()); + tourMatterService.dao().execute(sql); + return Result.success(sql.getList(NutMap.class)); + } + @At @SaCheckPermission(value = {"tour.signup", "h5.tour.signup"}, mode = SaMode.OR) public Result lineDetail(String lineId) { @@ -820,6 +850,18 @@ public class TourSignupController { return cnd; } + private void appendTravelPeriodCnd(Cnd cnd, String travelPeriod) { + if (cnd == null || StrUtil.isBlank(travelPeriod)) { + return; + } + // 移动端出行时间筛选使用 yyyyMMdd-yyyyMMdd 作为稳定值,避免前端直接依赖数据库原始时间格式。 + cnd.and(travelPeriodKeyExpr(), "=", travelPeriod); + } + + private String travelPeriodKeyExpr() { + return "CONCAT(REPLACE(SUBSTRING(m.travelStartTime, 1, 10), '-', ''), '-', REPLACE(SUBSTRING(m.travelEndTime, 1, 10), '-', ''))"; + } + private Result checkSignup(TourLedger ledger) { if (ledger == null) { return Result.error("参数错误"); diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourUnionLedgerController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourUnionLedgerController.java index 068f047e..9fb31d3d 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourUnionLedgerController.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourUnionLedgerController.java @@ -15,6 +15,7 @@ import com.budwk.app.zhgh.dayofficework.tour.models.TourLedgerFamily; import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerDirectRelativeService; import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerFamilyService; import com.budwk.app.zhgh.dayofficework.tour.service.TourLedgerService; +import com.budwk.app.zhgh.dayofficework.tour.service.TourUserAssignmentService; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.BorderStyle; import org.apache.poi.ss.usermodel.Cell; @@ -58,6 +59,9 @@ public class TourUnionLedgerController { @Inject private TourLedgerDirectRelativeService tourLedgerDirectRelativeService; + @Inject + private TourUserAssignmentService tourUserAssignmentService; + @At("") @Ok("beetl:/platform/zhgh/dayofficework/Tour/unionledger/index.html") @SaCheckPermission("tour.unionledger") @@ -206,8 +210,11 @@ public class TourUnionLedgerController { if (ledger == null) { return Result.error("台账记录不存在或无权删除"); } + // 删除分工会台账时同步清理台账明细和人员分配中的线路快照,避免人员分配列表继续显示已删除报名的路线信息。 tourLedgerFamilyService.clear(Cnd.where(TourLedgerFamily::getLedgerId, "=", ledger.getId())); + tourLedgerDirectRelativeService.clear(Cnd.where(TourLedgerDirectRelative::getLedgerId, "=", ledger.getId())); tourLedgerService.clear(Cnd.where(TourLedger::getId, "=", ledger.getId())); + tourUserAssignmentService.clearExistingAssignmentMatterAfterLedgerDelete(ledger.getMatterId(), ledger.getJobNo()); return Result.success(); } diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/service/TourUserAssignmentService.java b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/service/TourUserAssignmentService.java index 9c2b675e..18e837a5 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/service/TourUserAssignmentService.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/service/TourUserAssignmentService.java @@ -115,6 +115,16 @@ public interface TourUserAssignmentService extends BaseService users = Collections.singletonList(fetchAssignmentUserSnapshot(assignment)); + checkProxySignupMaxGroupPeople(matterInfo, users); + updateAssignmentMatterSnapshot(id, matterInfo, TourUserAssignment.ASSIGN_SOURCE_BRANCH_UNION); + int ledgerCount = insertProxySignupLedgers(matterInfo, users); + return NutMap.NEW().addv("ledgerCount", ledgerCount); + } + @Override public NutMap assignBranchUsers(String settingId, String matterId, String personType, List userIds) { String unionId = SecurityUtil.getUnionId(); @@ -358,6 +376,8 @@ public class TourUserAssignmentServiceImpl extends BaseServiceImpl remainingQuota) { throw new IllegalArgumentException("选择人数超过当前分工会剩余名额"); } + // 分工会代报名会占用线路成团人数,人员分配和台账写入前先做后端兜底校验。 + checkProxySignupMaxGroupPeople(matterInfo, candidateUsers); List assignments = candidateUsers.stream() .map(user -> buildAssignment(settingId, matterInfo, normalizedPersonType, user, TourUserAssignment.ASSIGN_SOURCE_BRANCH_UNION)) @@ -506,6 +526,29 @@ public class TourUserAssignmentServiceImpl extends BaseServiceImpl users) { + if (matterInfo == null || Lang.isEmpty(users)) { + return; + } + Integer maxGroupPeople = matterInfo.getInt("maxGroupPeople"); + if (maxGroupPeople == null || maxGroupPeople <= 0) { + return; + } + String matterId = matterInfo.getString("matterId"); + List newSignupUsers = users.stream() + // 已存在同事项台账的人员不会重复代报名,也不再计入本次新增人数。 + .filter(user -> !existsMatterLedger(matterId, user.getString("loginName"))) + .collect(Collectors.toList()); + if (Lang.isEmpty(newSignupUsers)) { + return; + } + int signedPeople = countMatterSignupPeople(matterId); + int totalPeople = signedPeople + newSignupUsers.size(); + if (totalPeople > maxGroupPeople) { + throw new IllegalArgumentException("当前报名人数 " + signedPeople + " 人,本次代报名 " + + newSignupUsers.size() + " 人,最多成团人数 " + maxGroupPeople + " 人,报名后将超过人数上限,不能提交"); + } + } + + private int countMatterSignupPeople(String matterId) { + if (StrUtil.isBlank(matterId)) { + return 0; + } + Sql sql = Sqls.create(""" + SELECT IFNULL(SUM(1 + IFNULL(f.familyCount, 0)), 0) AS signupPeople + 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 = @matterId + """); + sql.setParam("matterId", matterId); + sql.setCallback(Sqls.callback.integer()); + dao().execute(sql); + return sql.getInt(); + } + private boolean existsMatterLedger(String matterId, String loginName) { if (StrUtil.isBlank(matterId) || StrUtil.isBlank(loginName)) { return false; diff --git a/src/main/resources/views/platform/zhgh/dayofficework/Tour/branchUserAssignment/index.html b/src/main/resources/views/platform/zhgh/dayofficework/Tour/branchUserAssignment/index.html index 9c7b0602..87f87d0d 100644 --- a/src/main/resources/views/platform/zhgh/dayofficework/Tour/branchUserAssignment/index.html +++ b/src/main/resources/views/platform/zhgh/dayofficework/Tour/branchUserAssignment/index.html @@ -82,6 +82,7 @@ layout("/layouts/platform.html"){