diff --git a/src/main/java/io/v/nutz/zhgh/therapyRecuperation/controller/baseManage/TheRapyRecuperationBaseManagerController.java b/src/main/java/io/v/nutz/zhgh/therapyRecuperation/controller/baseManage/TheRapyRecuperationBaseManagerController.java index 07a163d..4b5c735 100644 --- a/src/main/java/io/v/nutz/zhgh/therapyRecuperation/controller/baseManage/TheRapyRecuperationBaseManagerController.java +++ b/src/main/java/io/v/nutz/zhgh/therapyRecuperation/controller/baseManage/TheRapyRecuperationBaseManagerController.java @@ -1,12 +1,8 @@ package io.v.nutz.zhgh.therapyRecuperation.controller.baseManage; import cn.afterturn.easypoi.excel.ExcelExportUtil; -import cn.afterturn.easypoi.excel.ExcelImportUtil; -import cn.afterturn.easypoi.excel.annotation.Excel; import cn.afterturn.easypoi.excel.entity.ExportParams; -import cn.afterturn.easypoi.excel.entity.ImportParams; import cn.afterturn.easypoi.excel.entity.enmus.ExcelType; -import cn.hutool.core.date.DateField; import cn.hutool.core.date.DateUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.core.lang.Assert; @@ -22,6 +18,7 @@ import io.v.nutz.sys.models.SysHoliday; import io.v.nutz.sys.models.User; import io.v.nutz.web.commons.utils.ShiroUtil; import io.v.nutz.zhgh.therapyRecuperation.constant.TheRapyRecuperationState; +import io.v.nutz.zhgh.therapyRecuperation.mode.TheRapyBaseManagementExcelMode; import io.v.nutz.zhgh.therapyRecuperation.model.*; import io.v.nutz.zhgh.therapyRecuperation.service.TheRapyRecuperationConfigService; import io.v.nutz.zhgh.therapyRecuperation.service.TheRapyRecuperationEnrollService; @@ -48,9 +45,6 @@ import org.nutz.mvc.upload.UploadAdaptor; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Proxy; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.*; @@ -454,7 +448,7 @@ public class TheRapyRecuperationBaseManagerController { /** - * 目的地导入模版 + * 目的地导入模板 * * @param response */ @@ -463,45 +457,10 @@ public class TheRapyRecuperationBaseManagerController { @RequiresPermissions("theRapyRecuperation.TheBaseManagement") public void exportTemplate(HttpServletResponse response) { try { - //查旅行社,转数组 - List travelAgencys = dao.query(TheRapyRecuperationTravelAgency.class, Cnd.NEW().desc("serialNumber")); - List excelTravelAgencyList = travelAgencys.stream().map(v -> v.getTravelAgencyName() + "_" + v.getId()).collect(Collectors.toList()); - String[] excelTravelAgencyArrs = excelTravelAgencyList.toArray(new String[excelTravelAgencyList.size()]); - - //查标段,转数组 - List lots = dao.query(TheRapyRecuperationLot.class, Cnd.NEW().asc("id")); - List excelLotList = lots.stream().map(v -> v.getLotName() + "_" + v.getId()).collect(Collectors.toList()); - String[] excelLotArrs = excelLotList.toArray(new String[excelLotList.size()]); - - ViTool.excelResponse(response, "目的地导入模版.xls"); - Class excelModeClass = TheRapyRecuperationBaseManagement.class; - Field[] excelModeClassDeclaredFields = excelModeClass.getDeclaredFields(); - //字段过滤 - List needAddReplaceFields = Arrays.stream(excelModeClassDeclaredFields).filter(v -> List.of("travelAgencyId", "lotId", "regionalNature", "isDisabled", "createMode").contains(v.getName())).collect(Collectors.toList()); - for (Field field : needAddReplaceFields) { - Excel excelAnnotation = field.getAnnotation(Excel.class); - if (Lang.isNotEmpty(excelAnnotation)) { - InvocationHandler invocationHandler = Proxy.getInvocationHandler(excelAnnotation); - Field memberValues = invocationHandler.getClass().getDeclaredField("memberValues"); - memberValues.setAccessible(true); - Map e = (Map) memberValues.get(invocationHandler); - e.put("addressList", true); - if (field.getName().equals("travelAgencyId")) { - e.put("replace", excelTravelAgencyArrs); - } else if (field.getName().equals("lotId")) { - e.put("replace", excelLotArrs); - } else if (field.getName().equals("regionalNature")) { - e.put("replace", new String[]{"省内_省内", "省外_省外"}); - } else if (field.getName().equals("createMode")) { - e.put("replace", new String[]{"校工会_1", "分工会_2"}); - } else if (field.getName().equals("isDisabled")) { - e.put("replace", new String[]{"是_1", "否_0"}); - } - } - } + ViTool.excelResponse(response, "目的地导入模板.xlsx"); ExportParams exportParams = new ExportParams(); exportParams.setType(ExcelType.XSSF); - Workbook sheets = ExcelExportUtil.exportExcel(exportParams, TheRapyRecuperationBaseManagement.class, new ArrayList<>()); + Workbook sheets = ExcelExportUtil.exportExcel(exportParams, TheRapyBaseManagementExcelMode.class, buildBaseTemplateExamples()); ServletOutputStream outputStream = response.getOutputStream(); sheets.write(outputStream); outputStream.close(); @@ -510,6 +469,23 @@ public class TheRapyRecuperationBaseManagerController { } } + private List buildBaseTemplateExamples() { + TheRapyBaseManagementExcelMode example = new TheRapyBaseManagementExcelMode(); + example.setYear(DateUtil.thisYear()); + example.setBaseName(TheRapyBaseManagementExcelMode.SAMPLE_BASE_NAME); + example.setTravelAgencySerialNumber("001"); + example.setTravelAgencyPlace("杭州"); + example.setRegionalNature("省内"); + example.setAllowDay("3,2,2.5"); + example.setMaxSignCount(30); + example.setBaseContactPerson("联系人"); + example.setBaseContactNumber("13800000000"); + example.setContent("目的地详细信息"); + List examples = new ArrayList<>(); + examples.add(example); + return examples; + } + /** * 目的地导入 @@ -530,30 +506,9 @@ public class TheRapyRecuperationBaseManagerController { if (!List.of("xls", "xlsx").contains(extName.toLowerCase())) { return Result.error("请上传xls,xlsx文件"); } - List excelList; - try { - ImportParams importParams = new ImportParams(); - excelList = ExcelImportUtil.importExcel(file.getFile(), TheRapyRecuperationBaseManagement.class, importParams); - } catch (Exception e) { - e.printStackTrace(); - return Result.error("读取不到数据,请检查excel文件格式"); - } - if (Lang.isEmpty(excelList)) { - return Result.error("读取不到数据,请检查excel文件格式"); - } - try { - if (excelList.stream().anyMatch(v -> StrUtil.isBlank(v.getBaseName())) || excelList.stream().anyMatch(v -> StrUtil.isBlank(v.getTravelAgencyId()))) { - return Result.error("目的地名称和旅行社名称不能为空"); - } - if (excelList.stream().anyMatch(v -> StrUtil.isBlank(v.getLotId())) || excelList.stream().anyMatch(v -> StrUtil.isBlank(v.getRegionalNature()))) { - return Result.error("时间标段和活动范围不能为空"); - } - excelList.forEach(v -> v.setOpBy((String) ShiroUtil.getPrincipalProperty("id"))); - dao.insertOrUpdate(excelList); - } catch (Exception e) { - e.printStackTrace(); - } - return null; + return theRapyRecuperationBaseManagerService.importBaseManager(file.getFile(), + (String) ShiroUtil.getPrincipalProperty("id"), + (String) ShiroUtil.getPrincipalProperty("unionid")); } @At diff --git a/src/main/java/io/v/nutz/zhgh/therapyRecuperation/controller/basicManage/TheRapyRecuperationLineController.java b/src/main/java/io/v/nutz/zhgh/therapyRecuperation/controller/basicManage/TheRapyRecuperationLineController.java index 849c441..8011ded 100644 --- a/src/main/java/io/v/nutz/zhgh/therapyRecuperation/controller/basicManage/TheRapyRecuperationLineController.java +++ b/src/main/java/io/v/nutz/zhgh/therapyRecuperation/controller/basicManage/TheRapyRecuperationLineController.java @@ -1,28 +1,25 @@ package io.v.nutz.zhgh.therapyRecuperation.controller.basicManage; import cn.afterturn.easypoi.excel.ExcelExportUtil; -import cn.afterturn.easypoi.excel.ExcelImportUtil; -import cn.afterturn.easypoi.excel.annotation.Excel; import cn.afterturn.easypoi.excel.entity.ExportParams; -import cn.afterturn.easypoi.excel.entity.ImportParams; +import cn.afterturn.easypoi.excel.entity.enmus.ExcelType; +import cn.hutool.core.date.DateUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import cn.wizzer.framework.base.Result; import io.v.nutz.base.annontation.ViReturn; import io.v.nutz.base.model.Audit; -import io.v.nutz.base.utils.Vi; import io.v.nutz.base.query.PageForm; -import io.v.nutz.sys.models.User; +import io.v.nutz.base.utils.Vi; +import io.v.nutz.base.utils.ViTool; import io.v.nutz.web.commons.utils.ShiroUtil; import io.v.nutz.zhgh.therapyRecuperation.constant.TheRapyRecuperationLineCreateMode; -import io.v.nutz.zhgh.therapyRecuperation.mode.TheRapyTravelLineExcelMode; -import io.v.nutz.zhgh.therapyRecuperation.model.TheRapyRecuperationEnroll; +import io.v.nutz.zhgh.therapyRecuperation.mode.TheRapyLineImportExcelMode; import io.v.nutz.zhgh.therapyRecuperation.model.TheRapyRecuperationLine; import io.v.nutz.zhgh.therapyRecuperation.model.TheRapyRecuperationLot; import io.v.nutz.zhgh.therapyRecuperation.model.TheRapyRecuperationTravelAgency; import io.v.nutz.zhgh.therapyRecuperation.service.TheRapyRecuperationLineService; -import io.v.nutz.base.utils.ViTool; import lombok.extern.slf4j.Slf4j; import org.apache.poi.ss.usermodel.Workbook; import org.apache.shiro.authz.annotation.Logical; @@ -45,12 +42,7 @@ import org.nutz.mvc.upload.UploadAdaptor; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; -import java.io.File; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Proxy; import java.util.*; -import java.util.stream.Collectors; /** * @FileName io.v.nutz.zhgh.therapyRecuperation.controller.basicManage.TheRapyRecuperationLineController @@ -318,56 +310,12 @@ public class TheRapyRecuperationLineController { if (!List.of("xls", "xlsx").contains(extName.toLowerCase())) { return Result.error("请上传xls,xlsx文件"); } - List excelList; - try { - ImportParams importParams = new ImportParams(); - excelList = ExcelImportUtil.importExcel(file.getFile(), TheRapyTravelLineExcelMode.class, importParams); - } catch (Exception e) { - log.error(e.getMessage()); - return Result.error("读取不到数据,请检查excel文件格式"); - } - if (Lang.isEmpty(excelList)) { - return Result.error("读取不到数据,请检查excel文件格式"); - } - try { - if (excelList.stream().anyMatch(v -> StrUtil.isBlank(v.getTravelAgencyId()))) { - return Result.error("旅行社名称不能为空"); - } - if (excelList.stream().anyMatch(v -> StrUtil.isBlank(v.getLotId())) || excelList.stream().anyMatch(v -> StrUtil.isBlank(v.getRegionalNature()))) { - return Result.error("时间标段和活动范围不能为空"); - } - List list = new ArrayList<>(); - for (TheRapyTravelLineExcelMode mode : excelList) { - TheRapyRecuperationLine line = new TheRapyRecuperationLine(); - line.setYear(mode.getYear()); - line.setSerialNumber(mode.getSerialNumber()); - line.setLineName(mode.getLineName()); - line.setTravelAgencyId(mode.getTravelAgencyId()); - line.setRegionalNature(mode.getRegionalNature()); - line.setContent(mode.getContent()); - line.setMinimumGroupSize(mode.getMinimumGroupSize()); - if (mode.getIsDisabled().equals("是")) { - line.setDisabled(false); - } else if (mode.getIsDisabled().equals("否")) { - line.setDisabled(true); - } - line.setEstimatedCost(mode.getEstimatedCost()); - line.setLotId(mode.getLotId()); -// line.setLineContact(mode.getLineContact()); -// line.setLineContactPhone(mode.getLineContactPhone()); - list.add(line); - } - dao.insert(list); - } catch (Exception e) { - log.error(e.getMessage()); - return Result.error("导入失败"); - } - return null; + return lineService.importTravelLine(file.getFile()); } /** - * 线路导入模版 + * 线路导入模板 * * @param response */ @@ -376,42 +324,10 @@ public class TheRapyRecuperationLineController { @RequiresPermissions("theRapyRecuperation.line") public void exportTemplate(HttpServletResponse response) { try { - //查旅行社,转数组 - List travelAgencys = dao.query(TheRapyRecuperationTravelAgency.class, Cnd.NEW().desc("serialNumber")); - List excelTravelAgencys = travelAgencys.stream().map(v -> v.getTravelAgencyName() + "_" + v.getId()).collect(Collectors.toList()); - String[] excelTravelAgencyArrs = excelTravelAgencys.toArray(new String[excelTravelAgencys.size()]); - - //查标段,转数组 - List lots = dao.query(TheRapyRecuperationLot.class, Cnd.NEW().asc("id")); - List excelLots = lots.stream().map(v -> v.getLotName() + "_" + v.getId()).collect(Collectors.toList()); - String[] excelLotArrs = excelLots.toArray(new String[excelLots.size()]); - - ViTool.excelResponse(response, "线路导入模版.xls"); - Class excelModeClass = TheRapyTravelLineExcelMode.class; - Field[] excelModeClassDeclaredFields = excelModeClass.getDeclaredFields(); - - //字段过滤 - List needAddReplaceFields = Arrays.stream(excelModeClassDeclaredFields).filter(v -> List.of("travelAgencyId", "lotId", "regionalNature").contains(v.getName())).collect(Collectors.toList()); - - //循环TheRapyTravelLineExcelMode需要下拉数据的字段 - for (Field field : needAddReplaceFields) { - Excel excelAnnotation = field.getAnnotation(Excel.class); - if (Lang.isNotEmpty(excelAnnotation)) { - InvocationHandler invocationHandler = Proxy.getInvocationHandler(excelAnnotation); - Field memberValues = invocationHandler.getClass().getDeclaredField("memberValues"); - memberValues.setAccessible(true); - Map e = (Map) memberValues.get(invocationHandler); - e.put("addressList", true); - if (field.getName().equals("travelAgencyId")) { - e.put("replace", excelTravelAgencyArrs); - } else if (field.getName().equals("lotId")) { - e.put("replace", excelLotArrs); - } else if (field.getName().equals("regionalNature")) { - e.put("replace", new String[]{"省内_省内", "省外_省外"}); - } - } - } - Workbook sheets = ExcelExportUtil.exportExcel(new ExportParams(), TheRapyTravelLineExcelMode.class, new ArrayList<>()); + ViTool.excelResponse(response, "线路导入模板.xlsx"); + ExportParams exportParams = new ExportParams(); + exportParams.setType(ExcelType.XSSF); + Workbook sheets = ExcelExportUtil.exportExcel(exportParams, TheRapyLineImportExcelMode.class, buildLineTemplateExamples()); ServletOutputStream outputStream = response.getOutputStream(); sheets.write(outputStream); outputStream.close(); @@ -419,4 +335,21 @@ public class TheRapyRecuperationLineController { log.error(e.getMessage()); } } + + private List buildLineTemplateExamples() { + TheRapyLineImportExcelMode example = new TheRapyLineImportExcelMode(); + example.setYear(DateUtil.thisYear()); + example.setLineName(TheRapyLineImportExcelMode.SAMPLE_LINE_NAME); + example.setTravelAgencySerialNumber("001"); + example.setTravelAgencyPlace("杭州"); + example.setRegionalNature("省内线路"); + example.setGroupType("常规团"); + example.setLotName("两天一晚"); + example.setEstimatedCost("1000"); + example.setMaxGroupSize(30); + example.setContent("线路内容"); + List examples = new ArrayList<>(); + examples.add(example); + return examples; + } } diff --git a/src/main/java/io/v/nutz/zhgh/therapyRecuperation/mode/TheRapyBaseManagementExcelMode.java b/src/main/java/io/v/nutz/zhgh/therapyRecuperation/mode/TheRapyBaseManagementExcelMode.java new file mode 100644 index 0000000..fff37cf --- /dev/null +++ b/src/main/java/io/v/nutz/zhgh/therapyRecuperation/mode/TheRapyBaseManagementExcelMode.java @@ -0,0 +1,43 @@ +package io.v.nutz.zhgh.therapyRecuperation.mode; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +/** + * 目的地导入模板字段,独立于数据库实体,避免模板导出时带出无关字段。 + */ +@Data +public class TheRapyBaseManagementExcelMode { + + public static final String SAMPLE_BASE_NAME = "示例目的地(请删除)"; + + @Excel(name = "年度") + private Integer year; + + @Excel(name = "目的地名称") + private String baseName; + + @Excel(name = "旅行社编号") + private String travelAgencySerialNumber; + + @Excel(name = "旅行社地点") + private String travelAgencyPlace; + + @Excel(name = "活动范围(省内/省外)") + private String regionalNature; + + @Excel(name = "天数(填3,2,2.5)") + private String allowDay; + + @Excel(name = "每日最高人数") + private Integer maxSignCount; + + @Excel(name = "目的地联系人") + private String baseContactPerson; + + @Excel(name = "联系电话") + private String baseContactNumber; + + @Excel(name = "详细信息", width = 30d) + private String content; +} diff --git a/src/main/java/io/v/nutz/zhgh/therapyRecuperation/mode/TheRapyLineImportExcelMode.java b/src/main/java/io/v/nutz/zhgh/therapyRecuperation/mode/TheRapyLineImportExcelMode.java new file mode 100644 index 0000000..ff8698d --- /dev/null +++ b/src/main/java/io/v/nutz/zhgh/therapyRecuperation/mode/TheRapyLineImportExcelMode.java @@ -0,0 +1,43 @@ +package io.v.nutz.zhgh.therapyRecuperation.mode; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +/** + * 线路导入模板字段,独立于数据库实体,避免模板导出时带出旅行社、标段等内部ID。 + */ +@Data +public class TheRapyLineImportExcelMode { + + public static final String SAMPLE_LINE_NAME = "示例线路(请删除)"; + + @Excel(name = "年度") + private Integer year; + + @Excel(name = "线路名称") + private String lineName; + + @Excel(name = "旅行社编号") + private String travelAgencySerialNumber; + + @Excel(name = "旅行社地点") + private String travelAgencyPlace; + + @Excel(name = "线路类型(省内线路/省外线路)") + private String regionalNature; + + @Excel(name = "成团类型(常规团/精品团)") + private String groupType; + + @Excel(name = "时间标段") + private String lotName; + + @Excel(name = "预计费用") + private String estimatedCost; + + @Excel(name = "最多报名人数") + private Integer maxGroupSize; + + @Excel(name = "线路内容", width = 30d) + private String content; +} diff --git a/src/main/java/io/v/nutz/zhgh/therapyRecuperation/service/TheRapyRecuperationLineService.java b/src/main/java/io/v/nutz/zhgh/therapyRecuperation/service/TheRapyRecuperationLineService.java index 7cf62ee..c005735 100644 --- a/src/main/java/io/v/nutz/zhgh/therapyRecuperation/service/TheRapyRecuperationLineService.java +++ b/src/main/java/io/v/nutz/zhgh/therapyRecuperation/service/TheRapyRecuperationLineService.java @@ -1,5 +1,6 @@ package io.v.nutz.zhgh.therapyRecuperation.service; +import cn.wizzer.framework.base.Result; import cn.wizzer.framework.page.Pagination; import io.v.nutz.base.query.PageForm; import io.v.nutz.base.service.ViService; @@ -7,6 +8,7 @@ import io.v.nutz.zhgh.therapyRecuperation.model.TheRapyRecuperationLine; import org.nutz.dao.Cnd; import org.nutz.lang.util.NutMap; +import java.io.File; import java.util.List; /** @@ -102,4 +104,12 @@ public interface TheRapyRecuperationLineService extends ViService v, (oldValue, newValue) -> oldValue)); - Map existEnrollMap = dao().query(TheRapyRecuperationEnroll.class, Cnd.where("loginName", "in", loginNames) + Map> existEnrollMap = dao().query(TheRapyRecuperationEnroll.class, Cnd.where("loginName", "in", loginNames) .and("YEAR(signingUptime)", "in", importYears)) .stream() - .collect(Collectors.toMap(v -> v.getLoginName() + "_" + DateUtil.year(v.getSigningUptime()), v -> v, (oldValue, newValue) -> oldValue)); + .collect(Collectors.groupingBy(v -> v.getLoginName() + "_" + DateUtil.year(v.getSigningUptime()))); TheRapyRecuperationConfig lineConfig = configService.requireByYear(lineInfo.getYear()); // 补录标段必须限定在所选线路年度配置内,避免不同年度同名标段匹配错。 Map lotMap = dao().query(TheRapyRecuperationLot.class, Cnd.where("configId", "=", lineConfig.getId())) @@ -1428,30 +1428,42 @@ public class TheRapyRecuperationEnrollServiceImpl extends ViServiceImpl v, (oldValue, newValue) -> oldValue)); List supplementList = new ArrayList<>(); - List existInfos = new ArrayList<>(); - List errorInfos = new ArrayList<>(); + List successList = new ArrayList<>(); + List errorList = new ArrayList<>(); Set supplementKeys = new HashSet<>(); - for (TheRapyRecuperationEnrollExcelMode excel : excelList) { + for (int i = 0; i < excelList.size(); i++) { + TheRapyRecuperationEnrollExcelMode excel = excelList.get(i); String loginName = StrUtil.trim(excel.getLoginName()); int takePartInYear = DateUtil.year(excel.getTakePartInTime()); String enrollKey = loginName + "_" + takePartInYear; - if (existEnrollMap.containsKey(enrollKey) || supplementKeys.contains(enrollKey)) { - existInfos.add(loginName); + NutMap row = createSupplementImportRow(i + 2, excel, takePartInYear); + List existEnrollList = existEnrollMap.getOrDefault(enrollKey, Collections.emptyList()); + if (Lang.isNotEmpty(existEnrollList)) { + row.setv("errors", buildSupplementExistReason(existEnrollList, lineUnionSelect)); + errorList.add(row); + continue; + } + if (supplementKeys.contains(enrollKey)) { + row.setv("errors", "Excel中同一工号同一参加年度重复,请保留一条后重新导入"); + errorList.add(row); continue; } User user = userMap.get(loginName); if (user == null) { - errorInfos.add("工号" + loginName + "的系统用户不存在"); + row.setv("errors", "系统用户不存在"); + errorList.add(row); continue; } TheRapyRecuperationLot lot = lotMap.get(excel.getLotId()); if (lot == null) { - errorInfos.add("工号" + loginName + "的标段时间不存在"); + row.setv("errors", "标段时间不存在,当前年度没有【" + excel.getLotId() + "】"); + errorList.add(row); continue; } if (StrUtil.isNotBlank(lineInfo.getLotId()) && !lineInfo.getLotId().equals(lot.getId())) { - errorInfos.add("工号" + loginName + "的标段时间与所选线路不一致"); + row.setv("errors", "标段时间与所选线路不一致,所选线路标段为【" + getLineLotName(lineInfo) + "】"); + errorList.add(row); continue; } @@ -1478,19 +1490,86 @@ public class TheRapyRecuperationEnrollServiceImpl extends ViServiceImpl existEnrollList, TheRapyRecuperationLineUnionSelect targetLineUnionSelect) { + List reasons = new ArrayList<>(); + for (TheRapyRecuperationEnroll existEnroll : existEnrollList) { + reasons.add(buildSingleSupplementExistReason(existEnroll, targetLineUnionSelect)); } - String msg = "补录成功" + supplementList.size() + "人,已存在" + existInfos.size() + "人"; - if (Lang.isNotEmpty(errorInfos)) { - msg += ",失败" + errorInfos.size() + "人:" + String.join(";", errorInfos); + return reasons.stream().distinct().collect(Collectors.joining(";")); + } + + private String buildSingleSupplementExistReason(TheRapyRecuperationEnroll existEnroll, TheRapyRecuperationLineUnionSelect targetLineUnionSelect) { + if (StrUtil.isNotBlank(existEnroll.getTakePartInLineId())) { + TheRapyRecuperationLineUnionSelect existLineUnionSelect = dao().fetch(TheRapyRecuperationLineUnionSelect.class, existEnroll.getTakePartInLineId()); + TheRapyRecuperationLine existLine = existLineUnionSelect == null ? null : dao().fetch(TheRapyRecuperationLine.class, existLineUnionSelect.getLineId()); + String lineName = existLine == null ? "未知线路" : existLine.getLineName(); + String regionalNature = existLine == null ? "未知区域" : existLine.getRegionalNature(); + String unionName = existLineUnionSelect == null ? "未知分工会" : getUnionName(existLineUnionSelect.getUnionId()); + if (targetLineUnionSelect != null && existEnroll.getTakePartInLineId().equals(targetLineUnionSelect.getId())) { + return "该年度已存在本线路报名记录,线路【" + lineName + "】"; + } + return "该年度已存在其他线路报名记录,线路【" + lineName + "】,区域【" + regionalNature + "】,线路分工会【" + unionName + "】"; } - return Result.success(msg); + if (StrUtil.isNotBlank(existEnroll.getTakePartInBaseManagementId())) { + TheRapyRecuperationBaseManagement baseManagement = dao().fetch(TheRapyRecuperationBaseManagement.class, existEnroll.getTakePartInBaseManagementId()); + String baseName = baseManagement == null ? "未知目的地" : baseManagement.getBaseName(); + return "该年度已存在酒店/目的地报名记录,目的地【" + baseName + "】"; + } + if (StrUtil.isNotBlank(existEnroll.getTakePartInTravelAgencyId())) { + TheRapyRecuperationTravelAgency travelAgency = dao().fetch(TheRapyRecuperationTravelAgency.class, existEnroll.getTakePartInTravelAgencyId()); + String travelAgencyName = travelAgency == null ? "未知旅行社" : travelAgency.getTravelAgencyName(); + return "该年度已存在旅行社报名记录,旅行社【" + travelAgencyName + "】"; + } + return "该年度已存在报名记录,但未绑定线路、旅行社或目的地,请联系管理员核对记录【" + existEnroll.getId() + "】"; + } + + private String getLineLotName(TheRapyRecuperationLine lineInfo) { + if (lineInfo == null || StrUtil.isBlank(lineInfo.getLotId())) { + return "未设置"; + } + TheRapyRecuperationLot lot = dao().fetch(TheRapyRecuperationLot.class, lineInfo.getLotId()); + return lot == null ? "未设置" : lot.getLotName(); + } + + private String getUnionName(String unionId) { + if (StrUtil.isBlank(unionId)) { + return "未设置"; + } + Sys_union union = dao().fetch(Sys_union.class, unionId); + return union == null ? "未知分工会" : union.getUnionname(); } /** diff --git a/src/main/java/io/v/nutz/zhgh/therapyRecuperation/service/impl/TheRapyRecuperationLineServiceImpl.java b/src/main/java/io/v/nutz/zhgh/therapyRecuperation/service/impl/TheRapyRecuperationLineServiceImpl.java index 50aa8bd..cd3003c 100644 --- a/src/main/java/io/v/nutz/zhgh/therapyRecuperation/service/impl/TheRapyRecuperationLineServiceImpl.java +++ b/src/main/java/io/v/nutz/zhgh/therapyRecuperation/service/impl/TheRapyRecuperationLineServiceImpl.java @@ -1,20 +1,25 @@ package io.v.nutz.zhgh.therapyRecuperation.service.impl; +import cn.afterturn.easypoi.excel.ExcelImportUtil; +import cn.afterturn.easypoi.excel.entity.ImportParams; import cn.hutool.core.util.StrUtil; +import cn.wizzer.framework.base.Result; import cn.wizzer.framework.page.Pagination; -import io.v.nutz.base.utils.Vi; import io.v.nutz.base.query.PageForm; import io.v.nutz.base.service.impl.ViServiceImpl; +import io.v.nutz.base.utils.Vi; import io.v.nutz.web.commons.utils.ShiroUtil; import io.v.nutz.zhgh.therapyRecuperation.constant.TheRapyRecuperationLineCreateMode; import io.v.nutz.zhgh.therapyRecuperation.constant.TheRapyRecuperationSignUpMode; import io.v.nutz.zhgh.therapyRecuperation.constant.TheRapyRecuperationState; +import io.v.nutz.zhgh.therapyRecuperation.mode.TheRapyLineImportExcelMode; import io.v.nutz.zhgh.therapyRecuperation.model.TheRapyRecuperationConfig; import io.v.nutz.zhgh.therapyRecuperation.model.TheRapyRecuperationEnroll; import io.v.nutz.zhgh.therapyRecuperation.model.TheRapyRecuperationEnrollCompanion; import io.v.nutz.zhgh.therapyRecuperation.model.TheRapyRecuperationLine; import io.v.nutz.zhgh.therapyRecuperation.model.TheRapyRecuperationLineUnionSelect; import io.v.nutz.zhgh.therapyRecuperation.model.TheRapyRecuperationLot; +import io.v.nutz.zhgh.therapyRecuperation.model.TheRapyRecuperationTravelAgency; import io.v.nutz.zhgh.therapyRecuperation.service.TheRapyRecuperationConfigService; import io.v.nutz.zhgh.therapyRecuperation.service.TheRapyRecuperationLineService; import org.nutz.aop.interceptor.ioc.TransAop; @@ -26,11 +31,15 @@ import org.nutz.dao.sql.Sql; import org.nutz.ioc.aop.Aop; import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.Lang; import org.nutz.lang.util.NutMap; import org.nutz.plugins.wkcache.annotation.CacheRemove; +import java.io.File; +import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.Objects; /** * @FileName io.v.nutz.zhgh.therapyRecuperation.service.impl.TheRapyRecuperationLineServiceImpl @@ -287,6 +296,270 @@ public class TheRapyRecuperationLineServiceImpl extends ViServiceImpl excelList; + try { + excelList = ExcelImportUtil.importExcel(file, TheRapyLineImportExcelMode.class, new ImportParams()); + } catch (Exception e) { + return Result.error("读取不到数据,请检查excel文件格式"); + } + if (Lang.isEmpty(excelList)) { + return Result.error("读取不到数据,请检查excel文件格式"); + } + List lineList = new ArrayList<>(); + List successList = new ArrayList<>(); + List errorList = new ArrayList<>(); + int nextSerialNumber = getNextSerialNumber(); + for (int i = 0; i < excelList.size(); i++) { + TheRapyLineImportExcelMode row = excelList.get(i); + int rowNumber = i + 2; + if (isBlankImportRow(row) || TheRapyLineImportExcelMode.SAMPLE_LINE_NAME.equals(StrUtil.trim(row.getLineName()))) { + continue; + } + NutMap resultRow = createLineImportResultRow(rowNumber, row); + List errors = validateLineImportRow(row); + TheRapyRecuperationConfig config = null; + TheRapyRecuperationTravelAgency travelAgency = null; + TheRapyRecuperationLot lot = null; + Integer groupType = null; + if (row.getYear() != null) { + try { + config = configService.requireByYear(row.getYear()); + } catch (Exception e) { + errors.add(e.getMessage()); + } + } + if (StrUtil.isNotBlank(row.getTravelAgencySerialNumber())) { + travelAgency = dao().fetch(TheRapyRecuperationTravelAgency.class, Cnd.where("serialNumber", "=", StrUtil.trim(row.getTravelAgencySerialNumber()))); + validateTravelAgency(row, travelAgency, errors); + } + if (StrUtil.isNotBlank(row.getGroupType())) { + groupType = parseGroupType(row.getGroupType(), errors); + } + if (config != null && groupType != null) { + validateGroupCountConfig(config, groupType, errors); + } + if (config != null) { + validateLineTimeConfig(config, errors); + } + if (config != null && StrUtil.isNotBlank(row.getLotName())) { + lot = findImportLot(config, row.getLotName()); + if (lot == null) { + errors.add("时间标段不存在,当前年度没有【" + StrUtil.trim(row.getLotName()) + "】"); + } else if (StrUtil.isBlank(lot.getLotValue()) || !StrUtil.trim(lot.getLotValue()).matches("\\d+")) { + errors.add("时间标段天数配置不正确"); + } + } + if (Lang.isNotEmpty(errors)) { + resultRow.setv("errors", String.join(";", errors)); + errorList.add(resultRow); + continue; + } + TheRapyRecuperationLine line = buildLineByExcel(row, config, travelAgency, lot, groupType, nextSerialNumber++); + lineList.add(line); + resultRow.setv("errors", ""); + successList.add(resultRow); + } + if (Lang.isEmpty(lineList) && Lang.isEmpty(errorList)) { + return Result.error("读取不到数据,请检查excel文件格式"); + } + if (Lang.isNotEmpty(lineList)) { + insert(lineList); + } + NutMap importResult = NutMap.NEW() + .setv("totalCount", successList.size() + errorList.size()) + .setv("successCount", successList.size()) + .setv("errorCount", errorList.size()) + .setv("successList", successList) + .setv("errorList", errorList); + String msg = "导入完成,成功" + successList.size() + "条,失败" + errorList.size() + "条"; + return Result.success().addMsg(msg).addData(importResult); + } + + private boolean isBlankImportRow(TheRapyLineImportExcelMode row) { + return row == null + || (row.getYear() == null + && row.getMaxGroupSize() == null + && StrUtil.isAllBlank(row.getLineName(), row.getTravelAgencySerialNumber(), row.getTravelAgencyPlace(), + row.getRegionalNature(), row.getGroupType(), row.getLotName(), row.getEstimatedCost(), row.getContent())); + } + + /** + * 生成线路导入结果行,前端错误表格和错误导出共用这一份数据。 + */ + private NutMap createLineImportResultRow(int rowNumber, TheRapyLineImportExcelMode row) { + return NutMap.NEW() + .setv("no", rowNumber) + .setv("year", row.getYear()) + .setv("lineName", StrUtil.trim(row.getLineName())) + .setv("travelAgencySerialNumber", StrUtil.trim(row.getTravelAgencySerialNumber())) + .setv("travelAgencyPlace", StrUtil.trim(row.getTravelAgencyPlace())) + .setv("regionalNature", StrUtil.trim(row.getRegionalNature())) + .setv("groupType", StrUtil.trim(row.getGroupType())) + .setv("lotName", StrUtil.trim(row.getLotName())) + .setv("estimatedCost", StrUtil.trim(row.getEstimatedCost())) + .setv("maxGroupSize", row.getMaxGroupSize()); + } + + /** + * 校验模板基础必填项和枚举项,只收集错误不抛出,保证前端能一次看到全部错误行。 + */ + private List validateLineImportRow(TheRapyLineImportExcelMode row) { + List errors = new ArrayList<>(); + if (row.getYear() == null) { + errors.add("年度不能为空"); + } + if (StrUtil.isBlank(row.getLineName())) { + errors.add("线路名称不能为空"); + } + if (StrUtil.isBlank(row.getTravelAgencySerialNumber())) { + errors.add("旅行社编号不能为空"); + } + if (StrUtil.isBlank(row.getTravelAgencyPlace())) { + errors.add("旅行社地点不能为空"); + } + if (StrUtil.isBlank(row.getRegionalNature())) { + errors.add("线路类型不能为空"); + } else if (parseRegionalNature(row.getRegionalNature()) == null) { + errors.add("线路类型只能填写省内线路或省外线路"); + } + if (StrUtil.isBlank(row.getGroupType())) { + errors.add("成团类型不能为空"); + } + if (StrUtil.isBlank(row.getLotName())) { + errors.add("时间标段不能为空"); + } + if (row.getMaxGroupSize() == null) { + errors.add("最多报名人数不能为空"); + } else if (row.getMaxGroupSize() < 0) { + errors.add("最多报名人数不能小于0"); + } + return errors; + } + + /** + * 根据旅行社编号核对旅行社、年度、启用状态和地点,避免线路导到不可用旅行社下。 + */ + private void validateTravelAgency(TheRapyLineImportExcelMode row, TheRapyRecuperationTravelAgency travelAgency, List errors) { + if (travelAgency == null) { + errors.add("旅行社编号不存在"); + return; + } + if (travelAgency.getYear() != null && row.getYear() != null && !travelAgency.getYear().equals(row.getYear())) { + errors.add("旅行社年度与模板年度不一致"); + } + if (travelAgency.isDisabled()) { + errors.add("旅行社未启用"); + } + if (Lang.isEmpty(travelAgency.getTravelAgencyPlaces()) || !travelAgency.getTravelAgencyPlaces().contains(StrUtil.trim(row.getTravelAgencyPlace()))) { + errors.add("旅行社地点不在该旅行社地点范围内"); + } + } + + private Integer parseGroupType(String groupType, List errors) { + String value = StrUtil.trim(groupType); + if ("常规团".equals(value)) { + return 1; + } + if ("精品团".equals(value)) { + return 2; + } + errors.add("成团类型只能填写常规团或精品团"); + return null; + } + + private String parseRegionalNature(String regionalNature) { + String value = StrUtil.trim(regionalNature); + if ("省内线路".equals(value) || "省内".equals(value)) { + return "省内"; + } + if ("省外线路".equals(value) || "省外".equals(value)) { + return "省外"; + } + return null; + } + + private void validateGroupCountConfig(TheRapyRecuperationConfig config, Integer groupType, List errors) { + if (groupType == 1 && config.getConventionalCount() == null) { + errors.add("年度配置未维护常规团最少成团人数"); + } + if (groupType == 2 && config.getBoutiqueCount() == null) { + errors.add("年度配置未维护精品团最少成团人数"); + } + } + + private void validateLineTimeConfig(TheRapyRecuperationConfig config, List errors) { + if (config.getFragmentStartTime() == null || config.getFragmentEndTime() == null + || config.getFragmentPlayStartTime() == null || config.getFragmentPlayEndTime() == null) { + errors.add("年度配置未维护报名或游玩时间"); + } + } + + private TheRapyRecuperationLot findImportLot(TheRapyRecuperationConfig config, String lotName) { + String name = StrUtil.trim(lotName); + if (Lang.isNotEmpty(config.getLots())) { + for (TheRapyRecuperationLot lot : config.getLots()) { + if (name.equals(StrUtil.trim(lot.getLotName()))) { + return lot; + } + } + } + if (StrUtil.isBlank(config.getId())) { + return null; + } + return dao().fetch(TheRapyRecuperationLot.class, Cnd.where("configId", "=", config.getId()).and("lotName", "=", name)); + } + + /** + * 按新建线路字段组装实体,导入默认不启用,旅行社联系人自动沿用旅行社基础信息。 + */ + private TheRapyRecuperationLine buildLineByExcel(TheRapyLineImportExcelMode row, TheRapyRecuperationConfig config, TheRapyRecuperationTravelAgency travelAgency, + TheRapyRecuperationLot lot, Integer groupType, int serialNumber) { + TheRapyRecuperationLine line = new TheRapyRecuperationLine(); + line.setSerialNumber(serialNumber); + line.setLineName(StrUtil.trim(row.getLineName())); + line.setTravelAgencyId(travelAgency.getId()); + line.setTravelAgencyPlace(StrUtil.trim(row.getTravelAgencyPlace())); + line.setLineContact(travelAgency.getContact()); + line.setLineContactPhone(travelAgency.getContactMobileNumber()); + line.setRegionalNature(parseRegionalNature(row.getRegionalNature())); + line.setGroupType(groupType); + line.setMinimumGroupSize(groupType == 1 ? config.getConventionalCount() : config.getBoutiqueCount()); + line.setYear(row.getYear()); + line.setDisabled(true); + line.setCreateUnionId(Vi.getUnionId()); + line.setSignUpStartTime(config.getFragmentStartTime()); + line.setSignUpEndTime(config.getFragmentEndTime()); + line.setChangeEndTime(config.getFragmentEndTime()); + line.setPlayStartTime(config.getFragmentPlayStartTime()); + line.setPlayEndTime(config.getFragmentPlayEndTime()); + line.setEstimatedCost(row.getEstimatedCost()); + line.setEstimatedFamilyNumbers(1); + line.setMaxGroupSize(Objects.requireNonNullElse(row.getMaxGroupSize(), 0)); + line.setSignUpMode(ShiroUtil.hasAnyRoles("sysadmin, SchoolUnionAdmin") + ? TheRapyRecuperationSignUpMode.FREE.getValue() : TheRapyRecuperationSignUpMode.PERSONAL.getValue()); + line.setCreateMode(ShiroUtil.hasAnyRoles("sysadmin, SchoolUnionAdmin") + ? TheRapyRecuperationLineCreateMode.SCHOOL.getValue() : TheRapyRecuperationLineCreateMode.UNION.getValue()); + line.setLotId(lot.getId()); + line.setPlayNumberOfDays(Integer.parseInt(lot.getLotValue())); + line.setContent(row.getContent()); + line.setOpenChoose(false); + line.setSpecialLine(false); + line.setTogetherLine(false); + line.setStateId(groupType == 2 ? 1 : 4); + line.setOpBy(ShiroUtil.getUserId()); + line.setOpAt(Long.valueOf(String.valueOf(new Date().getTime()))); + return line; + } + /** * 目标年度中已存在同名、同旅行社、同标段、同区域性质的校工会组织线路时,不再重复复制。 * diff --git a/src/main/java/io/v/nutz/zhgh/therapyRecuperation/service/impl/baseManage/TheRapyRecuperationBaseManagerServiceImpl.java b/src/main/java/io/v/nutz/zhgh/therapyRecuperation/service/impl/baseManage/TheRapyRecuperationBaseManagerServiceImpl.java index 72c3e09..332e011 100644 --- a/src/main/java/io/v/nutz/zhgh/therapyRecuperation/service/impl/baseManage/TheRapyRecuperationBaseManagerServiceImpl.java +++ b/src/main/java/io/v/nutz/zhgh/therapyRecuperation/service/impl/baseManage/TheRapyRecuperationBaseManagerServiceImpl.java @@ -1,17 +1,22 @@ package io.v.nutz.zhgh.therapyRecuperation.service.impl.baseManage; +import cn.afterturn.easypoi.excel.ExcelImportUtil; +import cn.afterturn.easypoi.excel.entity.ImportParams; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.StrUtil; +import cn.wizzer.framework.base.Result; import io.v.nutz.base.service.impl.BaseServiceImpl; import io.v.nutz.base.utils.Vi; import io.v.nutz.sys.models.SysHoliday; import io.v.nutz.web.commons.utils.ShiroUtil; import io.v.nutz.zhgh.therapyRecuperation.constant.TheRapyRecuperationState; +import io.v.nutz.zhgh.therapyRecuperation.mode.TheRapyBaseManagementExcelMode; import io.v.nutz.zhgh.therapyRecuperation.model.TheRapyRecuperationBaseDailyQuota; import io.v.nutz.zhgh.therapyRecuperation.model.TheRapyRecuperationBaseManagement; import io.v.nutz.zhgh.therapyRecuperation.model.TheRapyRecuperationConfig; import io.v.nutz.zhgh.therapyRecuperation.model.TheRapyRecuperationEnroll; import io.v.nutz.zhgh.therapyRecuperation.model.TheRapyRecuperationLot; +import io.v.nutz.zhgh.therapyRecuperation.model.TheRapyRecuperationTravelAgency; import io.v.nutz.zhgh.therapyRecuperation.service.TheRapyRecuperationConfigService; import io.v.nutz.zhgh.therapyRecuperation.service.baseManage.TheRapyRecuperationBaseManagerService; import org.nutz.aop.interceptor.ioc.TransAop; @@ -25,6 +30,7 @@ import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.lang.Lang; import org.nutz.lang.util.NutMap; +import java.io.File; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.ArrayList; @@ -264,6 +270,214 @@ public class TheRapyRecuperationBaseManagerServiceImpl extends BaseServiceImpl i .setv("skipCount", skipCount); } + /** + * 导入目的地时只读取模板基础字段,报名和活动时间统一取对应年度的疗休养配置。 + * + * @param file Excel文件 + * @param opBy 当前操作人ID + * @param createUnionId 当前操作人所属工会ID + * @return 导入结果 + */ + @Override + @Aop(TransAop.READ_COMMITTED) + public Result importBaseManager(File file, String opBy, String createUnionId) { + List excelList; + try { + excelList = ExcelImportUtil.importExcel(file, TheRapyBaseManagementExcelMode.class, new ImportParams()); + } catch (Exception e) { + return Result.error("读取不到数据,请检查excel文件格式"); + } + if (Lang.isEmpty(excelList)) { + return Result.error("读取不到数据,请检查excel文件格式"); + } + List baseList = new ArrayList<>(); + List successList = new ArrayList<>(); + List errorList = new ArrayList<>(); + int nextSortNumber = getNextSortNumber(); + for (int i = 0; i < excelList.size(); i++) { + TheRapyBaseManagementExcelMode row = excelList.get(i); + int rowNumber = i + 2; + if (isBlankImportRow(row) || TheRapyBaseManagementExcelMode.SAMPLE_BASE_NAME.equals(StrUtil.trim(row.getBaseName()))) { + continue; + } + NutMap resultRow = createBaseImportResultRow(rowNumber, row); + List errors = validateImportRow(row); + TheRapyRecuperationConfig config = null; + TheRapyRecuperationTravelAgency travelAgency = null; + List allowDayList = Collections.emptyList(); + if (row.getYear() != null) { + try { + config = configService.requireByYear(row.getYear()); + } catch (Exception e) { + errors.add(e.getMessage()); + } + } + if (StrUtil.isNotBlank(row.getTravelAgencySerialNumber())) { + travelAgency = dao().fetch(TheRapyRecuperationTravelAgency.class, Cnd.where("serialNumber", "=", StrUtil.trim(row.getTravelAgencySerialNumber()))); + validateTravelAgency(row, travelAgency, errors); + } + if (StrUtil.isNotBlank(row.getAllowDay())) { + allowDayList = parseAllowDay(row.getAllowDay(), errors); + } + if (Lang.isNotEmpty(errors)) { + resultRow.setv("errors", String.join(";", errors)); + errorList.add(resultRow); + continue; + } + TheRapyRecuperationBaseManagement baseManagement = buildBaseManagementByExcel(row, opBy, createUnionId, config, travelAgency, allowDayList, nextSortNumber++); + baseList.add(baseManagement); + resultRow.setv("errors", ""); + successList.add(resultRow); + } + if (Lang.isEmpty(baseList) && Lang.isEmpty(errorList)) { + return Result.error("读取不到数据,请检查excel文件格式"); + } + if (Lang.isNotEmpty(baseList)) { + dao().insertOrUpdate(baseList); + } + NutMap importResult = NutMap.NEW() + .setv("totalCount", successList.size() + errorList.size()) + .setv("successCount", successList.size()) + .setv("errorCount", errorList.size()) + .setv("successList", successList) + .setv("errorList", errorList); + String msg = "导入完成,成功" + successList.size() + "条,失败" + errorList.size() + "条"; + return Result.success().addMsg(msg).addData(importResult); + } + + private boolean isBlankImportRow(TheRapyBaseManagementExcelMode row) { + return row == null + || (row.getYear() == null + && row.getMaxSignCount() == null + && StrUtil.isAllBlank(row.getBaseName(), row.getTravelAgencySerialNumber(), row.getTravelAgencyPlace(), + row.getRegionalNature(), row.getAllowDay(), row.getBaseContactPerson(), row.getBaseContactNumber(), row.getContent())); + } + + /** + * 生成目的地导入结果行,前端错误表格和错误导出共用这一份数据。 + */ + private NutMap createBaseImportResultRow(int rowNumber, TheRapyBaseManagementExcelMode row) { + return NutMap.NEW() + .setv("no", rowNumber) + .setv("year", row.getYear()) + .setv("baseName", StrUtil.trim(row.getBaseName())) + .setv("travelAgencySerialNumber", StrUtil.trim(row.getTravelAgencySerialNumber())) + .setv("travelAgencyPlace", StrUtil.trim(row.getTravelAgencyPlace())) + .setv("regionalNature", StrUtil.trim(row.getRegionalNature())) + .setv("allowDay", StrUtil.trim(row.getAllowDay())); + } + + /** + * 校验模板基础必填项和枚举项,只收集错误不抛出,保证前端能一次看到全部错误行。 + */ + private List validateImportRow(TheRapyBaseManagementExcelMode row) { + List errors = new ArrayList<>(); + if (row.getYear() == null) { + errors.add("年度不能为空"); + } + if (StrUtil.isBlank(row.getBaseName())) { + errors.add("目的地名称不能为空"); + } + if (StrUtil.isBlank(row.getTravelAgencySerialNumber())) { + errors.add("旅行社编号不能为空"); + } + if (StrUtil.isBlank(row.getTravelAgencyPlace())) { + errors.add("旅行社地点不能为空"); + } + if (StrUtil.isBlank(row.getRegionalNature())) { + errors.add("活动范围不能为空"); + } else if (!List.of("省内", "省外").contains(StrUtil.trim(row.getRegionalNature()))) { + errors.add("活动范围只能填写省内或省外"); + } + if (StrUtil.isBlank(row.getAllowDay())) { + errors.add("天数不能为空"); + } + if (row.getMaxSignCount() != null && row.getMaxSignCount() < 0) { + errors.add("每日最高人数不能小于0"); + } + return errors; + } + + /** + * 根据旅行社编号核对旅行社、年度、启用状态和地点,避免目的地导到不可用旅行社下。 + */ + private void validateTravelAgency(TheRapyBaseManagementExcelMode row, TheRapyRecuperationTravelAgency travelAgency, List errors) { + if (travelAgency == null) { + errors.add("旅行社编号不存在"); + return; + } + if (travelAgency.getYear() != null && row.getYear() != null && !travelAgency.getYear().equals(row.getYear())) { + errors.add("旅行社年度与模板年度不一致"); + } + if (travelAgency.isDisabled()) { + errors.add("旅行社未启用"); + } + if (Lang.isEmpty(travelAgency.getTravelAgencyPlaces()) || !travelAgency.getTravelAgencyPlaces().contains(StrUtil.trim(row.getTravelAgencyPlace()))) { + errors.add("旅行社地点不在该旅行社地点范围内"); + } + } + + /** + * 解析模板天数字段,支持英文逗号和中文逗号,导入值限定为页面可选的3、2、2.5。 + * + * @param allowDay 模板天数字段 + * @param errors 当前行错误列表 + * @return 可保存到目的地的天数列表 + */ + private List parseAllowDay(String allowDay, List errors) { + Set allowedValues = Set.of("3", "2", "2.5"); + List allowDayList = new ArrayList<>(); + String[] values = StrUtil.trim(allowDay).replace(",", ",").split(","); + for (String value : values) { + String day = StrUtil.trim(value); + if (StrUtil.isBlank(day)) { + continue; + } + if (!allowedValues.contains(day)) { + errors.add("天数只能填写3、2、2.5"); + continue; + } + if (!allowDayList.contains(day)) { + allowDayList.add(day); + } + } + if (Lang.isEmpty(allowDayList)) { + errors.add("天数不能为空"); + } + return allowDayList; + } + + /** + * 按新建目的地提交字段组装实体,导入默认不启用,时间统一沿用年度配置。 + */ + private TheRapyRecuperationBaseManagement buildBaseManagementByExcel(TheRapyBaseManagementExcelMode row, String opBy, String createUnionId, TheRapyRecuperationConfig config, + TheRapyRecuperationTravelAgency travelAgency, List allowDayList, int sortNumber) { + TheRapyRecuperationBaseManagement baseManagement = new TheRapyRecuperationBaseManagement(); + baseManagement.setYear(row.getYear()); + baseManagement.setSortNumber(sortNumber); + baseManagement.setBaseName(StrUtil.trim(row.getBaseName())); + baseManagement.setTravelAgencyId(travelAgency.getId()); + baseManagement.setTravelAgencyPlace(StrUtil.trim(row.getTravelAgencyPlace())); + baseManagement.setRegionalNature(StrUtil.trim(row.getRegionalNature())); + baseManagement.setContent(row.getContent()); + baseManagement.setIsDisabled(true); + baseManagement.setCreateUnionId(createUnionId); + baseManagement.setSignUpStartTime(config.getFragmentStartTime()); + baseManagement.setSignUpEndTime(config.getFragmentEndTime()); + baseManagement.setChangeEndTime(config.getFragmentEndTime()); + baseManagement.setActivityStartTime(config.getFragmentPlayStartTime()); + baseManagement.setActivityEndTime(config.getFragmentPlayEndTime()); + baseManagement.setCreateMode(1); + baseManagement.setBaseContactPerson(StrUtil.blankToDefault(row.getBaseContactPerson(), travelAgency.getContact())); + baseManagement.setBaseContactNumber(StrUtil.blankToDefault(row.getBaseContactNumber(), travelAgency.getContactMobileNumber())); + baseManagement.setWeekCheckIn(Collections.emptyList()); + baseManagement.setAllowDay(allowDayList); + baseManagement.setMaxSignCount(Objects.requireNonNullElse(row.getMaxSignCount(), 0)); + baseManagement.setOpBy(opBy); + baseManagement.setOpAt(String.valueOf(new Date().getTime())); + return baseManagement; + } + /** * 目标年度存在同名、同旅行社、同地点、同区域、同标段的目的地时,不再重复复制。 * diff --git a/src/main/resources/static/components/theRapyRecuperation/LineInfo.vue b/src/main/resources/static/components/theRapyRecuperation/LineInfo.vue index 1774e49..c0239b3 100644 --- a/src/main/resources/static/components/theRapyRecuperation/LineInfo.vue +++ b/src/main/resources/static/components/theRapyRecuperation/LineInfo.vue @@ -17,6 +17,7 @@ {{ viewData.groupType === 1 ? '常规团' : '精品团' }} {{ viewData.regionalNature }} {{ viewData.minimumGroupSize }} + {{ viewData.maxGroupSize === 0 ? '不限制' : viewData.maxGroupSize }} {{ viewData.lotName }} {{ viewData.estimatedCost }} {{ viewData.lineContact }} diff --git a/src/main/resources/views/platform/theRapyRecuperation/baseManage/baseManagement.html b/src/main/resources/views/platform/theRapyRecuperation/baseManage/baseManagement.html index 151671c..f01837e 100644 --- a/src/main/resources/views/platform/theRapyRecuperation/baseManage/baseManagement.html +++ b/src/main/resources/views/platform/theRapyRecuperation/baseManage/baseManagement.html @@ -404,8 +404,8 @@ layout("/layouts/platform.html"){ @@ -419,14 +419,43 @@ layout("/layouts/platform.html"){ + + +

总记录数:{{importResult.totalCount}}

+

成功数:{{importResult.successCount}}

+

失败数:{{importResult.errorCount}}

+ 查看错误记录 + +
+
- 取 消 + 取 消 确定 + +
+ 下载错误记录 + +
+ + + + + + + + + + +
+ +