commit
This commit is contained in:
+24
-69
@@ -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
|
||||
|
||||
+28
-95
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+43
@@ -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;
|
||||
}
|
||||
+10
@@ -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);
|
||||
}
|
||||
|
||||
+12
@@ -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);
|
||||
}
|
||||
|
||||
+96
-17
@@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+274
-1
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 目标年度中已存在同名、同旅行社、同标段、同区域性质的校工会组织线路时,不再重复复制。
|
||||
*
|
||||
|
||||
+214
@@ -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>
|
||||
|
||||
+125
-19
@@ -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) {
|
||||
|
||||
+96
-4
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user