This commit is contained in:
=
2026-06-08 08:40:54 +08:00
parent 62b66a2afd
commit e970c350dc
13 changed files with 1107 additions and 229 deletions
@@ -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<TheRapyRecuperationTravelAgency> travelAgencys = dao.query(TheRapyRecuperationTravelAgency.class, Cnd.NEW().desc("serialNumber"));
List<String> excelTravelAgencyList = travelAgencys.stream().map(v -> v.getTravelAgencyName() + "_" + v.getId()).collect(Collectors.toList());
String[] excelTravelAgencyArrs = excelTravelAgencyList.toArray(new String[excelTravelAgencyList.size()]);
//查标段,转数组
List<TheRapyRecuperationLot> lots = dao.query(TheRapyRecuperationLot.class, Cnd.NEW().asc("id"));
List<String> 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<TheRapyRecuperationBaseManagement> excelModeClass = TheRapyRecuperationBaseManagement.class;
Field[] excelModeClassDeclaredFields = excelModeClass.getDeclaredFields();
//字段过滤
List<Field> 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<TheRapyBaseManagementExcelMode> 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<TheRapyBaseManagementExcelMode> 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<TheRapyRecuperationBaseManagement> 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
@@ -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<TheRapyTravelLineExcelMode> 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<TheRapyRecuperationLine> 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<TheRapyRecuperationTravelAgency> travelAgencys = dao.query(TheRapyRecuperationTravelAgency.class, Cnd.NEW().desc("serialNumber"));
List<String> excelTravelAgencys = travelAgencys.stream().map(v -> v.getTravelAgencyName() + "_" + v.getId()).collect(Collectors.toList());
String[] excelTravelAgencyArrs = excelTravelAgencys.toArray(new String[excelTravelAgencys.size()]);
//查标段,转数组
List<TheRapyRecuperationLot> lots = dao.query(TheRapyRecuperationLot.class, Cnd.NEW().asc("id"));
List<String> 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<TheRapyTravelLineExcelMode> excelModeClass = TheRapyTravelLineExcelMode.class;
Field[] excelModeClassDeclaredFields = excelModeClass.getDeclaredFields();
//字段过滤
List<Field> 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<TheRapyLineImportExcelMode> 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<TheRapyLineImportExcelMode> examples = new ArrayList<>();
examples.add(example);
return examples;
}
}
@@ -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;
}
@@ -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;
}
@@ -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<TheRapyRecuper
* @return 复制结果,包含来源数量、复制数量和跳过数量
*/
NutMap copySchoolUnionLines(Integer sourceYear, Integer targetYear);
/**
* 导入线路模板数据,负责把模板展示值转换成线路保存字段。
*
* @param file 导入的Excel文件
* @return 导入结果
*/
Result importTravelLine(File file);
}
@@ -1,7 +1,9 @@
package io.v.nutz.zhgh.therapyRecuperation.service.baseManage;
import cn.wizzer.framework.base.Result;
import org.nutz.lang.util.NutMap;
import java.io.File;
import java.util.List;
/**
@@ -29,4 +31,14 @@ public interface TheRapyRecuperationBaseManagerService {
* @return 复制结果,包含来源数量、复制数量和跳过数量
*/
NutMap copyLastYearBase(Integer sourceYear, Integer targetYear);
/**
* 导入目的地模板数据,负责把模板里的中文展示值转换成数据库字段。
*
* @param file 导入的Excel文件
* @param opBy 当前操作人ID
* @param createUnionId 当前操作人所属工会ID
* @return 导入结果
*/
Result importBaseManager(File file, String opBy, String createUnionId);
}
@@ -806,7 +806,7 @@ public class TheRapyRecuperationEnrollServiceImpl extends ViServiceImpl<TheRapyR
int count = dao().count(TheRapyRecuperationEnroll.class,
Cnd.where("takePartInBaseManagementId", "=", currentEnroll.getTakePartInBaseManagementId())
.and("loginName", "=", loginName)
.and("isNormal", "=", 2750)
.and("isNormal", "=", true)
.and("YEAR(signingUptime)", "=", DateUtil.thisYear())
.and("specificTime", "=", currentEnroll.getSpecificTime())
//.and("playDay", "=", currentEnroll.getPlayDay())
@@ -1417,10 +1417,10 @@ public class TheRapyRecuperationEnrollServiceImpl extends ViServiceImpl<TheRapyR
Map<String, User> userMap = dao().query(User.class, Cnd.where("loginname", "in", loginNames))
.stream()
.collect(Collectors.toMap(User::getLoginname, v -> v, (oldValue, newValue) -> oldValue));
Map<String, TheRapyRecuperationEnroll> existEnrollMap = dao().query(TheRapyRecuperationEnroll.class, Cnd.where("loginName", "in", loginNames)
Map<String, List<TheRapyRecuperationEnroll>> 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<String, TheRapyRecuperationLot> lotMap = dao().query(TheRapyRecuperationLot.class, Cnd.where("configId", "=", lineConfig.getId()))
@@ -1428,30 +1428,42 @@ public class TheRapyRecuperationEnrollServiceImpl extends ViServiceImpl<TheRapyR
.collect(Collectors.toMap(TheRapyRecuperationLot::getLotName, v -> v, (oldValue, newValue) -> oldValue));
List<TheRapyRecuperationEnroll> supplementList = new ArrayList<>();
List<String> existInfos = new ArrayList<>();
List<String> errorInfos = new ArrayList<>();
List<NutMap> successList = new ArrayList<>();
List<NutMap> errorList = new ArrayList<>();
Set<String> 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<TheRapyRecuperationEnroll> 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<TheRapyR
enroll.setNormal(true);
supplementKeys.add(enrollKey);
supplementList.add(enroll);
row.setv("errors", "");
successList.add(row);
}
if (Lang.isNotEmpty(supplementList)) {
dao().insert(supplementList);
}
if (Lang.isEmpty(supplementList) && Lang.isNotEmpty(errorInfos) && Lang.isEmpty(existInfos)) {
return Result.error("补录失败:" + String.join("", errorInfos));
NutMap importResult = NutMap.NEW()
.setv("totalCount", excelList.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 NutMap createSupplementImportRow(int no, TheRapyRecuperationEnrollExcelMode excel, int takePartInYear) {
return NutMap.NEW()
.setv("no", no)
.setv("loginName", StrUtil.trim(excel.getLoginName()))
.setv("userName", excel.getUserName())
.setv("takePartInYear", takePartInYear)
.setv("takePartInTime", DateUtil.formatDate(excel.getTakePartInTime()))
.setv("lotName", excel.getLotId());
}
/**
* 将已存在记录转换成可读原因,说明人员为什么没有补录到本次选择的线路。
*/
private String buildSupplementExistReason(List<TheRapyRecuperationEnroll> existEnrollList, TheRapyRecuperationLineUnionSelect targetLineUnionSelect) {
List<String> 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();
}
/**
@@ -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<TheRapyRec
.setv("skipCount", skipCount);
}
/**
* 导入线路时只读取模板展示字段,旅行社、时间标段和创建字段按系统数据转换。
*
* @param file Excel文件
* @return 导入结果
*/
@Override
@Aop(TransAop.READ_COMMITTED)
public Result importTravelLine(File file) {
List<TheRapyLineImportExcelMode> 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<TheRapyRecuperationLine> lineList = new ArrayList<>();
List<NutMap> successList = new ArrayList<>();
List<NutMap> 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<String> 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<String> validateLineImportRow(TheRapyLineImportExcelMode row) {
List<String> 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<String> 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<String> 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<String> errors) {
if (groupType == 1 && config.getConventionalCount() == null) {
errors.add("年度配置未维护常规团最少成团人数");
}
if (groupType == 2 && config.getBoutiqueCount() == null) {
errors.add("年度配置未维护精品团最少成团人数");
}
}
private void validateLineTimeConfig(TheRapyRecuperationConfig config, List<String> 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;
}
/**
* 目标年度中已存在同名、同旅行社、同标段、同区域性质的校工会组织线路时,不再重复复制。
*
@@ -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<TheRapyBaseManagementExcelMode> 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<TheRapyRecuperationBaseManagement> baseList = new ArrayList<>();
List<NutMap> successList = new ArrayList<>();
List<NutMap> 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<String> errors = validateImportRow(row);
TheRapyRecuperationConfig config = null;
TheRapyRecuperationTravelAgency travelAgency = null;
List<String> 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<String> validateImportRow(TheRapyBaseManagementExcelMode row) {
List<String> 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<String> 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<String> parseAllowDay(String allowDay, List<String> errors) {
Set<String> allowedValues = Set.of("3", "2", "2.5");
List<String> 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<String> 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;
}
/**
* 目标年度存在同名、同旅行社、同地点、同区域、同标段的目的地时,不再重复复制。
*
@@ -17,6 +17,7 @@
<el-descriptions-item label="成团类型">{{ viewData.groupType === 1 ? '常规团' : '精品团' }}</el-descriptions-item>
<el-descriptions-item label="线路类型">{{ viewData.regionalNature }}</el-descriptions-item>
<el-descriptions-item label="最少成团人数">{{ viewData.minimumGroupSize }}</el-descriptions-item>
<el-descriptions-item label="最多报名人数">{{ viewData.maxGroupSize === 0 ? '不限制' : viewData.maxGroupSize }}</el-descriptions-item>
<el-descriptions-item label="时间标段">{{ viewData.lotName }}</el-descriptions-item>
<el-descriptions-item label="预计费用">{{ viewData.estimatedCost }}</el-descriptions-item>
<el-descriptions-item label="联系人">{{ viewData.lineContact }}</el-descriptions-item>
@@ -404,8 +404,8 @@ layout("/layouts/platform.html"){
<el-upload
name="file"
ref="upload"
:on-remove="(file, fileList) => {importData.fileList = fileHandleRemove(file, fileList)}"
:on-change="(file, fileList) => {importData.fileList = fileHandleChange(file, fileList,{type:['xls','xlsx']})}"
:on-remove="handleImportFileRemove"
:on-change="handleImportFileChange"
:auto-upload="false"
:limit="1"
:file-list="importData.fileList">
@@ -419,14 +419,43 @@ layout("/layouts/platform.html"){
</el-form>
</el-card>
</el-timeline-item>
<el-timeline-item timestamp="导入结果" placement="top">
<el-card shadow="never">
<p>总记录数:{{importResult.totalCount}}</p>
<p>成功数:<span class="text-success">{{importResult.successCount}}</span></p>
<p>失败数:<span class="text-danger">{{importResult.errorCount}}</span></p>
<el-link @click="openImportError" type="primary"
v-if="importResult.errorCount>0">查看错误记录
</el-link>
</el-card>
</el-timeline-item>
</el-timeline>
<span slot="footer" class="dialog-footer">
<el-button @click="importVisible = false" :disabled="importLoading">取 消</el-button>
<el-button @click="closeImportDialog" :disabled="importLoading">取 消</el-button>
<el-button type="primary" @click="doImport" :loading="importLoading">确定</el-button>
</span>
</el-dialog>
<el-dialog title="目的地导入错误记录" :visible.sync="importErrorVisible" append-to-body
:close-on-click-modal="false" width="80%">
<div style="text-align: right; margin-bottom: 10px">
<el-button size="small" type="primary" icon="el-icon-download"
@click="exportImportErrors">下载错误记录
</el-button>
</div>
<el-table :data="importResult.errorList" size="small" border>
<el-table-column label="excel序号" prop="no" width="100px"></el-table-column>
<el-table-column label="年度" prop="year" width="100px"></el-table-column>
<el-table-column label="目的地名称" prop="baseName" width="160px"></el-table-column>
<el-table-column label="旅行社编号" prop="travelAgencySerialNumber" width="130px"></el-table-column>
<el-table-column label="旅行社地点" prop="travelAgencyPlace" width="130px"></el-table-column>
<el-table-column label="活动范围" prop="regionalNature" width="110px"></el-table-column>
<el-table-column label="天数" prop="allowDay" width="120px"></el-table-column>
<el-table-column label="未导入原因" prop="errors" show-overflow-tooltip></el-table-column>
</el-table>
</el-dialog>
<el-dialog
title="沿用目的地"
:visible.sync="copyBaseVisible"
@@ -464,6 +493,7 @@ layout("/layouts/platform.html"){
</template>
</guava>
</div>
<script src="${base!}/assets/platform/plugins/xlsx/xlsx.full.min.js"></script>
<script>
new Vue({
el: '#app',
@@ -599,8 +629,18 @@ layout("/layouts/platform.html"){
},
//目的地导入
importVisible: false,
importErrorVisible: false,
importLoading: false,
importData: {},
importData: {
fileList: []
},
importResult: {
totalCount: 0,
successCount: 0,
errorCount: 0,
successList: [],
errorList: []
},
copyBaseVisible: false,
copyBaseLoading: false,
copyBaseForm: {
@@ -842,10 +882,17 @@ layout("/layouts/platform.html"){
}
},
openImport() {
this.importData = {
fileList: []
}
this.importVisible = true;
this.$set(this.importData, 'fileList', [])
this.resetImportResult()
this.$set(this, 'importVisible', true)
},
handleImportFileRemove(file, fileList) {
this.$set(this.importData, 'fileList', this.fileHandleRemove(file, fileList))
this.resetImportResult()
},
handleImportFileChange(file, fileList) {
this.$set(this.importData, 'fileList', this.fileHandleChange(file, fileList, {type: ['xls', 'xlsx']}))
this.resetImportResult()
},
doImport() {
if (this.importData.fileList.length === 0) {
@@ -856,29 +903,88 @@ layout("/layouts/platform.html"){
this.importData.fileList.forEach((val) => {
data.append("file", val.raw, val.raw.name);
});
this.importLoading = true
this.$set(this, 'importLoading', true)
$.ajax({
url: loc() + "/importBaseManager",
type: "post",
data: data,
processData: false,
contentType: false,
success: (data) => {
if (data.code === 0){
this.$message.success(data.msg)
this.pageData();
this.importVisible = false
this.importLoading = false
}else {
this.importVisible = false
success: (resp) => {
if (resp.code === 0) {
const result = resp.data || this.emptyImportResult()
this.$set(this, 'importResult', result)
if (result.successCount > 0) {
this.pageData()
}
if (result.errorCount > 0) {
this.notifyWarning(resp.msg || '导入完成,存在未导入目的地')
} else {
this.notifySuccess(resp.msg || '导入成功')
}
} else {
this.notifyWarning(resp.msg)
}
this.$set(this, 'importLoading', false)
},
error: (data) => {
error: () => {
this.notifyWarning("导入失败")
this.importLoading = false
this.$set(this, 'importLoading', false)
}
});
},
closeImportDialog() {
this.$set(this, 'importVisible', false)
this.$set(this, 'importErrorVisible', false)
},
emptyImportResult() {
return {
totalCount: 0,
successCount: 0,
errorCount: 0,
successList: [],
errorList: []
}
},
resetImportResult() {
this.$set(this, 'importResult', this.emptyImportResult())
this.$set(this, 'importErrorVisible', false)
},
openImportError() {
this.$set(this, 'importErrorVisible', true)
},
exportImportErrors() {
const data = this.importResult.errorList || []
if (data.length === 0) {
this.notifyWarning('暂无错误记录')
return
}
const exportData = data.map(item => {
return {
'excel序号': item.no,
'年度': item.year,
'目的地名称': item.baseName,
'旅行社编号': item.travelAgencySerialNumber,
'旅行社地点': item.travelAgencyPlace,
'活动范围': item.regionalNature,
'天数': item.allowDay,
'未导入原因': item.errors
}
})
const workbook = XLSX.utils.book_new()
const worksheet = XLSX.utils.json_to_sheet(exportData)
XLSX.utils.book_append_sheet(workbook, worksheet, '错误记录')
const excelBuffer = XLSX.write(workbook, {bookType: 'xlsx', type: 'array'})
const blob = new Blob([excelBuffer], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'})
const url = window.URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = url
link.download = '目的地导入错误记录.xlsx'
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
window.URL.revokeObjectURL(url)
},
async getNumber() {
const resp = await $.post(loc() + '/getNo')
this.formData.sortNumber = resp.data
@@ -131,6 +131,7 @@ layout("/layouts/platform.html"){
@click="openCopySchoolUnionLine"
size="medium"
type="primary">沿用校工会线路</el-button>
<el-button @click="openImport" size="medium" type="primary">导入线路</el-button>
<el-button @click="openAdd" size="medium" type="primary">新建线路</el-button>
</template>
</table-tool>
@@ -479,12 +480,8 @@ layout("/layouts/platform.html"){
<el-upload
name="file"
ref="upload"
:on-remove="(file, fileList) => {
importData.fileList = fileHandleRemove(file, fileList)
}"
:on-change="(file, fileList) => {
importData.fileList = fileHandleChange(file, fileList,{type:['xls','xlsx']})
}"
:on-remove="handleImportFileRemove"
:on-change="handleImportFileChange"
:auto-upload="false"
:limit="1"
:file-list="importData.fileList">
@@ -498,14 +495,46 @@ layout("/layouts/platform.html"){
</el-form>
</el-card>
</el-timeline-item>
<el-timeline-item timestamp="导入结果" placement="top">
<el-card shadow="never">
<p>总记录数:{{importResult.totalCount}}</p>
<p>成功数:<span class="text-success">{{importResult.successCount}}</span></p>
<p>失败数:<span class="text-danger">{{importResult.errorCount}}</span></p>
<el-link @click="openImportError" type="primary"
v-if="importResult.errorCount>0">查看错误记录
</el-link>
</el-card>
</el-timeline-item>
</el-timeline>
<span slot="footer" class="dialog-footer">
<el-button @click="importVisible = false" :disabled="importLoading">取 消</el-button>
<el-button @click="closeImportDialog" :disabled="importLoading">取 消</el-button>
<el-button type="primary" @click="doImport" :loading="importLoading">确定</el-button>
</span>
</el-dialog>
<el-dialog title="线路导入错误记录" :visible.sync="importErrorVisible" append-to-body
:close-on-click-modal="false" width="85%">
<div style="text-align: right; margin-bottom: 10px">
<el-button size="small" type="primary" icon="el-icon-download"
@click="exportImportErrors">下载错误记录
</el-button>
</div>
<el-table :data="importResult.errorList" size="small" border>
<el-table-column label="excel序号" prop="no" width="100px"></el-table-column>
<el-table-column label="年度" prop="year" width="100px"></el-table-column>
<el-table-column label="线路名称" prop="lineName" width="160px"></el-table-column>
<el-table-column label="旅行社编号" prop="travelAgencySerialNumber" width="130px"></el-table-column>
<el-table-column label="旅行社地点" prop="travelAgencyPlace" width="130px"></el-table-column>
<el-table-column label="线路类型" prop="regionalNature" width="130px"></el-table-column>
<el-table-column label="成团类型" prop="groupType" width="120px"></el-table-column>
<el-table-column label="时间标段" prop="lotName" width="130px"></el-table-column>
<el-table-column label="预计费用" prop="estimatedCost" width="110px"></el-table-column>
<el-table-column label="最多报名人数" prop="maxGroupSize" width="120px"></el-table-column>
<el-table-column label="未导入原因" prop="errors" show-overflow-tooltip></el-table-column>
</el-table>
</el-dialog>
<el-dialog
title="沿用校工会线路"
:visible.sync="copyLineVisible"
@@ -541,6 +570,7 @@ layout("/layouts/platform.html"){
</guava>
</div>
<script src="${base!}/assets/platform/plugins/xlsx/xlsx.full.min.js"></script>
<script>
const vue = new Vue({
@@ -692,8 +722,18 @@ layout("/layouts/platform.html"){
lotList: [],
//路线导入
importVisible: false,
importErrorVisible: false,
importLoading: false,
importData: {},
importData: {
fileList: []
},
importResult: {
totalCount: 0,
successCount: 0,
errorCount: 0,
successList: [],
errorList: []
},
copyLineVisible: false,
copyLineLoading: false,
copyLineForm: {
@@ -832,7 +872,10 @@ layout("/layouts/platform.html"){
await this.$nextTick()
const data = resp.data
data.year = data.year.toString()
this.formData = {...data}
await this.getConfig(data.year)
await this.getLotList(data.year)
await this.getModifyConfig(data.year)
this.$set(this, 'formData', {...data})
} else {
this.notifyWarning(resp.msg)
}
@@ -945,10 +988,17 @@ layout("/layouts/platform.html"){
this.$set(this, 'lotList', (data || {}).lots || [])
},
openImport() {
this.importData = {
fileList: []
}
this.importVisible = true;
this.$set(this.importData, 'fileList', [])
this.resetImportResult()
this.$set(this, 'importVisible', true)
},
handleImportFileRemove(file, fileList) {
this.$set(this.importData, 'fileList', this.fileHandleRemove(file, fileList))
this.resetImportResult()
},
handleImportFileChange(file, fileList) {
this.$set(this.importData, 'fileList', this.fileHandleChange(file, fileList, {type: ['xls', 'xlsx']}))
this.resetImportResult()
},
async doImport() {
if (this.importData.fileList.length === 0) {
@@ -959,24 +1009,91 @@ layout("/layouts/platform.html"){
this.importData.fileList.forEach((val) => {
data.append("file", val.raw, val.raw.name);
});
this.importLoading = true
const resp = await $.ajax({
this.$set(this, 'importLoading', true)
$.ajax({
url: loc() + '/travelLineImport',
type: 'POST',
data: data,
processData: false,
contentType: false
contentType: false,
success: (resp) => {
if (resp.code === 0) {
const result = resp.data || this.emptyImportResult()
this.$set(this, 'importResult', result)
if (result.successCount > 0) {
this.pageData()
}
if (result.errorCount > 0) {
this.notifyWarning(resp.msg || '导入完成,存在线路未导入')
} else {
this.notifySuccess(resp.msg || '导入成功')
}
} else {
this.notifyWarning(resp.msg)
}
this.$set(this, 'importLoading', false)
},
error: () => {
this.notifyWarning("导入失败")
this.$set(this, 'importLoading', false)
}
})
if (resp.code === 0){
this.$message.success(resp.msg)
this.pageData();
this.importVisible = false
this.importLoading = false
}else {
this.notifyWarning("导入失败")
this.importLoading = false
},
closeImportDialog() {
this.$set(this, 'importVisible', false)
this.$set(this, 'importErrorVisible', false)
},
emptyImportResult() {
return {
totalCount: 0,
successCount: 0,
errorCount: 0,
successList: [],
errorList: []
}
},
resetImportResult() {
this.$set(this, 'importResult', this.emptyImportResult())
this.$set(this, 'importErrorVisible', false)
},
openImportError() {
this.$set(this, 'importErrorVisible', true)
},
exportImportErrors() {
const data = this.importResult.errorList || []
if (data.length === 0) {
this.notifyWarning('暂无错误记录')
return
}
const exportData = data.map(item => {
return {
'excel序号': item.no,
'年度': item.year,
'线路名称': item.lineName,
'旅行社编号': item.travelAgencySerialNumber,
'旅行社地点': item.travelAgencyPlace,
'线路类型': item.regionalNature,
'成团类型': item.groupType,
'时间标段': item.lotName,
'预计费用': item.estimatedCost,
'最多报名人数': item.maxGroupSize,
'未导入原因': item.errors
}
})
const workbook = XLSX.utils.book_new()
const worksheet = XLSX.utils.json_to_sheet(exportData)
XLSX.utils.book_append_sheet(workbook, worksheet, '错误记录')
const excelBuffer = XLSX.write(workbook, {bookType: 'xlsx', type: 'array'})
const blob = new Blob([excelBuffer], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'})
const url = window.URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = url
link.download = '线路导入错误记录.xlsx'
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
window.URL.revokeObjectURL(url)
},
handleChangeYear() {
if (this.pageForm.startYear && this.pageForm.endYear) {
if (this.pageForm.startYear > this.pageForm.endYear) {
@@ -344,7 +344,7 @@ layout("/layouts/platform.html"){
title="参加人员补录"
:visible.sync="supplementVisible"
:close-on-click-modal="false"
width="50%">
width="65%">
<el-timeline>
<el-timeline-item timestamp="选择线路" placement="top">
<el-card>
@@ -383,6 +383,16 @@ layout("/layouts/platform.html"){
</el-form>
</el-card>
</el-timeline-item>
<el-timeline-item placement="top" timestamp="导入结果">
<el-card shadow="never">
<p>总记录数:{{supplementResult.totalCount}}</p>
<p>成功数:<span class="text-success">{{supplementResult.successCount}}</span></p>
<p>失败数:<span class="text-danger">{{supplementResult.errorCount}}</span></p>
<el-link @click="openSupplementError" type="primary"
v-if="supplementResult.errorCount>0">查看错误记录
</el-link>
</el-card>
</el-timeline-item>
</el-timeline>
<span slot="footer" class="dialog-footer">
@@ -390,6 +400,23 @@ layout("/layouts/platform.html"){
<el-button type="primary" @click="doSupplementImport" :loading="supplementLoading">确定</el-button>
</span>
</el-dialog>
<el-dialog title="补录错误记录" :visible.sync="supplementErrorVisible" append-to-body
:close-on-click-modal="false" width="75%">
<div style="text-align: right; margin-bottom: 10px">
<el-button size="small" type="primary" icon="el-icon-download"
@click="exportSupplementErrors">下载错误记录
</el-button>
</div>
<el-table :data="supplementResult.errorList" size="small" border>
<el-table-column label="excel序号" prop="no" width="100px"></el-table-column>
<el-table-column label="工号" prop="loginName" width="120px"></el-table-column>
<el-table-column label="姓名" prop="userName" width="120px"></el-table-column>
<el-table-column label="参加时间" prop="takePartInTime" width="120px"></el-table-column>
<el-table-column label="标段时间" prop="lotName" width="120px"></el-table-column>
<el-table-column label="未导入原因" prop="errors" show-overflow-tooltip></el-table-column>
</el-table>
</el-dialog>
</div>
<script>
@@ -439,11 +466,19 @@ layout("/layouts/platform.html"){
fileList: []
},
supplementVisible: false,
supplementErrorVisible: false,
supplementLoading: false,
supplementLines: [],
supplementData: {
takePartInLineId: '',
fileList: []
},
supplementResult: {
totalCount: 0,
successCount: 0,
errorCount: 0,
successList: [],
errorList: []
}
}
},
@@ -563,14 +598,17 @@ layout("/layouts/platform.html"){
openSupplementImport() {
this.$set(this.supplementData, 'takePartInLineId', this.pageForm.takePartInLineId || '')
this.$set(this.supplementData, 'fileList', [])
this.resetSupplementResult()
this.getSupplementLines()
this.$set(this, 'supplementVisible', true)
},
handleSupplementFileRemove(file, fileList) {
this.$set(this.supplementData, 'fileList', this.fileHandleRemove(file, fileList))
this.resetSupplementResult()
},
handleSupplementFileChange(file, fileList) {
this.$set(this.supplementData, 'fileList', this.fileHandleChange(file, fileList, {type: ['xls', 'xlsx']}))
this.resetSupplementResult()
},
doSupplementImport() {
if (!this.supplementData.takePartInLineId) {
@@ -595,9 +633,16 @@ layout("/layouts/platform.html"){
contentType: false,
success: (resp) => {
if (resp.code === 0) {
this.$set(this, 'supplementVisible', false)
this.$message.success(resp.msg || resp.data || '补录成功')
this.doSearch()
const result = resp.data || this.emptySupplementResult()
this.$set(this, 'supplementResult', result)
if (result.successCount > 0) {
this.doSearch()
}
if (result.errorCount > 0) {
this.$message.warning(resp.msg || '补录完成,存在未导入人员')
} else {
this.$message.success(resp.msg || '补录成功')
}
} else {
this.$message.warning(resp.msg)
}
@@ -611,8 +656,55 @@ layout("/layouts/platform.html"){
},
supplementVisibleClose() {
this.$set(this, 'supplementVisible', false)
this.$set(this, 'supplementErrorVisible', false)
this.doSearch()
},
emptySupplementResult() {
return {
totalCount: 0,
successCount: 0,
errorCount: 0,
successList: [],
errorList: []
}
},
resetSupplementResult() {
this.$set(this, 'supplementResult', this.emptySupplementResult())
this.$set(this, 'supplementErrorVisible', false)
},
openSupplementError() {
this.$set(this, 'supplementErrorVisible', true)
},
exportSupplementErrors() {
const data = this.supplementResult.errorList || []
if (data.length === 0) {
this.$message.warning('暂无错误记录')
return
}
const exportData = data.map(item => {
return {
'excel序号': item.no,
'工号': item.loginName,
'姓名': item.userName,
'参加时间': item.takePartInTime,
'标段时间': item.lotName,
'未导入原因': item.errors
}
})
const workbook = XLSX.utils.book_new()
const worksheet = XLSX.utils.json_to_sheet(exportData)
XLSX.utils.book_append_sheet(workbook, worksheet, '错误记录')
const excelBuffer = XLSX.write(workbook, {bookType: 'xlsx', type: 'array'})
const blob = new Blob([excelBuffer], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'})
const url = window.URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = url
link.download = '补录错误记录.xlsx'
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
window.URL.revokeObjectURL(url)
},
getSupplementLines() {
$.post('/platform/theRapyRecuperation/schoolUnionUserQuery/supplementLineList', {
year: this.pageForm.year,