南大三十年教职工疗休养
This commit is contained in:
+77
-4
@@ -109,6 +109,24 @@ public class ThirtyTeachTourBranchUserAssignmentController {
|
||||
return Result.success(tourUserAssignmentService.branchQuotaInfo(settingId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询当前配置下已启用的出行时间段,供人员分配弹窗按钮组使用。
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("thirtyTeachTour.branchUserAssignment.assign")
|
||||
public Result travelPeriodOptions(String settingId) {
|
||||
return Result.success(tourUserAssignmentService.listBranchEnabledTravelPeriods(settingId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询当前分工会在指定出行时间段内的正式名额,正式人员分配按该口径控制。
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("thirtyTeachTour.branchUserAssignment.assign")
|
||||
public Result periodQuotaInfo(String settingId, String periodId) {
|
||||
return Result.success(tourUserAssignmentService.branchPeriodQuotaInfo(settingId, periodId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存分工会人员分配,保存时数据来源固定为 BRANCH_UNION。
|
||||
*/
|
||||
@@ -116,7 +134,22 @@ public class ThirtyTeachTourBranchUserAssignmentController {
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("thirtyTeachTour.branchUserAssignment.assign")
|
||||
@SLog(type = "tour", tag = "疗休养分工会人员分配", msg = "保存分工会人员分配")
|
||||
public Result doAssign(String settingId, String matterId, String personType, @Param("userIds") String userIds) {
|
||||
public Result doAssign(String settingId, String matterId, String periodId, String personType,
|
||||
@Param("userIds") String userIds, String photoFiles,
|
||||
@Param("assignItems") String assignItems) {
|
||||
if (StrUtil.isNotBlank(assignItems)) {
|
||||
List<NutMap> parsedItems;
|
||||
try {
|
||||
parsedItems = parseAssignItems(assignItems);
|
||||
} catch (Exception e) {
|
||||
return Result.error("人员分配明细参数错误");
|
||||
}
|
||||
try {
|
||||
return Result.success(tourUserAssignmentService.assignBranchUsers(settingId, matterId, periodId, personType, parsedItems));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Result.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
List<String> parsedUserIds;
|
||||
try {
|
||||
parsedUserIds = parseUserIds(userIds);
|
||||
@@ -124,7 +157,8 @@ public class ThirtyTeachTourBranchUserAssignmentController {
|
||||
return Result.error("人员参数错误");
|
||||
}
|
||||
try {
|
||||
return Result.success(tourUserAssignmentService.assignBranchUsers(settingId, matterId, personType, parsedUserIds));
|
||||
return Result.success(tourUserAssignmentService.assignBranchUsers(settingId, matterId, periodId, personType,
|
||||
buildAssignItems(parsedUserIds, photoFiles)));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Result.error(e.getMessage());
|
||||
}
|
||||
@@ -152,9 +186,25 @@ public class ThirtyTeachTourBranchUserAssignmentController {
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("thirtyTeachTour.branchUserAssignment.selectMatter")
|
||||
@SLog(type = "tour", tag = "疗休养分工会人员分配", msg = "选择分工会分配事项")
|
||||
public Result selectMatter(String id, String matterId) {
|
||||
public Result selectMatter(String id, String matterId, String photoFiles) {
|
||||
try {
|
||||
return Result.success(tourUserAssignmentService.selectCurrentBranchAssignmentMatter(id, matterId));
|
||||
return Result.success(tourUserAssignmentService.selectCurrentBranchAssignmentMatter(id, matterId, photoFiles));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Result.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新当前分工会人员分配记录的图片材料,已生成台账时同步回写台账图片。
|
||||
*/
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("thirtyTeachTour.branchUserAssignment.assign")
|
||||
@SLog(type = "tour", tag = "疗休养分工会人员分配", msg = "上传分工会人员分配图片")
|
||||
public Result updatePhotoFiles(String id, String photoFiles) {
|
||||
try {
|
||||
tourUserAssignmentService.updateCurrentBranchAssignmentPhotoFiles(id, photoFiles);
|
||||
return Result.success();
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Result.error(e.getMessage());
|
||||
}
|
||||
@@ -215,6 +265,29 @@ public class ThirtyTeachTourBranchUserAssignmentController {
|
||||
return Lang.isEmpty(list) ? Collections.emptyList() : list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析前端批量人员分配明细,支持每个人携带独立图片材料。
|
||||
*/
|
||||
private List<NutMap> parseAssignItems(String assignItems) {
|
||||
if (StrUtil.isBlank(assignItems)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<NutMap> list = Json.fromJsonAsList(NutMap.class, assignItems);
|
||||
return Lang.isEmpty(list) ? Collections.emptyList() : list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 兼容旧的 userIds 入参,把公共图片材料转换成按人员明细的统一 service 入参。
|
||||
*/
|
||||
private List<NutMap> buildAssignItems(List<String> userIds, String photoFiles) {
|
||||
if (Lang.isEmpty(userIds)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<NutMap> list = new ArrayList<>();
|
||||
userIds.forEach(userId -> list.add(NutMap.NEW().addv("userId", userId).addv("photoFiles", photoFiles)));
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 定义人员分配导出字段,保持与页面列表核心字段一致并补充人员基础信息。
|
||||
*/
|
||||
|
||||
+2
-1
@@ -512,7 +512,8 @@ public class ThirtyTeachTourMySignupController {
|
||||
|
||||
tourLedgerService.updateIgnoreNull(ledger);
|
||||
// 报名台账更新后,仅回填已存在的人员分配记录事项信息,不新增记录、不改变分配来源。
|
||||
tourUserAssignmentService.backfillExistingAssignmentAfterSignup(matter.getSettingId(), matter.getId(), SecurityUtil.getUserId(), ledger.getBoardingPlace());
|
||||
tourUserAssignmentService.backfillExistingAssignmentAfterSignup(matter.getSettingId(), matter.getId(), SecurityUtil.getUserId(),
|
||||
ledger.getBoardingPlace(), ledger.getPhotoFiles());
|
||||
tourLedgerFamilyService.clear(Cnd.where(ThirtyTeachTourLedgerFamily::getLedgerId, "=", ledger.getId()));
|
||||
tourLedgerDirectRelativeService.clear(Cnd.where(ThirtyTeachTourLedgerDirectRelative::getLedgerId, "=", ledger.getId()));
|
||||
if (Lang.isNotEmpty(familyList)) {
|
||||
|
||||
+24
-6
@@ -100,8 +100,10 @@ public class ThirtyTeachTourSchoolUserAssignmentController {
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("thirtyTeachTour.schoolUserAssignment")
|
||||
public Result candidatePageData(PageForm pageForm, String settingId, String unionId, String keyword, @Param("userIds") String userIds) {
|
||||
return Result.success(tourUserAssignmentService.schoolCandidatePage(pageForm, settingId, unionId, keyword, parseUserIds(userIds)));
|
||||
public Result candidatePageData(PageForm pageForm, String settingId, String unionId, String keyword, @Param("userIds") String userIds,
|
||||
Boolean summerJoined, Boolean lastThirtyJoined) {
|
||||
return Result.success(tourUserAssignmentService.schoolCandidatePage(pageForm, settingId, unionId, keyword,
|
||||
parseUserIds(userIds), summerJoined, lastThirtyJoined));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,7 +140,7 @@ public class ThirtyTeachTourSchoolUserAssignmentController {
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("thirtyTeachTour.schoolUserAssignment")
|
||||
@SLog(type = "tour", tag = "疗休养校工会人员分配", msg = "保存校工会人员分配")
|
||||
public Result doAssign(String settingId, String matterId, String personType, @Param("userIds") String userIds) {
|
||||
public Result doAssign(String settingId, String matterId, String personType, @Param("userIds") String userIds, String photoFiles) {
|
||||
List<String> parsedUserIds;
|
||||
try {
|
||||
parsedUserIds = parseUserIds(userIds);
|
||||
@@ -146,7 +148,7 @@ public class ThirtyTeachTourSchoolUserAssignmentController {
|
||||
return Result.error("人员参数错误");
|
||||
}
|
||||
try {
|
||||
return Result.success(tourUserAssignmentService.assignSchoolUsers(settingId, matterId, personType, parsedUserIds));
|
||||
return Result.success(tourUserAssignmentService.assignSchoolUsers(settingId, matterId, personType, parsedUserIds, photoFiles));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Result.error(e.getMessage());
|
||||
}
|
||||
@@ -180,9 +182,25 @@ public class ThirtyTeachTourSchoolUserAssignmentController {
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("thirtyTeachTour.schoolUserAssignment")
|
||||
@SLog(type = "tour", tag = "疗休养校工会人员分配", msg = "选择校工会分配事项")
|
||||
public Result selectMatter(String id, String matterId) {
|
||||
public Result selectMatter(String id, String matterId, String photoFiles) {
|
||||
try {
|
||||
return Result.success(tourUserAssignmentService.selectSchoolAssignmentMatter(id, matterId));
|
||||
return Result.success(tourUserAssignmentService.selectSchoolAssignmentMatter(id, matterId, photoFiles));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Result.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新校工会人员分配记录的图片材料,已生成台账时同步回写台账图片。
|
||||
*/
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("thirtyTeachTour.schoolUserAssignment")
|
||||
@SLog(type = "tour", tag = "疗休养校工会人员分配", msg = "上传校工会人员分配图片")
|
||||
public Result updatePhotoFiles(String id, String photoFiles) {
|
||||
try {
|
||||
tourUserAssignmentService.updateSchoolAssignmentPhotoFiles(id, photoFiles);
|
||||
return Result.success();
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Result.error(e.getMessage());
|
||||
}
|
||||
|
||||
+66
-5
@@ -8,6 +8,7 @@ import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.zhgh.dayofficework.thirtyTeachTour.models.ThirtyTeachTourSetting;
|
||||
import com.budwk.app.zhgh.dayofficework.thirtyTeachTour.models.ThirtyTeachTourSettingLot;
|
||||
import com.budwk.app.zhgh.dayofficework.thirtyTeachTour.models.ThirtyTeachTourSettingTravelPeriod;
|
||||
import com.budwk.app.zhgh.dayofficework.thirtyTeachTour.service.ThirtyTeachTourSettingService;
|
||||
import com.budwk.app.zhgh.dayofficework.thirtyTeachTour.service.ThirtyTeachTourUserAssignmentService;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
@@ -22,8 +23,11 @@ import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@IocBean
|
||||
@@ -77,7 +81,9 @@ public class ThirtyTeachTourSettingController {
|
||||
Cnd lotCnd = Cnd.NEW();
|
||||
lotCnd.desc(ThirtyTeachTourSettingLot::getLotValue);
|
||||
tourSettingService.dao().fetchLinks(tourSetting, "lots", lotCnd);
|
||||
tourSetting.setUnionQuotas(tourSettingService.listUnionQuotaRows(id));
|
||||
tourSetting.setUnionQuotas(tourSettingService.listUnionQuotaRows(id, tourSetting.getYear(), tourSetting.getActivityGroupId()));
|
||||
tourSetting.setTravelPeriods(tourSettingService.listTravelPeriods(id));
|
||||
tourSetting.setPeriodQuotas(tourSettingService.listPeriodQuotas(id));
|
||||
return Result.success(tourSetting);
|
||||
}
|
||||
|
||||
@@ -98,15 +104,17 @@ public class ThirtyTeachTourSettingController {
|
||||
Cnd lotCnd = Cnd.NEW();
|
||||
lotCnd.desc(ThirtyTeachTourSettingLot::getLotValue);
|
||||
tourSettingService.dao().fetchLinks(tourSetting, "lots", lotCnd);
|
||||
tourSetting.setUnionQuotas(tourSettingService.listUnionQuotaRows(tourSetting.getId()));
|
||||
tourSetting.setUnionQuotas(tourSettingService.listUnionQuotaRows(tourSetting.getId(), tourSetting.getYear(), tourSetting.getActivityGroupId()));
|
||||
tourSetting.setTravelPeriods(tourSettingService.listTravelPeriods(tourSetting.getId()));
|
||||
tourSetting.setPeriodQuotas(tourSettingService.listPeriodQuotas(tourSetting.getId()));
|
||||
return Result.success(tourSetting);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("thirtyTeachTour.setting")
|
||||
public Result unionQuotaRows(String settingId) {
|
||||
// 新增配置时 settingId 为空,service 会返回所有分工会的空名额行;编辑时合并已保存名额。
|
||||
return Result.success(tourSettingService.listUnionQuotaRows(settingId));
|
||||
public Result unionQuotaRows(String settingId, Integer year, String activityGroupId) {
|
||||
// 新增配置时 settingId 为空,前端传入年度和可参加人员范围;编辑时 service 会兜底读取配置并合并已保存名额。
|
||||
return Result.success(tourSettingService.listUnionQuotaRows(settingId, year, activityGroupId));
|
||||
}
|
||||
|
||||
@At
|
||||
@@ -123,6 +131,8 @@ public class ThirtyTeachTourSettingController {
|
||||
public Result doSubmit(ThirtyTeachTourSetting tourSetting,
|
||||
@Param(value = "lots") String lots,
|
||||
@Param(value = "unionQuotas") String unionQuotas,
|
||||
@Param(value = "travelPeriods") String travelPeriods,
|
||||
@Param(value = "periodQuotas") String periodQuotas,
|
||||
@Param(value = "lotDeleteList") String[] lotDeleteList) {
|
||||
Result checkResult = check(tourSetting);
|
||||
if (checkResult != null) {
|
||||
@@ -145,6 +155,10 @@ public class ThirtyTeachTourSettingController {
|
||||
if (StrUtil.isNotBlank(quotaLimitMessage)) {
|
||||
return Result.error(quotaLimitMessage);
|
||||
}
|
||||
String periodQuotaLimitMessage = tourSettingService.checkPeriodQuotaLimit(periodQuotas, unionQuotas);
|
||||
if (StrUtil.isNotBlank(periodQuotaLimitMessage)) {
|
||||
return Result.error(periodQuotaLimitMessage);
|
||||
}
|
||||
|
||||
if (tourSetting.getEnabled() == null) {
|
||||
tourSetting.setEnabled(true);
|
||||
@@ -186,6 +200,10 @@ public class ThirtyTeachTourSettingController {
|
||||
if (lotCheckResult != null) {
|
||||
return lotCheckResult;
|
||||
}
|
||||
Result periodCheckResult = checkTravelPeriods(travelPeriods);
|
||||
if (periodCheckResult != null) {
|
||||
return periodCheckResult;
|
||||
}
|
||||
if (StrUtil.isBlank(tourSetting.getId())) {
|
||||
if (Lang.isEmpty(tourSetting.getLots())) {
|
||||
tourSettingService.insert(tourSetting);
|
||||
@@ -193,6 +211,8 @@ public class ThirtyTeachTourSettingController {
|
||||
tourSettingService.insertWith(tourSetting, "lots");
|
||||
}
|
||||
tourSettingService.saveUnionQuotas(tourSetting.getId(), unionQuotas);
|
||||
Set<String> validPeriodIds = tourSettingService.saveTravelPeriods(tourSetting.getId(), travelPeriods);
|
||||
tourSettingService.savePeriodQuotas(tourSetting.getId(), periodQuotas, validPeriodIds);
|
||||
} else {
|
||||
// 编辑时先处理页面删除的标段,再保存配置和当前标段行。
|
||||
if (Lang.isNotEmpty(lotDeleteList)) {
|
||||
@@ -201,6 +221,8 @@ public class ThirtyTeachTourSettingController {
|
||||
tourSettingService.updateIgnoreNull(tourSetting);
|
||||
saveLots(tourSetting);
|
||||
tourSettingService.saveUnionQuotas(tourSetting.getId(), unionQuotas);
|
||||
Set<String> validPeriodIds = tourSettingService.saveTravelPeriods(tourSetting.getId(), travelPeriods);
|
||||
tourSettingService.savePeriodQuotas(tourSetting.getId(), periodQuotas, validPeriodIds);
|
||||
}
|
||||
return Result.success();
|
||||
}
|
||||
@@ -215,6 +237,7 @@ public class ThirtyTeachTourSettingController {
|
||||
}
|
||||
tourSettingService.dao().clear(ThirtyTeachTourSettingLot.class, Cnd.where(ThirtyTeachTourSettingLot::getSettingId, "=", id));
|
||||
tourSettingService.clearUnionQuotas(id);
|
||||
tourSettingService.clearTravelPeriodsAndQuotas(id);
|
||||
tourUserAssignmentService.clearBySettingId(id);
|
||||
tourSettingService.delete(id);
|
||||
return Result.success();
|
||||
@@ -339,4 +362,42 @@ public class ThirtyTeachTourSettingController {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Result checkTravelPeriods(String travelPeriods) {
|
||||
if (StrUtil.isBlank(travelPeriods)) {
|
||||
return null;
|
||||
}
|
||||
List<ThirtyTeachTourSettingTravelPeriod> periodList;
|
||||
try {
|
||||
periodList = Json.fromJsonAsList(ThirtyTeachTourSettingTravelPeriod.class, travelPeriods);
|
||||
} catch (Exception e) {
|
||||
return Result.error("时间段数据格式不正确");
|
||||
}
|
||||
if (Lang.isEmpty(periodList)) {
|
||||
return null;
|
||||
}
|
||||
for (int i = 0; i < periodList.size(); i++) {
|
||||
ThirtyTeachTourSettingTravelPeriod period = periodList.get(i);
|
||||
if (period == null) {
|
||||
continue;
|
||||
}
|
||||
String rowNo = "第" + (i + 1) + "行";
|
||||
if (StrUtil.isBlank(period.getPeriodName())) {
|
||||
return Result.error(rowNo + "时间段名称不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(period.getStartDate()) || StrUtil.isBlank(period.getEndDate())) {
|
||||
return Result.error(rowNo + "开始日期和结束日期不能为空");
|
||||
}
|
||||
try {
|
||||
LocalDate startDate = LocalDate.parse(period.getStartDate());
|
||||
LocalDate endDate = LocalDate.parse(period.getEndDate());
|
||||
if (startDate.isAfter(endDate)) {
|
||||
return Result.error(rowNo + "开始日期不能大于结束日期");
|
||||
}
|
||||
} catch (DateTimeParseException e) {
|
||||
return Result.error(rowNo + "日期格式不正确");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -919,7 +919,8 @@ public class ThirtyTeachTourSignupController {
|
||||
tourLedgerService.insert(ledger);
|
||||
}
|
||||
// 报名台账落库后,仅回填已存在的人员分配记录事项信息,不新增记录、不改变分配来源。
|
||||
tourUserAssignmentService.backfillExistingAssignmentAfterSignup(matter.getSettingId(), matter.getId(), SecurityUtil.getUserId(), ledger.getBoardingPlace());
|
||||
tourUserAssignmentService.backfillExistingAssignmentAfterSignup(matter.getSettingId(), matter.getId(), SecurityUtil.getUserId(),
|
||||
ledger.getBoardingPlace(), ledger.getPhotoFiles());
|
||||
if (Lang.isNotEmpty(familyList)) {
|
||||
familyList.forEach(item -> {
|
||||
item.setLedgerId(ledger.getId());
|
||||
|
||||
+5
@@ -126,6 +126,11 @@ public class ThirtyTeachTourLedger extends BaseModel implements Serializable {
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String boardingPlace;
|
||||
|
||||
@Column
|
||||
@Comment("报名图片材料")
|
||||
@ColDefine(type = ColType.TEXT)
|
||||
private String photoFiles;
|
||||
|
||||
@Column
|
||||
@Comment("是否携带家属")
|
||||
@ColDefine(type = ColType.BOOLEAN)
|
||||
|
||||
+11
@@ -155,11 +155,22 @@ public class ThirtyTeachTourSetting extends BaseModel implements Serializable {
|
||||
@Many(field = "settingId")
|
||||
private List<ThirtyTeachTourSettingLot> lots;
|
||||
|
||||
/**
|
||||
* 时间段管理,仅用于配置弹窗回显与提交,不作为 thirty_teach_tour_setting 表字段保存。
|
||||
*/
|
||||
@Many(field = "settingId")
|
||||
private List<ThirtyTeachTourSettingTravelPeriod> travelPeriods;
|
||||
|
||||
/**
|
||||
* 分工会名额分配,仅用于配置弹窗回显与提交,不作为 thirty_teach_tour_setting 表字段保存。
|
||||
*/
|
||||
private List<ThirtyTeachTourSettingUnionQuota> unionQuotas;
|
||||
|
||||
/**
|
||||
* 时间段名额分配,仅用于配置弹窗回显与提交,不作为 thirty_teach_tour_setting 表字段保存。
|
||||
*/
|
||||
private List<ThirtyTeachTourSettingPeriodQuota> periodQuotas;
|
||||
|
||||
@Column
|
||||
@Comment("服务须知")
|
||||
@ColDefine(type = ColType.TEXT)
|
||||
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
package com.budwk.app.zhgh.dayofficework.thirtyTeachTour.models;
|
||||
|
||||
import com.budwk.app.base.model.BaseModel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.nutz.dao.entity.annotation.ColDefine;
|
||||
import org.nutz.dao.entity.annotation.ColType;
|
||||
import org.nutz.dao.entity.annotation.Column;
|
||||
import org.nutz.dao.entity.annotation.Comment;
|
||||
import org.nutz.dao.entity.annotation.Default;
|
||||
import org.nutz.dao.entity.annotation.Name;
|
||||
import org.nutz.dao.entity.annotation.Table;
|
||||
import org.nutz.dao.entity.annotation.TableMeta;
|
||||
import org.nutz.dao.interceptor.annotation.PrevInsert;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 30年教龄疗休养配置时间段名额。
|
||||
* 该表把分工会正式名额继续拆分到各时间段,保存时会校验同一分工会合计不超过正式名额。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Table("thirty_teach_tour_setting_period_quota")
|
||||
@TableMeta("{'mysql-charset':'utf8mb4'}")
|
||||
@Comment("30年教龄疗休养配置时间段名额")
|
||||
public class ThirtyTeachTourSettingPeriodQuota extends BaseModel implements Serializable {
|
||||
|
||||
@Column
|
||||
@Name
|
||||
@Comment("ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@PrevInsert(uu32 = true)
|
||||
private String id;
|
||||
|
||||
@Column
|
||||
@Comment("所属疗休养配置ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String settingId;
|
||||
|
||||
@Column
|
||||
@Comment("分工会ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String unionId;
|
||||
|
||||
@Column
|
||||
@Comment("分工会名称")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String unionName;
|
||||
|
||||
@Column
|
||||
@Comment("时间段ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String periodId;
|
||||
|
||||
@Column
|
||||
@Comment("时间段名称")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
private String periodName;
|
||||
|
||||
@Column
|
||||
@Comment("正式人员名额")
|
||||
@ColDefine(type = ColType.INT)
|
||||
@Default("0")
|
||||
private Integer formalQuota;
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package com.budwk.app.zhgh.dayofficework.thirtyTeachTour.models;
|
||||
|
||||
import com.budwk.app.base.model.BaseModel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.nutz.dao.entity.annotation.ColDefine;
|
||||
import org.nutz.dao.entity.annotation.ColType;
|
||||
import org.nutz.dao.entity.annotation.Column;
|
||||
import org.nutz.dao.entity.annotation.Comment;
|
||||
import org.nutz.dao.entity.annotation.Default;
|
||||
import org.nutz.dao.entity.annotation.Name;
|
||||
import org.nutz.dao.entity.annotation.Table;
|
||||
import org.nutz.dao.entity.annotation.TableMeta;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 30年教龄疗休养配置时间段。
|
||||
* 时间段只负责配置端细分名额的维度,报名/线路占用校验由后续业务接入时再按该配置扩展。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Table("thirty_teach_tour_setting_travel_period")
|
||||
@TableMeta("{'mysql-charset':'utf8mb4'}")
|
||||
@Comment("30年教龄疗休养配置时间段")
|
||||
public class ThirtyTeachTourSettingTravelPeriod extends BaseModel implements Serializable {
|
||||
|
||||
@Column
|
||||
@Name
|
||||
@Comment("ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String id;
|
||||
|
||||
@Column
|
||||
@Comment("所属疗休养配置ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String settingId;
|
||||
|
||||
@Column
|
||||
@Comment("时间段名称")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
private String periodName;
|
||||
|
||||
@Column
|
||||
@Comment("开始日期")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 10)
|
||||
private String startDate;
|
||||
|
||||
@Column
|
||||
@Comment("结束日期")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 10)
|
||||
private String endDate;
|
||||
|
||||
@Column
|
||||
@Comment("是否启用")
|
||||
@ColDefine(type = ColType.BOOLEAN)
|
||||
@Default("1")
|
||||
private Boolean enabled;
|
||||
}
|
||||
+15
@@ -77,6 +77,21 @@ public class ThirtyTeachTourUserAssignment extends BaseModel implements Serializ
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String boardingPlace;
|
||||
|
||||
@Column
|
||||
@Comment("报名图片材料")
|
||||
@ColDefine(type = ColType.TEXT)
|
||||
private String photoFiles;
|
||||
|
||||
@Column
|
||||
@Comment("出行时间段ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String periodId;
|
||||
|
||||
@Column
|
||||
@Comment("出行时间段名称")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
private String periodName;
|
||||
|
||||
@Column
|
||||
@Comment("人员ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
|
||||
+59
-3
@@ -2,19 +2,40 @@ package com.budwk.app.zhgh.dayofficework.thirtyTeachTour.service;
|
||||
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.zhgh.dayofficework.thirtyTeachTour.models.ThirtyTeachTourSetting;
|
||||
import com.budwk.app.zhgh.dayofficework.thirtyTeachTour.models.ThirtyTeachTourSettingPeriodQuota;
|
||||
import com.budwk.app.zhgh.dayofficework.thirtyTeachTour.models.ThirtyTeachTourSettingTravelPeriod;
|
||||
import com.budwk.app.zhgh.dayofficework.thirtyTeachTour.models.ThirtyTeachTourSettingUnionQuota;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public interface ThirtyTeachTourSettingService extends BaseService<ThirtyTeachTourSetting> {
|
||||
|
||||
/**
|
||||
* 查询所有分工会在指定疗休养配置下的名额,实时补充当前工会会员数供页面分配时参考。
|
||||
* 查询所有分工会在指定疗休养配置下的名额,并实时补充可参加人数供页面分配时参考。
|
||||
*
|
||||
* @param settingId 疗休养配置ID,新增时可为空
|
||||
* @param settingId 疗休养配置ID,新增时可为空
|
||||
* @param year 配置年度,新增未落库时用于计算历史参加情况
|
||||
* @param activityGroupId 可参加人员范围分组ID,新增未落库时用于计算可参加人员
|
||||
* @return 按分工会编码排序后的名额列表
|
||||
*/
|
||||
List<ThirtyTeachTourSettingUnionQuota> listUnionQuotaRows(String settingId);
|
||||
List<ThirtyTeachTourSettingUnionQuota> listUnionQuotaRows(String settingId, Integer year, String activityGroupId);
|
||||
|
||||
/**
|
||||
* 查询配置下维护的时间段,按开始日期和创建时间排序。
|
||||
*
|
||||
* @param settingId 疗休养配置ID
|
||||
* @return 时间段列表
|
||||
*/
|
||||
List<ThirtyTeachTourSettingTravelPeriod> listTravelPeriods(String settingId);
|
||||
|
||||
/**
|
||||
* 查询配置下已保存的时间段名额。
|
||||
*
|
||||
* @param settingId 疗休养配置ID
|
||||
* @return 时间段名额列表
|
||||
*/
|
||||
List<ThirtyTeachTourSettingPeriodQuota> listPeriodQuotas(String settingId);
|
||||
|
||||
/**
|
||||
* 保存指定疗休养配置下的分工会名额,前端传入的是 JSON 数组字符串。
|
||||
@@ -24,6 +45,25 @@ public interface ThirtyTeachTourSettingService extends BaseService<ThirtyTeachTo
|
||||
*/
|
||||
void saveUnionQuotas(String settingId, String unionQuotas);
|
||||
|
||||
/**
|
||||
* 保存指定配置下的时间段,前端传入的是 JSON 数组字符串。
|
||||
* 时间段ID由前端生成并由服务端原样保留,确保同一次提交里的时间段名额可以稳定关联。
|
||||
*
|
||||
* @param settingId 疗休养配置ID
|
||||
* @param travelPeriods 时间段 JSON
|
||||
* @return 本次实际保存且已启用的时间段ID集合
|
||||
*/
|
||||
Set<String> saveTravelPeriods(String settingId, String travelPeriods);
|
||||
|
||||
/**
|
||||
* 保存指定配置下的时间段名额,保存前会清理无效时间段和零名额行。
|
||||
*
|
||||
* @param settingId 疗休养配置ID
|
||||
* @param periodQuotas 时间段名额 JSON
|
||||
* @param validPeriodIds 当前配置下本次实际保存且已启用的时间段ID集合
|
||||
*/
|
||||
void savePeriodQuotas(String settingId, String periodQuotas, Set<String> validPeriodIds);
|
||||
|
||||
/**
|
||||
* 校验分工会正式人员名额合计是否超过分工会总名额。
|
||||
*
|
||||
@@ -33,10 +73,26 @@ public interface ThirtyTeachTourSettingService extends BaseService<ThirtyTeachTo
|
||||
*/
|
||||
String checkBranchFormalQuotaLimit(String unionQuotas, int branchTotalQuota);
|
||||
|
||||
/**
|
||||
* 校验时间段名额合计是否超过对应分工会正式名额。
|
||||
*
|
||||
* @param periodQuotas 时间段名额 JSON
|
||||
* @param unionQuotas 分工会名额 JSON
|
||||
* @return 通过返回空字符串;不通过返回业务提示
|
||||
*/
|
||||
String checkPeriodQuotaLimit(String periodQuotas, String unionQuotas);
|
||||
|
||||
/**
|
||||
* 清理指定疗休养配置下的分工会名额。
|
||||
*
|
||||
* @param settingId 疗休养配置ID
|
||||
*/
|
||||
void clearUnionQuotas(String settingId);
|
||||
|
||||
/**
|
||||
* 清理指定配置下的时间段和时间段名额。
|
||||
*
|
||||
* @param settingId 疗休养配置ID
|
||||
*/
|
||||
void clearTravelPeriodsAndQuotas(String settingId);
|
||||
}
|
||||
|
||||
+46
-8
@@ -73,9 +73,12 @@ public interface ThirtyTeachTourUserAssignmentService extends BaseService<Thirty
|
||||
* @param unionId 所属分工会ID
|
||||
* @param keyword 姓名或工号关键字
|
||||
* @param userIds 指定候选人员ID列表,人员选择器多选查询时使用
|
||||
* @param summerJoinedFilter 今年是否已参加暑期疗休养过滤:true 是,false 否,null 不过滤
|
||||
* @param lastThirtyJoinedFilter 去年是否参加30年教龄疗休养过滤:true 是,false 否,null 不过滤
|
||||
* @return 可分配候选人分页数据
|
||||
*/
|
||||
Pagination<NutMap> schoolCandidatePage(PageForm pageForm, String settingId, String unionId, String keyword, List<String> userIds);
|
||||
Pagination<NutMap> schoolCandidatePage(PageForm pageForm, String settingId, String unionId, String keyword, List<String> userIds,
|
||||
Boolean summerJoinedFilter, Boolean lastThirtyJoinedFilter);
|
||||
|
||||
/**
|
||||
* 分页查询当前登录人所在分工会的人员分配记录,列表只读取人员分配表,不读取报名台账。
|
||||
@@ -157,11 +160,11 @@ public interface ThirtyTeachTourUserAssignmentService extends BaseService<Thirty
|
||||
* @param userIds 待分配人员ID列表
|
||||
* @return 保存结果,包含实际分配数量、跳过数量和代报名台账写入数量
|
||||
*/
|
||||
NutMap assignSchoolUsers(String settingId, String matterId, String personType, List<String> userIds);
|
||||
NutMap assignSchoolUsers(String settingId, String matterId, String personType, List<String> userIds, String photoFiles);
|
||||
|
||||
/**
|
||||
* 保存校工会人员分配,支持每个候选人员单独选择分配线路。
|
||||
* assignItems 中每项包含 userId、matterId;matterId 为空时只保存人员分配,不写台账。
|
||||
* assignItems 中每项包含 userId、matterId、photoFiles;matterId 为空时只保存人员分配,不写台账。
|
||||
*
|
||||
* @param settingId 疗休养配置ID
|
||||
* @param assignItems 人员和分配线路明细
|
||||
@@ -177,7 +180,7 @@ public interface ThirtyTeachTourUserAssignmentService extends BaseService<Thirty
|
||||
* @param matterId 疗休养事项ID
|
||||
* @return 处理结果,包含台账写入数量
|
||||
*/
|
||||
NutMap selectSchoolAssignmentMatter(String id, String matterId);
|
||||
NutMap selectSchoolAssignmentMatter(String id, String matterId, String photoFiles);
|
||||
|
||||
/**
|
||||
* 给当前分工会已分配的正式人员补选分配路线,并按代报名写入疗休养台账。
|
||||
@@ -187,19 +190,38 @@ public interface ThirtyTeachTourUserAssignmentService extends BaseService<Thirty
|
||||
* @param matterId 疗休养事项ID
|
||||
* @return 处理结果,包含台账写入数量
|
||||
*/
|
||||
NutMap selectCurrentBranchAssignmentMatter(String id, String matterId);
|
||||
NutMap selectCurrentBranchAssignmentMatter(String id, String matterId, String photoFiles);
|
||||
|
||||
/**
|
||||
* 查询指定配置下已启用的出行时间段,供分工会人员分配弹窗按时间段选择正式名额。
|
||||
*
|
||||
* @param settingId 疗休养配置ID
|
||||
* @return 已启用出行时间段列表
|
||||
*/
|
||||
List<NutMap> listBranchEnabledTravelPeriods(String settingId);
|
||||
|
||||
/**
|
||||
* 查询当前登录人所在分工会在指定时间段下的正式名额使用情况。
|
||||
*
|
||||
* @param settingId 疗休养配置ID
|
||||
* @param periodId 出行时间段ID
|
||||
* @return 时间段正式名额、已分配人数和剩余人数
|
||||
*/
|
||||
NutMap branchPeriodQuotaInfo(String settingId, String periodId);
|
||||
|
||||
/**
|
||||
* 保存分工会人员分配。保存前会重新按配置可参加人员范围和当前登录人所在分工会过滤,并校验正式/替补名额。
|
||||
* 正式人员必须选择出行时间段,并按“当前分工会 + 出行时间段”校验正式名额;替补人员沿用分工会替补名额。
|
||||
* 疗休养事项为可选;正式人员选择事项时视为代报名并同步写入疗休养台账,替补人员不能分配事项。
|
||||
*
|
||||
* @param settingId 疗休养配置ID
|
||||
* @param matterId 疗休养事项ID,可为空
|
||||
* @param periodId 出行时间段ID,正式人员必填
|
||||
* @param personType 人员类型:FORMAL 正式人员,BACKUP 替补人员
|
||||
* @param userIds 待分配人员ID列表
|
||||
* @param assignItems 待分配人员明细,每项包含 userId、photoFiles
|
||||
* @return 保存结果,包含实际分配数量、跳过数量、代报名台账写入数量和剩余名额
|
||||
*/
|
||||
NutMap assignBranchUsers(String settingId, String matterId, String personType, List<String> userIds);
|
||||
NutMap assignBranchUsers(String settingId, String matterId, String periodId, String personType, List<NutMap> assignItems);
|
||||
|
||||
/**
|
||||
* 切换当前分工会人员分配记录的正式/替补状态。
|
||||
@@ -251,7 +273,7 @@ public interface ThirtyTeachTourUserAssignmentService extends BaseService<Thirty
|
||||
* @param boardingPlace 用户报名时最终选择的乘车地点
|
||||
* @return 更新记录数
|
||||
*/
|
||||
int backfillExistingAssignmentAfterSignup(String settingId, String matterId, String userId, String boardingPlace);
|
||||
int backfillExistingAssignmentAfterSignup(String settingId, String matterId, String userId, String boardingPlace, String photoFiles);
|
||||
|
||||
/**
|
||||
* 用户取消报名删除台账后,清空该用户在同一疗休养配置下已存在人员分配记录的事项快照。
|
||||
@@ -297,6 +319,22 @@ public interface ThirtyTeachTourUserAssignmentService extends BaseService<Thirty
|
||||
*/
|
||||
NutMap branchDeleteInfo(String id);
|
||||
|
||||
/**
|
||||
* 更新校工会人员分配记录的图片材料,并同步该人员已存在的报名台账图片。
|
||||
*
|
||||
* @param id 人员分配记录ID
|
||||
* @param photoFiles 图片材料,多个文件以逗号分隔
|
||||
*/
|
||||
void updateSchoolAssignmentPhotoFiles(String id, String photoFiles);
|
||||
|
||||
/**
|
||||
* 更新当前分工会人员分配记录的图片材料,并同步该人员已存在的报名台账图片。
|
||||
*
|
||||
* @param id 人员分配记录ID
|
||||
* @param photoFiles 图片材料,多个文件以逗号分隔
|
||||
*/
|
||||
void updateCurrentBranchAssignmentPhotoFiles(String id, String photoFiles);
|
||||
|
||||
/**
|
||||
* 删除指定来源的人员分配记录,避免校工会页面误删分工会分配的数据。
|
||||
*
|
||||
|
||||
+193
-9
@@ -4,6 +4,8 @@ import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.sys.models.Sys_union;
|
||||
import com.budwk.app.zhgh.dayofficework.thirtyTeachTour.models.ThirtyTeachTourSetting;
|
||||
import com.budwk.app.zhgh.dayofficework.thirtyTeachTour.models.ThirtyTeachTourSettingPeriodQuota;
|
||||
import com.budwk.app.zhgh.dayofficework.thirtyTeachTour.models.ThirtyTeachTourSettingTravelPeriod;
|
||||
import com.budwk.app.zhgh.dayofficework.thirtyTeachTour.models.ThirtyTeachTourSettingUnionQuota;
|
||||
import com.budwk.app.zhgh.dayofficework.thirtyTeachTour.service.ThirtyTeachTourSettingService;
|
||||
import org.nutz.dao.Cnd;
|
||||
@@ -15,8 +17,10 @@ import org.nutz.json.Json;
|
||||
import org.nutz.lang.Lang;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@IocBean(args = {"refer:dao"})
|
||||
@@ -27,12 +31,18 @@ public class ThirtyTeachTourSettingServiceImpl extends BaseServiceImpl<ThirtyTea
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ThirtyTeachTourSettingUnionQuota> listUnionQuotaRows(String settingId) {
|
||||
// 一次性查出所有分工会、已保存名额和实时会员数,避免页面打开时按分工会循环统计造成 N+1 查询。
|
||||
public List<ThirtyTeachTourSettingUnionQuota> listUnionQuotaRows(String settingId, Integer year, String activityGroupId) {
|
||||
ThirtyTeachTourSetting setting = resolveQuotaSetting(settingId);
|
||||
Integer effectiveYear = year == null && setting != null ? setting.getYear() : year;
|
||||
String effectiveActivityGroupId = StrUtil.isBlank(activityGroupId) && setting != null ? setting.getActivityGroupId() : activityGroupId;
|
||||
String quotaSettingId = settingId == null ? "" : settingId;
|
||||
int previousYear = effectiveYear == null ? 0 : effectiveYear - 1;
|
||||
// 一次性查出所有分工会、已保存名额和可参加人数,避免页面打开时按分工会循环统计造成 N+1 查询。
|
||||
// 可参加人数口径:当前活动人员范围内人员,扣除去年已参加30年教龄疗休养和本年度已参加暑期疗休养的人员。
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
quota.id AS id,
|
||||
@settingId AS settingId,
|
||||
@quotaSettingId AS settingId,
|
||||
un.id AS unionId,
|
||||
un.name AS unionName,
|
||||
COALESCE(quota.formalQuota, 0) AS formalQuota,
|
||||
@@ -41,16 +51,37 @@ public class ThirtyTeachTourSettingServiceImpl extends BaseServiceImpl<ThirtyTea
|
||||
FROM sys_union un
|
||||
LEFT JOIN thirty_teach_tour_setting_union_quota quota
|
||||
ON quota.unionId = un.id
|
||||
AND quota.settingId = @settingId
|
||||
AND quota.settingId = @quotaSettingId
|
||||
LEFT JOIN (
|
||||
SELECT unionId, COUNT(1) AS memberCount
|
||||
FROM vw_user
|
||||
WHERE member = 1
|
||||
GROUP BY unionId
|
||||
SELECT u.unionid AS unionId, COUNT(DISTINCT u.id) AS memberCount
|
||||
FROM activity_user_scope aus
|
||||
INNER JOIN vw_user u ON u.id = aus.userId
|
||||
WHERE aus.groupId = @activityGroupId
|
||||
AND @year > 0
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM thirty_teach_tour_ledger previous_ledger
|
||||
WHERE previous_ledger.delFlag = 0
|
||||
AND previous_ledger.joined = 1
|
||||
AND previous_ledger.`year` = @previousYear
|
||||
AND previous_ledger.jobNo = u.loginname
|
||||
)
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM tour_ledger summer_ledger
|
||||
WHERE summer_ledger.delFlag = 0
|
||||
AND summer_ledger.joined = 1
|
||||
AND summer_ledger.`year` = @year
|
||||
AND summer_ledger.jobNo = u.loginname
|
||||
)
|
||||
GROUP BY u.unionid
|
||||
) user_count ON user_count.unionId = un.id
|
||||
ORDER BY un.unionCode ASC
|
||||
""");
|
||||
sql.setParam("settingId", settingId == null ? "" : settingId);
|
||||
sql.setParam("quotaSettingId", quotaSettingId);
|
||||
sql.setParam("activityGroupId", StrUtil.blankToDefault(effectiveActivityGroupId, ""));
|
||||
sql.setParam("year", effectiveYear == null ? 0 : effectiveYear);
|
||||
sql.setParam("previousYear", previousYear);
|
||||
List<NutMap> rows = listMap(sql);
|
||||
return rows.stream().map(row -> {
|
||||
ThirtyTeachTourSettingUnionQuota quota = new ThirtyTeachTourSettingUnionQuota();
|
||||
@@ -65,6 +96,37 @@ public class ThirtyTeachTourSettingServiceImpl extends BaseServiceImpl<ThirtyTea
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private ThirtyTeachTourSetting resolveQuotaSetting(String settingId) {
|
||||
// 编辑配置时允许前端只传 settingId,服务层兜底读取年度和可参加人员范围,保证接口兼容已有调用。
|
||||
if (StrUtil.isBlank(settingId)) {
|
||||
return null;
|
||||
}
|
||||
return fetch(settingId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ThirtyTeachTourSettingTravelPeriod> listTravelPeriods(String settingId) {
|
||||
if (StrUtil.isBlank(settingId)) {
|
||||
return List.of();
|
||||
}
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("settingId", "=", settingId)
|
||||
.and("delFlag", "=", false)
|
||||
.asc("startDate")
|
||||
.asc("createdAt");
|
||||
return dao().query(ThirtyTeachTourSettingTravelPeriod.class, cnd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ThirtyTeachTourSettingPeriodQuota> listPeriodQuotas(String settingId) {
|
||||
if (StrUtil.isBlank(settingId)) {
|
||||
return List.of();
|
||||
}
|
||||
Cnd cnd = Cnd.where("settingId", "=", settingId)
|
||||
.and("delFlag", "=", false);
|
||||
return dao().query(ThirtyTeachTourSettingPeriodQuota.class, cnd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveUnionQuotas(String settingId, String unionQuotas) {
|
||||
if (StrUtil.isBlank(settingId)) {
|
||||
@@ -90,6 +152,76 @@ public class ThirtyTeachTourSettingServiceImpl extends BaseServiceImpl<ThirtyTea
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> saveTravelPeriods(String settingId, String travelPeriods) {
|
||||
if (StrUtil.isBlank(settingId)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
dao().clear(ThirtyTeachTourSettingTravelPeriod.class,
|
||||
Cnd.where("settingId", "=", settingId));
|
||||
if (StrUtil.isBlank(travelPeriods)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
List<ThirtyTeachTourSettingTravelPeriod> periodList = Json.fromJsonAsList(ThirtyTeachTourSettingTravelPeriod.class, travelPeriods);
|
||||
if (Lang.isEmpty(periodList)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
List<ThirtyTeachTourSettingTravelPeriod> saveList = periodList.stream()
|
||||
.filter(item -> item != null
|
||||
&& StrUtil.isNotBlank(item.getId())
|
||||
&& StrUtil.isNotBlank(item.getPeriodName())
|
||||
&& StrUtil.isNotBlank(item.getStartDate())
|
||||
&& StrUtil.isNotBlank(item.getEndDate()))
|
||||
.peek(item -> {
|
||||
// 前端会为新增时间段生成临时ID,服务端保留该ID以便时间段名额能稳定关联。
|
||||
item.setSettingId(settingId);
|
||||
item.setEnabled(Boolean.TRUE.equals(item.getEnabled()));
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
if (Lang.isNotEmpty(saveList)) {
|
||||
dao().insert(saveList);
|
||||
}
|
||||
return saveList.stream()
|
||||
.filter(item -> Boolean.TRUE.equals(item.getEnabled()))
|
||||
.map(ThirtyTeachTourSettingTravelPeriod::getId)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void savePeriodQuotas(String settingId, String periodQuotas, Set<String> validPeriodIds) {
|
||||
if (StrUtil.isBlank(settingId)) {
|
||||
return;
|
||||
}
|
||||
dao().clear(ThirtyTeachTourSettingPeriodQuota.class,
|
||||
Cnd.where("settingId", "=", settingId));
|
||||
if (StrUtil.isBlank(periodQuotas)) {
|
||||
return;
|
||||
}
|
||||
List<ThirtyTeachTourSettingPeriodQuota> quotaList = Json.fromJsonAsList(ThirtyTeachTourSettingPeriodQuota.class, periodQuotas);
|
||||
if (Lang.isEmpty(quotaList)) {
|
||||
return;
|
||||
}
|
||||
Set<String> periodIds = Lang.isEmpty(validPeriodIds)
|
||||
? listTravelPeriods(settingId).stream()
|
||||
.filter(item -> Boolean.TRUE.equals(item.getEnabled()))
|
||||
.map(ThirtyTeachTourSettingTravelPeriod::getId)
|
||||
.collect(Collectors.toSet())
|
||||
: validPeriodIds;
|
||||
Map<String, Sys_union> unionMap = dao().query(Sys_union.class, Cnd.NEW()).stream()
|
||||
.collect(Collectors.toMap(Sys_union::getId, item -> item, (a, b) -> a));
|
||||
List<ThirtyTeachTourSettingPeriodQuota> saveList = quotaList.stream()
|
||||
.filter(item -> item != null
|
||||
&& StrUtil.isNotBlank(item.getUnionId())
|
||||
&& StrUtil.isNotBlank(item.getPeriodId())
|
||||
&& periodIds.contains(item.getPeriodId())
|
||||
&& defaultInt(item.getFormalQuota()) > 0)
|
||||
.map(item -> normalizePeriodQuota(settingId, item, unionMap))
|
||||
.collect(Collectors.toList());
|
||||
if (Lang.isNotEmpty(saveList)) {
|
||||
dao().insert(saveList);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String checkBranchFormalQuotaLimit(String unionQuotas, int branchTotalQuota) {
|
||||
if (StrUtil.isBlank(unionQuotas)) {
|
||||
@@ -109,6 +241,37 @@ public class ThirtyTeachTourSettingServiceImpl extends BaseServiceImpl<ThirtyTea
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String checkPeriodQuotaLimit(String periodQuotas, String unionQuotas) {
|
||||
if (StrUtil.isBlank(periodQuotas)) {
|
||||
return "";
|
||||
}
|
||||
List<ThirtyTeachTourSettingPeriodQuota> periodQuotaList = Json.fromJsonAsList(ThirtyTeachTourSettingPeriodQuota.class, periodQuotas);
|
||||
if (Lang.isEmpty(periodQuotaList)) {
|
||||
return "";
|
||||
}
|
||||
List<ThirtyTeachTourSettingUnionQuota> unionQuotaList = StrUtil.isBlank(unionQuotas)
|
||||
? List.of()
|
||||
: Json.fromJsonAsList(ThirtyTeachTourSettingUnionQuota.class, unionQuotas);
|
||||
Map<String, ThirtyTeachTourSettingUnionQuota> unionQuotaMap = unionQuotaList.stream()
|
||||
.filter(item -> item != null && StrUtil.isNotBlank(item.getUnionId()))
|
||||
.collect(Collectors.toMap(ThirtyTeachTourSettingUnionQuota::getUnionId, item -> item, (a, b) -> a));
|
||||
Map<String, Integer> periodQuotaTotalMap = periodQuotaList.stream()
|
||||
.filter(item -> item != null && StrUtil.isNotBlank(item.getUnionId()))
|
||||
.collect(Collectors.groupingBy(ThirtyTeachTourSettingPeriodQuota::getUnionId,
|
||||
Collectors.summingInt(item -> defaultInt(item.getFormalQuota()))));
|
||||
for (Map.Entry<String, Integer> entry : periodQuotaTotalMap.entrySet()) {
|
||||
ThirtyTeachTourSettingUnionQuota unionQuota = unionQuotaMap.get(entry.getKey());
|
||||
int formalQuota = unionQuota == null ? 0 : defaultInt(unionQuota.getFormalQuota());
|
||||
if (entry.getValue() > formalQuota) {
|
||||
String unionName = unionQuota == null ? "" : unionQuota.getUnionName();
|
||||
return "分工会【" + StrUtil.blankToDefault(unionName, entry.getKey()) + "】时间段名额合计 "
|
||||
+ entry.getValue() + ",不能大于当前分工会正式名额 " + formalQuota;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearUnionQuotas(String settingId) {
|
||||
if (StrUtil.isNotBlank(settingId)) {
|
||||
@@ -116,6 +279,15 @@ public class ThirtyTeachTourSettingServiceImpl extends BaseServiceImpl<ThirtyTea
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearTravelPeriodsAndQuotas(String settingId) {
|
||||
if (StrUtil.isBlank(settingId)) {
|
||||
return;
|
||||
}
|
||||
dao().clear(ThirtyTeachTourSettingPeriodQuota.class, Cnd.where("settingId", "=", settingId));
|
||||
dao().clear(ThirtyTeachTourSettingTravelPeriod.class, Cnd.where("settingId", "=", settingId));
|
||||
}
|
||||
|
||||
private ThirtyTeachTourSettingUnionQuota normalizeUnionQuota(String settingId, ThirtyTeachTourSettingUnionQuota item, Map<String, Sys_union> unionMap) {
|
||||
Sys_union union = unionMap.get(item.getUnionId());
|
||||
ThirtyTeachTourSettingUnionQuota quota = new ThirtyTeachTourSettingUnionQuota();
|
||||
@@ -127,6 +299,18 @@ public class ThirtyTeachTourSettingServiceImpl extends BaseServiceImpl<ThirtyTea
|
||||
return quota;
|
||||
}
|
||||
|
||||
private ThirtyTeachTourSettingPeriodQuota normalizePeriodQuota(String settingId, ThirtyTeachTourSettingPeriodQuota item, Map<String, Sys_union> unionMap) {
|
||||
Sys_union union = unionMap.get(item.getUnionId());
|
||||
ThirtyTeachTourSettingPeriodQuota quota = new ThirtyTeachTourSettingPeriodQuota();
|
||||
quota.setSettingId(settingId);
|
||||
quota.setUnionId(item.getUnionId());
|
||||
quota.setUnionName(union == null ? item.getUnionName() : union.getName());
|
||||
quota.setPeriodId(item.getPeriodId());
|
||||
quota.setPeriodName(item.getPeriodName());
|
||||
quota.setFormalQuota(defaultInt(item.getFormalQuota()));
|
||||
return quota;
|
||||
}
|
||||
|
||||
private Integer defaultInt(Integer value) {
|
||||
return value == null || value < 0 ? 0 : value;
|
||||
}
|
||||
|
||||
+348
-31
@@ -122,13 +122,14 @@ public class ThirtyTeachTourUserAssignmentServiceImpl extends BaseServiceImpl<Th
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pagination<NutMap> schoolCandidatePage(PageForm pageForm, String settingId, String unionId, String keyword, List<String> userIds) {
|
||||
public Pagination<NutMap> schoolCandidatePage(PageForm pageForm, String settingId, String unionId, String keyword, List<String> userIds,
|
||||
Boolean summerJoinedFilter, Boolean lastThirtyJoinedFilter) {
|
||||
ThirtyTeachTourSetting setting = fetchSettingForAssignment(settingId);
|
||||
if (setting == null || StrUtil.isBlank(setting.getActivityGroupId())) {
|
||||
return emptyPagination(pageForm);
|
||||
}
|
||||
Sql sql = buildCandidateSql(settingId);
|
||||
Cnd cnd = buildCandidateCnd(settingId, setting.getActivityGroupId(), unionId, keyword);
|
||||
Sql sql = buildCandidateSql(settingId, setting.getYear());
|
||||
Cnd cnd = buildCandidateCnd(setting.getActivityGroupId(), unionId, keyword, summerJoinedFilter, lastThirtyJoinedFilter);
|
||||
List<String> normalizedUserIds = normalizeUserIds(userIds);
|
||||
// 人员选择器多选查询时,候选范围仍受活动组、分工会、已分配排除规则约束,再按指定人员ID精确过滤。
|
||||
if (!Lang.isEmpty(normalizedUserIds)) {
|
||||
@@ -171,7 +172,7 @@ public class ThirtyTeachTourUserAssignmentServiceImpl extends BaseServiceImpl<Th
|
||||
if (StrUtil.isBlank(unionId)) {
|
||||
return emptyPagination(pageForm);
|
||||
}
|
||||
return schoolCandidatePage(pageForm, settingId, unionId, keyword, userIds);
|
||||
return schoolCandidatePage(pageForm, settingId, unionId, keyword, userIds, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -342,7 +343,7 @@ public class ThirtyTeachTourUserAssignmentServiceImpl extends BaseServiceImpl<Th
|
||||
}
|
||||
|
||||
@Override
|
||||
public NutMap assignSchoolUsers(String settingId, String matterId, String personType, List<String> userIds) {
|
||||
public NutMap assignSchoolUsers(String settingId, String matterId, String personType, List<String> userIds, String photoFiles) {
|
||||
List<String> distinctUserIds = normalizeUserIds(userIds);
|
||||
if (StrUtil.isBlank(settingId) || Lang.isEmpty(distinctUserIds)) {
|
||||
throw new IllegalArgumentException("请选择疗休养配置和分配人员");
|
||||
@@ -359,11 +360,12 @@ public class ThirtyTeachTourUserAssignmentServiceImpl extends BaseServiceImpl<Th
|
||||
}
|
||||
|
||||
// 保存前重新按“配置人员范围 + 未分配”查询,防止前端绕过候选列表提交范围外人员。
|
||||
Sql userSql = buildCandidateSql(settingId);
|
||||
Cnd userCnd = buildCandidateCnd(settingId, setting.getActivityGroupId(), null, null);
|
||||
Sql userSql = buildCandidateSql(settingId, setting.getYear());
|
||||
Cnd userCnd = buildCandidateCnd(setting.getActivityGroupId(), null, null, false, false);
|
||||
userCnd.and("u.id", "in", distinctUserIds);
|
||||
userSql.setCondition(userCnd);
|
||||
List<NutMap> candidateUsers = listMap(userSql);
|
||||
fillCandidatePhotoFiles(candidateUsers, normalizePhotoFiles(photoFiles));
|
||||
List<ThirtyTeachTourUserAssignment> assignments = candidateUsers.stream()
|
||||
.map(user -> buildSchoolAssignment(settingId, matterInfo, normalizedPersonType, user))
|
||||
.collect(Collectors.toList());
|
||||
@@ -392,6 +394,7 @@ public class ThirtyTeachTourUserAssignmentServiceImpl extends BaseServiceImpl<Th
|
||||
}
|
||||
|
||||
Map<String, String> matterByUserId = new HashMap<>();
|
||||
Map<String, String> photoFilesByUserId = new HashMap<>();
|
||||
List<String> userIds = assignItems.stream()
|
||||
.map(item -> item == null ? "" : item.getString("userId", ""))
|
||||
.filter(StrUtil::isNotBlank)
|
||||
@@ -406,6 +409,7 @@ public class ThirtyTeachTourUserAssignmentServiceImpl extends BaseServiceImpl<Th
|
||||
return;
|
||||
}
|
||||
matterByUserId.put(userId, item.getString("matterId", ""));
|
||||
photoFilesByUserId.put(userId, normalizePhotoFiles(item.getString("photoFiles")));
|
||||
});
|
||||
if (Lang.isEmpty(userIds)) {
|
||||
throw new IllegalArgumentException("请选择分配人员");
|
||||
@@ -424,11 +428,12 @@ public class ThirtyTeachTourUserAssignmentServiceImpl extends BaseServiceImpl<Th
|
||||
});
|
||||
|
||||
// 保存前重新按“配置人员范围 + 未分配”查询,防止前端绕过候选列表提交范围外人员。
|
||||
Sql userSql = buildCandidateSql(settingId);
|
||||
Cnd userCnd = buildCandidateCnd(settingId, setting.getActivityGroupId(), null, null);
|
||||
Sql userSql = buildCandidateSql(settingId, setting.getYear());
|
||||
Cnd userCnd = buildCandidateCnd(setting.getActivityGroupId(), null, null, false, false);
|
||||
userCnd.and("u.id", "in", userIds);
|
||||
userSql.setCondition(userCnd);
|
||||
List<NutMap> candidateUsers = listMap(userSql);
|
||||
candidateUsers.forEach(user -> user.put("photoFiles", photoFilesByUserId.get(user.getString("userId", ""))));
|
||||
|
||||
List<ThirtyTeachTourUserAssignment> assignments = candidateUsers.stream()
|
||||
.map(user -> {
|
||||
@@ -456,7 +461,7 @@ public class ThirtyTeachTourUserAssignmentServiceImpl extends BaseServiceImpl<Th
|
||||
}
|
||||
|
||||
@Override
|
||||
public NutMap selectSchoolAssignmentMatter(String id, String matterId) {
|
||||
public NutMap selectSchoolAssignmentMatter(String id, String matterId, String photoFiles) {
|
||||
if (StrUtil.isBlank(id) || StrUtil.isBlank(matterId)) {
|
||||
throw new IllegalArgumentException("请选择人员分配记录和分配线路");
|
||||
}
|
||||
@@ -477,13 +482,14 @@ public class ThirtyTeachTourUserAssignmentServiceImpl extends BaseServiceImpl<Th
|
||||
if (matterInfo == null) {
|
||||
throw new IllegalArgumentException("分配线路不存在或未配置线路");
|
||||
}
|
||||
updateAssignmentMatterSnapshot(id, matterInfo, ThirtyTeachTourUserAssignment.ASSIGN_SOURCE_SCHOOL_UNION);
|
||||
updateAssignmentMatterSnapshot(id, matterInfo, ThirtyTeachTourUserAssignment.ASSIGN_SOURCE_SCHOOL_UNION, photoFiles);
|
||||
assignment.setPhotoFiles(normalizePhotoFiles(photoFiles));
|
||||
int ledgerCount = insertProxySignupLedgers(matterInfo, Collections.singletonList(fetchAssignmentUserSnapshot(assignment)));
|
||||
return NutMap.NEW().addv("ledgerCount", ledgerCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NutMap selectCurrentBranchAssignmentMatter(String id, String matterId) {
|
||||
public NutMap selectCurrentBranchAssignmentMatter(String id, String matterId, String photoFiles) {
|
||||
if (StrUtil.isBlank(id) || StrUtil.isBlank(matterId)) {
|
||||
throw new IllegalArgumentException("请选择人员分配记录和分配路线");
|
||||
}
|
||||
@@ -505,23 +511,43 @@ public class ThirtyTeachTourUserAssignmentServiceImpl extends BaseServiceImpl<Th
|
||||
if (!isMatterSignupOpen(matterInfo)) {
|
||||
throw new IllegalArgumentException("当前线路不在报名时间内,不能选择");
|
||||
}
|
||||
assignment.setPhotoFiles(normalizePhotoFiles(photoFiles));
|
||||
List<NutMap> users = Collections.singletonList(fetchAssignmentUserSnapshot(assignment));
|
||||
checkProxySignupMaxGroupPeople(matterInfo, users);
|
||||
updateAssignmentMatterSnapshot(id, matterInfo, ThirtyTeachTourUserAssignment.ASSIGN_SOURCE_BRANCH_UNION);
|
||||
updateAssignmentMatterSnapshot(id, matterInfo, ThirtyTeachTourUserAssignment.ASSIGN_SOURCE_BRANCH_UNION, photoFiles);
|
||||
int ledgerCount = insertProxySignupLedgers(matterInfo, users);
|
||||
return NutMap.NEW().addv("ledgerCount", ledgerCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NutMap assignBranchUsers(String settingId, String matterId, String personType, List<String> userIds) {
|
||||
public NutMap assignBranchUsers(String settingId, String matterId, String periodId, String personType, List<NutMap> assignItems) {
|
||||
String unionId = SecurityUtil.getUnionId();
|
||||
if (StrUtil.isBlank(unionId)) {
|
||||
throw new IllegalArgumentException("当前登录人未绑定分工会");
|
||||
}
|
||||
List<String> distinctUserIds = normalizeUserIds(userIds);
|
||||
if (StrUtil.isBlank(settingId) || Lang.isEmpty(distinctUserIds)) {
|
||||
if (StrUtil.isBlank(settingId) || Lang.isEmpty(assignItems)) {
|
||||
throw new IllegalArgumentException("请选择疗休养配置和分配人员");
|
||||
}
|
||||
Map<String, String> photoFilesByUserId = new HashMap<>();
|
||||
List<String> distinctUserIds = assignItems.stream()
|
||||
.map(item -> item == null ? "" : item.getString("userId", ""))
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
assignItems.forEach(item -> {
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
String userId = item.getString("userId", "");
|
||||
if (StrUtil.isBlank(userId)) {
|
||||
return;
|
||||
}
|
||||
// 图片材料来自人员分配弹窗的行级暂存,按人员写入后续分配表和台账。
|
||||
photoFilesByUserId.put(userId, normalizePhotoFiles(item.getString("photoFiles")));
|
||||
});
|
||||
if (Lang.isEmpty(distinctUserIds)) {
|
||||
throw new IllegalArgumentException("请选择分配人员");
|
||||
}
|
||||
String normalizedPersonType = normalizePersonType(personType);
|
||||
NutMap matterInfo = prepareMatterInfoForAssignment(settingId, matterId, normalizedPersonType);
|
||||
// 分工会代报名占用事项最大成团人数;在同一事务中锁定事项行,避免多个分工会同时校验通过后并发写入导致超额。
|
||||
@@ -539,26 +565,47 @@ public class ThirtyTeachTourUserAssignmentServiceImpl extends BaseServiceImpl<Th
|
||||
throw new IllegalArgumentException("疗休养配置未设置可参加人员范围");
|
||||
}
|
||||
NutMap quotaInfo = branchQuotaInfo(settingId);
|
||||
NutMap periodInfo = NutMap.NEW();
|
||||
ThirtyTeachTourSettingTravelPeriod selectedPeriod = null;
|
||||
int remainingQuota = defaultInt(quotaInfo.getInt(remainingQuotaKey(normalizedPersonType)));
|
||||
if (ThirtyTeachTourUserAssignment.PERSON_TYPE_FORMAL.equals(normalizedPersonType)) {
|
||||
if (StrUtil.isBlank(periodId)) {
|
||||
throw new IllegalArgumentException("请选择出行时间");
|
||||
}
|
||||
selectedPeriod = fetchEnabledTravelPeriod(settingId, periodId);
|
||||
if (selectedPeriod == null) {
|
||||
throw new IllegalArgumentException("出行时间不存在或已禁用");
|
||||
}
|
||||
lockBranchPeriodQuota(settingId, periodId, unionId);
|
||||
// 正式人员按“当前分工会 + 已启用时间段”读取细分名额,避免继续占用配置页签中的分工会总正式名额。
|
||||
periodInfo = branchPeriodQuotaInfo(settingId, periodId);
|
||||
remainingQuota = defaultInt(periodInfo.getInt("formalRemaining"));
|
||||
}
|
||||
if (remainingQuota <= 0) {
|
||||
throw new IllegalArgumentException("当前分工会该人员类型暂无剩余名额");
|
||||
}
|
||||
|
||||
// 保存前重新按“配置人员范围 + 当前分工会 + 未分配”查询,防止前端提交范围外或其它分工会人员。
|
||||
Sql userSql = buildCandidateSql(settingId);
|
||||
Cnd userCnd = buildCandidateCnd(settingId, setting.getActivityGroupId(), unionId, null);
|
||||
Sql userSql = buildCandidateSql(settingId, setting.getYear());
|
||||
Cnd userCnd = buildCandidateCnd(setting.getActivityGroupId(), unionId, null, false, false);
|
||||
userCnd.and("u.id", "in", distinctUserIds);
|
||||
userSql.setCondition(userCnd);
|
||||
List<NutMap> candidateUsers = listMap(userSql);
|
||||
candidateUsers.forEach(user -> user.put("photoFiles", photoFilesByUserId.get(user.getString("userId", ""))));
|
||||
if (candidateUsers.size() > remainingQuota) {
|
||||
throw new IllegalArgumentException("选择人数超过当前分工会剩余名额");
|
||||
}
|
||||
// 分工会代报名会占用线路成团人数,人员分配和台账写入前先做后端兜底校验。
|
||||
checkProxySignupMaxGroupPeople(matterInfo, candidateUsers);
|
||||
final NutMap assignmentMatterInfo = matterInfo;
|
||||
final ThirtyTeachTourSettingTravelPeriod assignmentPeriod = selectedPeriod;
|
||||
List<ThirtyTeachTourUserAssignment> assignments = candidateUsers.stream()
|
||||
.map(user -> buildAssignment(settingId, assignmentMatterInfo, normalizedPersonType, user,
|
||||
ThirtyTeachTourUserAssignment.ASSIGN_SOURCE_BRANCH_UNION))
|
||||
.map(user -> {
|
||||
ThirtyTeachTourUserAssignment assignment = buildAssignment(settingId, assignmentMatterInfo, normalizedPersonType, user,
|
||||
ThirtyTeachTourUserAssignment.ASSIGN_SOURCE_BRANCH_UNION);
|
||||
fillTravelPeriodSnapshot(assignment, assignmentPeriod);
|
||||
return assignment;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
if (Lang.isNotEmpty(assignments)) {
|
||||
dao().insert(assignments);
|
||||
@@ -566,11 +613,14 @@ public class ThirtyTeachTourUserAssignmentServiceImpl extends BaseServiceImpl<Th
|
||||
// 事项为空时只写人员分配表;正式人员选择事项时按代报名写入台账。
|
||||
int ledgerCount = insertProxySignupLedgers(matterInfo, candidateUsers);
|
||||
NutMap newQuotaInfo = branchQuotaInfo(settingId);
|
||||
NutMap newPeriodQuotaInfo = ThirtyTeachTourUserAssignment.PERSON_TYPE_FORMAL.equals(normalizedPersonType)
|
||||
? branchPeriodQuotaInfo(settingId, periodId) : NutMap.NEW();
|
||||
return NutMap.NEW()
|
||||
.addv("assignCount", assignments.size())
|
||||
.addv("skipCount", distinctUserIds.size() - assignments.size())
|
||||
.addv("ledgerCount", ledgerCount)
|
||||
.addv("formalRemaining", defaultInt(newQuotaInfo.getInt("formalRemaining")))
|
||||
.addv("formalRemaining", ThirtyTeachTourUserAssignment.PERSON_TYPE_FORMAL.equals(normalizedPersonType)
|
||||
? defaultInt(newPeriodQuotaInfo.getInt("formalRemaining")) : defaultInt(newQuotaInfo.getInt("formalRemaining")))
|
||||
.addv("backupRemaining", defaultInt(newQuotaInfo.getInt("backupRemaining")));
|
||||
}
|
||||
|
||||
@@ -625,6 +675,79 @@ public class ThirtyTeachTourUserAssignmentServiceImpl extends BaseServiceImpl<Th
|
||||
.addv("backupRemaining", Math.max(backupQuota - backupUsed, 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<NutMap> listBranchEnabledTravelPeriods(String settingId) {
|
||||
if (StrUtil.isBlank(settingId)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<ThirtyTeachTourSettingTravelPeriod> periods = dao().query(ThirtyTeachTourSettingTravelPeriod.class,
|
||||
Cnd.where("settingId", "=", settingId)
|
||||
.and("enabled", "=", true)
|
||||
.and("delFlag", "=", false)
|
||||
.asc("startDate")
|
||||
.asc("createdAt"));
|
||||
return periods.stream()
|
||||
.map(period -> NutMap.NEW()
|
||||
.addv("id", period.getId())
|
||||
.addv("periodName", period.getPeriodName())
|
||||
.addv("startDate", period.getStartDate())
|
||||
.addv("endDate", period.getEndDate())
|
||||
.addv("label", travelPeriodButtonLabel(period)))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public NutMap branchPeriodQuotaInfo(String settingId, String periodId) {
|
||||
String unionId = SecurityUtil.getUnionId();
|
||||
if (StrUtil.isBlank(settingId) || StrUtil.isBlank(periodId) || StrUtil.isBlank(unionId)) {
|
||||
return emptyPeriodQuotaInfo(periodId);
|
||||
}
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
COALESCE(q.formalQuota, 0) AS formalQuota,
|
||||
COALESCE(used_quota.formalUsed, 0) AS formalUsed
|
||||
FROM thirty_teach_tour_setting_period_quota q
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
settingId,
|
||||
unionId,
|
||||
periodId,
|
||||
COUNT(1) AS formalUsed
|
||||
FROM thirty_teach_tour_user_assignment
|
||||
WHERE delFlag = 0
|
||||
AND assignSource = @assignSource
|
||||
AND personType = @formalType
|
||||
AND settingId = @settingId
|
||||
AND unionId = @unionId
|
||||
AND periodId = @periodId
|
||||
AND (cancelled = 0 OR cancelled IS NULL)
|
||||
GROUP BY settingId, unionId, periodId
|
||||
) used_quota ON used_quota.settingId = q.settingId
|
||||
AND used_quota.unionId = q.unionId
|
||||
AND used_quota.periodId = q.periodId
|
||||
WHERE q.settingId = @settingId
|
||||
AND q.unionId = @unionId
|
||||
AND q.periodId = @periodId
|
||||
AND q.delFlag = 0
|
||||
LIMIT 1
|
||||
""");
|
||||
sql.setParam("assignSource", ThirtyTeachTourUserAssignment.ASSIGN_SOURCE_BRANCH_UNION);
|
||||
sql.setParam("formalType", ThirtyTeachTourUserAssignment.PERSON_TYPE_FORMAL);
|
||||
sql.setParam("settingId", settingId);
|
||||
sql.setParam("unionId", unionId);
|
||||
sql.setParam("periodId", periodId);
|
||||
List<NutMap> rows = listMap(sql);
|
||||
NutMap quotaInfo = Lang.isEmpty(rows) ? emptyPeriodQuotaInfo(periodId) : rows.get(0);
|
||||
int formalQuota = defaultInt(quotaInfo.getInt("formalQuota"));
|
||||
int formalUsed = defaultInt(quotaInfo.getInt("formalUsed"));
|
||||
// NutMap.addv 对已存在的同名 key 会形成数组,这里直接构造最终返回值,避免前端显示 [0, 12]。
|
||||
return NutMap.NEW()
|
||||
.addv("periodId", periodId)
|
||||
.addv("formalQuota", formalQuota)
|
||||
.addv("formalUsed", formalUsed)
|
||||
.addv("formalRemaining", Math.max(formalQuota - formalUsed, 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public NutMap switchCurrentBranchPersonType(String id, String personType) {
|
||||
String unionId = SecurityUtil.getUnionId();
|
||||
@@ -651,6 +774,14 @@ public class ThirtyTeachTourUserAssignmentServiceImpl extends BaseServiceImpl<Th
|
||||
}
|
||||
NutMap quotaInfo = branchQuotaInfo(assignment.getSettingId());
|
||||
int remainingQuota = defaultInt(quotaInfo.getInt(remainingQuotaKey(targetPersonType)));
|
||||
if (ThirtyTeachTourUserAssignment.PERSON_TYPE_FORMAL.equals(targetPersonType)) {
|
||||
if (StrUtil.isBlank(assignment.getPeriodId())) {
|
||||
throw new IllegalArgumentException("当前人员未记录出行时间,不能直接转为正式人员");
|
||||
}
|
||||
// 转为正式人员会重新占用时间段名额,按人员原有时间段快照做后端兜底校验。
|
||||
NutMap periodQuotaInfo = branchPeriodQuotaInfo(assignment.getSettingId(), assignment.getPeriodId());
|
||||
remainingQuota = defaultInt(periodQuotaInfo.getInt("formalRemaining"));
|
||||
}
|
||||
if (remainingQuota <= 0) {
|
||||
throw new IllegalArgumentException("当前分工会目标人员类型暂无剩余名额");
|
||||
}
|
||||
@@ -743,6 +874,7 @@ public class ThirtyTeachTourUserAssignmentServiceImpl extends BaseServiceImpl<Th
|
||||
unionId,
|
||||
unionName,
|
||||
boardingPlace,
|
||||
photoFiles,
|
||||
personType,
|
||||
assignSource,
|
||||
IFNULL(cancelled, 0) AS cancelled
|
||||
@@ -762,7 +894,7 @@ public class ThirtyTeachTourUserAssignmentServiceImpl extends BaseServiceImpl<Th
|
||||
}
|
||||
|
||||
@Override
|
||||
public int backfillExistingAssignmentAfterSignup(String settingId, String matterId, String userId, String boardingPlace) {
|
||||
public int backfillExistingAssignmentAfterSignup(String settingId, String matterId, String userId, String boardingPlace, String photoFiles) {
|
||||
if (StrUtil.isBlank(settingId) || StrUtil.isBlank(matterId) || StrUtil.isBlank(userId)) {
|
||||
return 0;
|
||||
}
|
||||
@@ -777,7 +909,8 @@ public class ThirtyTeachTourUserAssignmentServiceImpl extends BaseServiceImpl<Th
|
||||
.add("lineName", matterInfo.getString("lineName"))
|
||||
.add("travelAgencyId", matterInfo.getString("travelAgencyId"))
|
||||
.add("travelAgencyName", matterInfo.getString("travelAgencyName"))
|
||||
.add("boardingPlace", StrUtil.blankToDefault(boardingPlace, matterInfo.getString("defaultBoardingPlace"))),
|
||||
.add("boardingPlace", StrUtil.blankToDefault(boardingPlace, matterInfo.getString("defaultBoardingPlace")))
|
||||
.add("photoFiles", normalizePhotoFiles(photoFiles)),
|
||||
Cnd.where(ThirtyTeachTourUserAssignment::getSettingId, "=", settingId)
|
||||
.and(ThirtyTeachTourUserAssignment::getUserId, "=", userId)
|
||||
.and(ThirtyTeachTourUserAssignment::getDelFlag, "=", false));
|
||||
@@ -834,6 +967,24 @@ public class ThirtyTeachTourUserAssignmentServiceImpl extends BaseServiceImpl<Th
|
||||
return assignmentDeleteInfo(fetchCurrentBranchAssignment(id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSchoolAssignmentPhotoFiles(String id, String photoFiles) {
|
||||
ThirtyTeachTourUserAssignment assignment = fetchAssignmentBySource(id, ThirtyTeachTourUserAssignment.ASSIGN_SOURCE_SCHOOL_UNION);
|
||||
if (assignment == null) {
|
||||
throw new IllegalArgumentException("人员分配记录不存在或无权限操作");
|
||||
}
|
||||
updateAssignmentPhotoFiles(assignment, photoFiles);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCurrentBranchAssignmentPhotoFiles(String id, String photoFiles) {
|
||||
ThirtyTeachTourUserAssignment assignment = fetchCurrentBranchAssignment(id);
|
||||
if (assignment == null) {
|
||||
throw new IllegalArgumentException("人员分配记录不存在或无权限操作");
|
||||
}
|
||||
updateAssignmentPhotoFiles(assignment, photoFiles);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteBySource(String id, String assignSource) {
|
||||
deleteBySource(id, assignSource, false);
|
||||
@@ -997,7 +1148,11 @@ public class ThirtyTeachTourUserAssignmentServiceImpl extends BaseServiceImpl<Th
|
||||
return listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
}
|
||||
|
||||
private Sql buildCandidateSql(String settingId) {
|
||||
/**
|
||||
* 构建人员分配候选人查询,额外带出今年暑期疗休养和去年30年教龄疗休养参加标记。
|
||||
*/
|
||||
private Sql buildCandidateSql(String settingId, Integer year) {
|
||||
int currentYear = year == null ? LocalDate.now().getYear() : year;
|
||||
return Sqls.create("""
|
||||
SELECT
|
||||
u.id AS userId,
|
||||
@@ -1011,23 +1166,49 @@ public class ThirtyTeachTourUserAssignmentServiceImpl extends BaseServiceImpl<Th
|
||||
u.unitid AS unitId,
|
||||
u.unitname AS unitName,
|
||||
u.unionid AS unionId,
|
||||
u.unionname AS unionName
|
||||
u.unionname AS unionName,
|
||||
CASE WHEN IFNULL(summer_joined.joinedCount, 0) > 0 THEN 1 ELSE 0 END AS summerJoined,
|
||||
CASE WHEN IFNULL(last_thirty_joined.joinedCount, 0) > 0 THEN 1 ELSE 0 END AS lastThirtyJoined
|
||||
FROM activity_user_scope aus
|
||||
LEFT JOIN vw_user u ON u.id = aus.userId
|
||||
LEFT JOIN thirty_teach_tour_user_assignment a
|
||||
ON a.settingId = @settingId
|
||||
AND a.userId = aus.userId
|
||||
AND a.delFlag = 0
|
||||
LEFT JOIN (
|
||||
SELECT jobNo, COUNT(1) AS joinedCount
|
||||
FROM tour_ledger
|
||||
WHERE delFlag = 0
|
||||
AND joined = 1
|
||||
AND `year` = @currentYear
|
||||
GROUP BY jobNo
|
||||
) summer_joined ON summer_joined.jobNo = u.loginname
|
||||
LEFT JOIN (
|
||||
SELECT jobNo, COUNT(1) AS joinedCount
|
||||
FROM thirty_teach_tour_ledger
|
||||
WHERE delFlag = 0
|
||||
AND joined = 1
|
||||
AND `year` = @lastThirtyYear
|
||||
GROUP BY jobNo
|
||||
) last_thirty_joined ON last_thirty_joined.jobNo = u.loginname
|
||||
$condition
|
||||
""").setParam("settingId", settingId);
|
||||
""").setParam("settingId", settingId)
|
||||
.setParam("currentYear", currentYear)
|
||||
.setParam("lastThirtyYear", currentYear - 1);
|
||||
}
|
||||
|
||||
private Cnd buildCandidateCnd(String settingId, String activityGroupId, String unionId, String keyword) {
|
||||
/**
|
||||
* 组装候选人过滤条件,参游记录过滤为null时表示不限制该条件。
|
||||
*/
|
||||
private Cnd buildCandidateCnd(String activityGroupId, String unionId, String keyword,
|
||||
Boolean summerJoinedFilter, Boolean lastThirtyJoinedFilter) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("aus.groupId", "=", activityGroupId);
|
||||
cnd.and("u.id", "is not", null);
|
||||
cnd.and("a.id", "is", null);
|
||||
cnd.andEX("u.unionid", "=", unionId);
|
||||
appendJoinedFilter(cnd, "summer_joined.joinedCount", summerJoinedFilter);
|
||||
appendJoinedFilter(cnd, "last_thirty_joined.joinedCount", lastThirtyJoinedFilter);
|
||||
if (StrUtil.isNotBlank(keyword)) {
|
||||
SqlExpressionGroup group = new SqlExpressionGroup();
|
||||
group.orLike("u.username", keyword);
|
||||
@@ -1037,6 +1218,16 @@ public class ThirtyTeachTourUserAssignmentServiceImpl extends BaseServiceImpl<Th
|
||||
return cnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* 按是否参加过对应疗休养活动追加过滤:true查已参加,false查未参加,null不追加条件。
|
||||
*/
|
||||
private void appendJoinedFilter(Cnd cnd, String countColumn, Boolean joinedFilter) {
|
||||
if (joinedFilter == null) {
|
||||
return;
|
||||
}
|
||||
cnd.and("IFNULL(" + countColumn + ", 0)", joinedFilter ? ">" : "=", 0);
|
||||
}
|
||||
|
||||
private NutMap assignmentDeleteInfo(ThirtyTeachTourUserAssignment assignment) {
|
||||
int ledgerCount = countAssignmentLedgers(assignment);
|
||||
return NutMap.NEW()
|
||||
@@ -1089,6 +1280,28 @@ public class ThirtyTeachTourUserAssignmentServiceImpl extends BaseServiceImpl<Th
|
||||
.and(ThirtyTeachTourLedger::getDelFlag, "=", false));
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新人员分配图片材料,并同步同一事项和工号下已生成的报名台账。
|
||||
* 未选择线路或尚未生成台账时,只更新人员分配表,保证主列表上传不会强制产生台账数据。
|
||||
*/
|
||||
private void updateAssignmentPhotoFiles(ThirtyTeachTourUserAssignment assignment, String photoFiles) {
|
||||
if (assignment == null || StrUtil.isBlank(assignment.getId())) {
|
||||
throw new IllegalArgumentException("人员分配记录不存在或无权限操作");
|
||||
}
|
||||
String normalizedPhotoFiles = normalizePhotoFiles(photoFiles);
|
||||
update(Chain.make("photoFiles", normalizedPhotoFiles),
|
||||
Cnd.where(ThirtyTeachTourUserAssignment::getId, "=", assignment.getId())
|
||||
.and(ThirtyTeachTourUserAssignment::getDelFlag, "=", false));
|
||||
if (StrUtil.isBlank(assignment.getMatterId()) || StrUtil.isBlank(assignment.getLoginName())) {
|
||||
return;
|
||||
}
|
||||
dao().update(ThirtyTeachTourLedger.class,
|
||||
Chain.make("photoFiles", normalizedPhotoFiles),
|
||||
Cnd.where(ThirtyTeachTourLedger::getMatterId, "=", assignment.getMatterId())
|
||||
.and(ThirtyTeachTourLedger::getJobNo, "=", assignment.getLoginName())
|
||||
.and(ThirtyTeachTourLedger::getDelFlag, "=", false));
|
||||
}
|
||||
|
||||
private void deleteAssignmentLedgers(ThirtyTeachTourUserAssignment assignment) {
|
||||
List<ThirtyTeachTourLedger> ledgers = dao().query(ThirtyTeachTourLedger.class, Cnd.where(ThirtyTeachTourLedger::getMatterId, "=", assignment.getMatterId())
|
||||
.and(ThirtyTeachTourLedger::getJobNo, "=", assignment.getLoginName())
|
||||
@@ -1145,6 +1358,11 @@ public class ThirtyTeachTourUserAssignmentServiceImpl extends BaseServiceImpl<Th
|
||||
String personType = normalizePersonType(assignment.getPersonType());
|
||||
NutMap quotaInfo = branchQuotaInfo(assignment.getSettingId());
|
||||
int remainingQuota = defaultInt(quotaInfo.getInt(remainingQuotaKey(personType)));
|
||||
if (ThirtyTeachTourUserAssignment.PERSON_TYPE_FORMAL.equals(personType) && StrUtil.isNotBlank(assignment.getPeriodId())) {
|
||||
// 恢复已退出正式人员时,同步按该人员原时间段重新占用细分名额。
|
||||
NutMap periodQuotaInfo = branchPeriodQuotaInfo(assignment.getSettingId(), assignment.getPeriodId());
|
||||
remainingQuota = defaultInt(periodQuotaInfo.getInt("formalRemaining"));
|
||||
}
|
||||
// 恢复已退出人员会重新占用当前人员类型名额,因此恢复前必须按正式/替补剩余名额校验。
|
||||
if (remainingQuota <= 0) {
|
||||
throw new IllegalArgumentException("当前分工会目标人员类型暂无剩余名额");
|
||||
@@ -1332,6 +1550,8 @@ public class ThirtyTeachTourUserAssignmentServiceImpl extends BaseServiceImpl<Th
|
||||
ThirtyTeachTourUserAssignment assignment = new ThirtyTeachTourUserAssignment();
|
||||
assignment.setSettingId(settingId);
|
||||
fillMatterSnapshot(assignment, matterInfo);
|
||||
// 图片材料来自人员分配/报名提交快照,不能放在事项快照方法中读取。
|
||||
assignment.setPhotoFiles(normalizePhotoFiles(user.getString("photoFiles")));
|
||||
assignment.setUserId(user.getString("userId"));
|
||||
assignment.setLoginName(user.getString("loginName"));
|
||||
assignment.setUserName(user.getString("userName"));
|
||||
@@ -1365,7 +1585,18 @@ public class ThirtyTeachTourUserAssignmentServiceImpl extends BaseServiceImpl<Th
|
||||
assignment.setBoardingPlace(matterInfo.getString("defaultBoardingPlace"));
|
||||
}
|
||||
|
||||
private void updateAssignmentMatterSnapshot(String id, NutMap matterInfo, String assignSource) {
|
||||
/**
|
||||
* 保存分工会正式人员时保留时间段快照,后续名额使用统计直接按人员分配表 periodId 汇总。
|
||||
*/
|
||||
private void fillTravelPeriodSnapshot(ThirtyTeachTourUserAssignment assignment, ThirtyTeachTourSettingTravelPeriod period) {
|
||||
if (period == null) {
|
||||
return;
|
||||
}
|
||||
assignment.setPeriodId(period.getId());
|
||||
assignment.setPeriodName(period.getPeriodName());
|
||||
}
|
||||
|
||||
private void updateAssignmentMatterSnapshot(String id, NutMap matterInfo, String assignSource, String photoFiles) {
|
||||
// 补选事项时同时回写人员分配表事项快照,后续列表筛选无需再跨表追溯事项信息。
|
||||
update(Chain.make("matterId", matterInfo.getString("matterId"))
|
||||
.add("matterName", matterInfo.getString("matterName"))
|
||||
@@ -1373,7 +1604,8 @@ public class ThirtyTeachTourUserAssignmentServiceImpl extends BaseServiceImpl<Th
|
||||
.add("lineName", matterInfo.getString("lineName"))
|
||||
.add("travelAgencyId", matterInfo.getString("travelAgencyId"))
|
||||
.add("travelAgencyName", matterInfo.getString("travelAgencyName"))
|
||||
.add("boardingPlace", matterInfo.getString("defaultBoardingPlace")),
|
||||
.add("boardingPlace", matterInfo.getString("defaultBoardingPlace"))
|
||||
.add("photoFiles", normalizePhotoFiles(photoFiles)),
|
||||
Cnd.where(ThirtyTeachTourUserAssignment::getId, "=", id)
|
||||
.and(ThirtyTeachTourUserAssignment::getAssignSource, "=", assignSource));
|
||||
}
|
||||
@@ -1484,7 +1716,9 @@ public class ThirtyTeachTourUserAssignmentServiceImpl extends BaseServiceImpl<Th
|
||||
sql.setCondition(cnd);
|
||||
List<NutMap> users = listMap(sql);
|
||||
if (Lang.isNotEmpty(users)) {
|
||||
return users.get(0);
|
||||
NutMap user = users.get(0);
|
||||
user.put("photoFiles", assignment.getPhotoFiles());
|
||||
return user;
|
||||
}
|
||||
// 视图中找不到人员时使用分配表快照兜底,保证补选事项不会因非关键字段缺失中断。
|
||||
return NutMap.NEW()
|
||||
@@ -1496,7 +1730,8 @@ public class ThirtyTeachTourUserAssignmentServiceImpl extends BaseServiceImpl<Th
|
||||
.addv("unitId", assignment.getUnitId())
|
||||
.addv("unitName", assignment.getUnitName())
|
||||
.addv("unionId", assignment.getUnionId())
|
||||
.addv("unionName", assignment.getUnionName());
|
||||
.addv("unionName", assignment.getUnionName())
|
||||
.addv("photoFiles", assignment.getPhotoFiles());
|
||||
}
|
||||
|
||||
private ThirtyTeachTourLedger buildProxySignupLedger(NutMap matterInfo, NutMap user) {
|
||||
@@ -1518,6 +1753,7 @@ public class ThirtyTeachTourUserAssignmentServiceImpl extends BaseServiceImpl<Th
|
||||
ledger.setTravelAgencyId(matterInfo.getString("travelAgencyId"));
|
||||
ledger.setTravelAgencyName(matterInfo.getString("travelAgencyName"));
|
||||
ledger.setBoardingPlace(matterInfo.getString("defaultBoardingPlace"));
|
||||
ledger.setPhotoFiles(normalizePhotoFiles(user.getString("photoFiles")));
|
||||
ledger.setHasFamily(false);
|
||||
ledger.setJoined(false);
|
||||
ledger.setReimbursed(false);
|
||||
@@ -1575,6 +1811,33 @@ public class ThirtyTeachTourUserAssignmentServiceImpl extends BaseServiceImpl<Th
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 清洗多图上传返回值,统一保存为逗号分隔路径,避免空白项和重复路径写入快照表。
|
||||
*/
|
||||
private String normalizePhotoFiles(String photoFiles) {
|
||||
if (StrUtil.isBlank(photoFiles)) {
|
||||
return "";
|
||||
}
|
||||
List<String> photos = StrUtil.splitTrim(photoFiles, ",");
|
||||
if (Lang.isEmpty(photos)) {
|
||||
return "";
|
||||
}
|
||||
return photos.stream()
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.distinct()
|
||||
.collect(Collectors.joining(","));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量人员共用同一组上传图片时,将图片路径写入候选人快照,后续构建分配表和台账时直接读取。
|
||||
*/
|
||||
private void fillCandidatePhotoFiles(List<NutMap> candidateUsers, String photoFiles) {
|
||||
if (Lang.isEmpty(candidateUsers)) {
|
||||
return;
|
||||
}
|
||||
candidateUsers.forEach(user -> user.put("photoFiles", photoFiles));
|
||||
}
|
||||
|
||||
private Pagination<NutMap> emptyPagination(PageForm pageForm) {
|
||||
int pageNumber = pageForm == null || pageForm.getPageNumber() == null ? 1 : pageForm.getPageNumber();
|
||||
int pageSize = pageForm == null || pageForm.getPageSize() == null ? 10 : pageForm.getPageSize();
|
||||
@@ -1591,6 +1854,60 @@ public class ThirtyTeachTourUserAssignmentServiceImpl extends BaseServiceImpl<Th
|
||||
.addv("backupRemaining", 0);
|
||||
}
|
||||
|
||||
private NutMap emptyPeriodQuotaInfo(String periodId) {
|
||||
return NutMap.NEW()
|
||||
.addv("periodId", periodId)
|
||||
.addv("formalQuota", 0)
|
||||
.addv("formalUsed", 0)
|
||||
.addv("formalRemaining", 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 正式分配只允许选择当前配置下已启用的时间段,避免前端传入历史或其它配置的时间段ID。
|
||||
*/
|
||||
private ThirtyTeachTourSettingTravelPeriod fetchEnabledTravelPeriod(String settingId, String periodId) {
|
||||
if (StrUtil.isBlank(settingId) || StrUtil.isBlank(periodId)) {
|
||||
return null;
|
||||
}
|
||||
return dao().fetch(ThirtyTeachTourSettingTravelPeriod.class,
|
||||
Cnd.where("id", "=", periodId)
|
||||
.and("settingId", "=", settingId)
|
||||
.and("enabled", "=", true)
|
||||
.and("delFlag", "=", false));
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存正式人员前锁定当前分工会当前时间段的名额行,使名额校验和人员插入在同一事务内串行执行。
|
||||
*/
|
||||
private void lockBranchPeriodQuota(String settingId, String periodId, String unionId) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT id
|
||||
FROM thirty_teach_tour_setting_period_quota
|
||||
WHERE settingId = @settingId
|
||||
AND periodId = @periodId
|
||||
AND unionId = @unionId
|
||||
AND delFlag = 0
|
||||
FOR UPDATE
|
||||
""");
|
||||
sql.setParam("settingId", settingId);
|
||||
sql.setParam("periodId", periodId);
|
||||
sql.setParam("unionId", unionId);
|
||||
List<NutMap> rows = listMap(sql);
|
||||
if (Lang.isEmpty(rows)) {
|
||||
throw new IllegalArgumentException("当前分工会未配置该出行时间名额");
|
||||
}
|
||||
}
|
||||
|
||||
private String travelPeriodButtonLabel(ThirtyTeachTourSettingTravelPeriod period) {
|
||||
if (period == null) {
|
||||
return "";
|
||||
}
|
||||
if (StrUtil.isNotBlank(period.getStartDate()) && StrUtil.isNotBlank(period.getEndDate())) {
|
||||
return period.getStartDate().replace("-", "") + "-" + period.getEndDate().replace("-", "");
|
||||
}
|
||||
return StrUtil.blankToDefault(period.getPeriodName(), "");
|
||||
}
|
||||
|
||||
private String remainingQuotaKey(String personType) {
|
||||
return ThirtyTeachTourUserAssignment.PERSON_TYPE_BACKUP.equals(personType) ? "backupRemaining" : "formalRemaining";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user