From 4c03b389d487eec22e6084a638a1210c78bce50a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B0=8C=E5=85=88=E8=88=9C?= <2499071264@qq.com> Date: Mon, 26 Oct 2026 15:27:53 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20v3=E7=89=88=E7=96=97=E4=BC=91=E5=85=BB?= =?UTF-8?q?=E4=BC=98=E5=8C=965?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + .../旅行社导入模板.xlsx | Bin 0 -> 8767 bytes .../commons/ext/websocket/WkWebSocket.java | 3 +- .../ext/websocket/WkWsConfigurator.java | 20 ++ .../TherapyWorkspaceController.java | 2 +- .../TheRapyRecuperationLineController.java | 20 ++ ...apyRecuperationTravelAgencyController.java | 210 ++++++++++++++---- .../mode/TheRapyTravelAgencyExcelMode.java | 3 + .../therapyRecuperation/component.js | 4 +- .../therapyRecuperation/basicManage/line.html | 39 ++-- .../basicManage/travelAgency.html | 51 +++-- .../therapyRecuperation/index.html | 2 +- 12 files changed, 266 insertions(+), 89 deletions(-) create mode 100644 outputs/therapy_travel_agency_20261026/旅行社导入模板.xlsx create mode 100644 src/main/java/com/budwk/app/web/commons/ext/websocket/WkWsConfigurator.java diff --git a/.gitignore b/.gitignore index ff490a0..ce1d174 100644 --- a/.gitignore +++ b/.gitignore @@ -49,3 +49,4 @@ Thumbs.db .trae/pr-creator/SKILL.md .trae/update-docs/SKILL.md .trae/webapp-testing/SKILL.md +outputs \ No newline at end of file diff --git a/outputs/therapy_travel_agency_20261026/旅行社导入模板.xlsx b/outputs/therapy_travel_agency_20261026/旅行社导入模板.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..2a4c51e93eb520881a27225fe6cc663b984ec45e GIT binary patch literal 8767 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 tabs = new ArrayList<>(); - String[][] groups = {{"line", "base"}, {"overview", "cluster", "adjustment"}, + String[][] groups = {{"overview", "cluster", "adjustment"}, {"branchQuery", "branchAudit", "travelAudit"}, {"userQuery", "schoolAudit", "import"}}; for (String[] group : groups) { if (Arrays.asList(group).contains(screen)) { diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/basicManage/TheRapyRecuperationLineController.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/basicManage/TheRapyRecuperationLineController.java index aa17112..d7ddab1 100644 --- a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/basicManage/TheRapyRecuperationLineController.java +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/basicManage/TheRapyRecuperationLineController.java @@ -10,6 +10,8 @@ import cn.hutool.core.io.FileUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import com.budwk.app.base.result.Result; +import com.budwk.app.base.utils.SysOfficeTemplateUtil; +import com.budwk.app.sys.models.Sys_office_template; import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn; import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext; import com.budwk.app.base.param.PageForm; @@ -66,6 +68,7 @@ import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; +import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; @@ -104,6 +107,23 @@ public class TheRapyRecuperationLineController { private TheRapyRecuperationLineService lineService; @Inject private Dao dao; + @Inject + private SysOfficeTemplateUtil sysOfficeTemplateUtil; + + @At + @Ok("void") + @SaCheckPermission("inclusiveTherapyV3.line") + public void downloadTemplate(HttpServletResponse response) throws IOException { + String templateCode = "inclusive_therapy_v3_line_import"; + try (InputStream in = sysOfficeTemplateUtil.getTemplate(templateCode)) { + Sys_office_template template = dao.fetch(Sys_office_template.class, Cnd.where("templateCode", "=", templateCode)); + TherapyDownload.excelResponse(response, template.getTemplateName()); + if (template.getTemplateName().toLowerCase(Locale.ROOT).endsWith(".xls")) { + response.setContentType("application/vnd.ms-excel"); + } + in.transferTo(response.getOutputStream()); + } + } @At("") @Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/basicManage/line.html") diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/basicManage/TheRapyRecuperationTravelAgencyController.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/basicManage/TheRapyRecuperationTravelAgencyController.java index 401a291..f3d9501 100644 --- a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/basicManage/TheRapyRecuperationTravelAgencyController.java +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/basicManage/TheRapyRecuperationTravelAgencyController.java @@ -1,10 +1,11 @@ package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.basicManage; -import cn.afterturn.easypoi.excel.ExcelImportUtil; -import cn.afterturn.easypoi.excel.entity.ImportParams; import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.StrUtil; import com.budwk.app.base.result.Result; +import com.budwk.app.base.utils.SysOfficeTemplateUtil; +import com.budwk.app.sys.models.Sys_office_template; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyDownload; import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn; import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.PageUtil; import com.budwk.app.base.param.PageForm; @@ -14,13 +15,11 @@ import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecupe import lombok.extern.slf4j.Slf4j; import cn.dev33.satoken.annotation.SaCheckLogin; import cn.dev33.satoken.annotation.SaCheckPermission; -import org.nutz.aop.interceptor.ioc.TransAop; import org.nutz.dao.Cnd; import org.nutz.dao.Dao; import org.nutz.dao.Sqls; import org.nutz.dao.sql.Sql; import org.nutz.dao.util.cri.SqlExpressionGroup; -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; @@ -32,7 +31,20 @@ import org.nutz.mvc.upload.UploadAdaptor; import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; +import org.nutz.trans.Trans; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellType; +import org.apache.poi.ss.usermodel.CellValue; +import org.apache.poi.ss.usermodel.DataFormatter; +import org.apache.poi.ss.usermodel.FormulaEvaluator; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.usermodel.WorkbookFactory; +import java.math.BigDecimal; +import java.io.IOException; +import java.io.InputStream; +import javax.servlet.http.HttpServletResponse; /** @@ -51,6 +63,8 @@ public class TheRapyRecuperationTravelAgencyController { private TheRapyRecuperationTravelAgencyService travelAgencyService; @Inject private Dao dao; + @Inject + private SysOfficeTemplateUtil sysOfficeTemplateUtil; @At("") @Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/basicManage/travelAgency.html") @@ -58,6 +72,21 @@ public class TheRapyRecuperationTravelAgencyController { public void index() { } + @At + @Ok("void") + @SaCheckPermission("inclusiveTherapyV3.travelAgency") + public void downloadTemplate(HttpServletResponse response) throws IOException { + String templateCode = "inclusive_therapy_v3_travel_agency_import"; + try (InputStream in = sysOfficeTemplateUtil.getTemplate(templateCode)) { + Sys_office_template template = dao.fetch(Sys_office_template.class, Cnd.where("templateCode", "=", templateCode)); + TherapyDownload.excelResponse(response, template.getTemplateName()); + if (template.getTemplateName().toLowerCase(java.util.Locale.ROOT).endsWith(".xls")) { + response.setContentType("application/vnd.ms-excel"); + } + in.transferTo(response.getOutputStream()); + } + } + /** * 页面数据 * @@ -211,9 +240,8 @@ public class TheRapyRecuperationTravelAgencyController { */ @At @ViReturn - @SaCheckLogin + @SaCheckPermission("inclusiveTherapyV3.travelAgency") @AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"}) - @Aop(TransAop.READ_COMMITTED) public Object travelAgencyImport(TempFile file) { if (Lang.isEmpty(file)) { return Result.error("上传的文件不能为空"); @@ -222,58 +250,146 @@ public class TheRapyRecuperationTravelAgencyController { if (!List.of("xls", "xlsx").contains(extName.toLowerCase())) { return Result.error("请上传xls,xlsx文件"); } - List excelList; + List excelList = new ArrayList<>(); + List excelRowNumbers = new ArrayList<>(); - try { - ImportParams importParams = new ImportParams(); -// importParams.setTitleRows(1); - excelList = ExcelImportUtil.importExcel(file.getFile(), TheRapyTravelAgencyExcelMode.class, importParams); + try (Workbook workbook = WorkbookFactory.create(file.getFile())) { + Sheet sheet = workbook.getSheetAt(0); + Row header = sheet.getRow(0); + if (header == null) return Result.error("第一行必须是模板表头"); + DataFormatter formatter = new DataFormatter(); + FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator(); + Map headers = new java.util.LinkedHashMap<>(); + for (Cell cell : header) { + String name = formatter.formatCellValue(cell).trim().replace("(可填)", "").replace("(可填)", ""); + if ("编号".equals(name)) name = "排序编号"; + if ("是否启用".equals(name)) name = "是否启用(是/否)"; + if (StrUtil.isBlank(name)) continue; + if (headers.putIfAbsent(name, cell.getColumnIndex()) != null) return Result.error("模板表头重复:" + name); + } + for (String name : List.of("年度", "排序编号", "旅行社名称", "是否自由组团(是/否)", "旅行社联系人", "联系电话")) { + if (!headers.containsKey(name)) return Result.error("模板缺少必填列:" + name); + } + for (int rowIndex = 1; rowIndex <= sheet.getLastRowNum(); rowIndex++) { + Row dataRow = sheet.getRow(rowIndex); + if (dataRow == null) continue; + Map values = new java.util.HashMap<>(); + for (Map.Entry column : headers.entrySet()) { + Cell cell = dataRow.getCell(column.getValue()); + String value = formatter.formatCellValue(cell, evaluator).trim(); + if (cell != null && ("年度".equals(column.getKey()) || "最多承担人数".equals(column.getKey()))) { + CellValue evaluated = evaluator.evaluate(cell); + if (evaluated != null && evaluated.getCellType() == CellType.NUMERIC) { + value = BigDecimal.valueOf(evaluated.getNumberValue()).toPlainString(); + } + } + values.put(column.getKey(), value); + } + if (values.values().stream().allMatch(StrUtil::isBlank)) continue; + TheRapyTravelAgencyExcelMode travel = new TheRapyTravelAgencyExcelMode(); + try { + if (StrUtil.isNotBlank(values.get("年度"))) { + travel.setYear(new BigDecimal(values.get("年度")).intValueExact()); + } + } catch (NumberFormatException | ArithmeticException e) { + return Result.error("第" + (rowIndex + 1) + "行:年度须填写4位整数"); + } + try { + if (StrUtil.isNotBlank(values.get("最多承担人数"))) { + travel.setMaxUndertakeNumber(new BigDecimal(values.get("最多承担人数")).intValueExact()); + } + } catch (NumberFormatException | ArithmeticException e) { + return Result.error("第" + (rowIndex + 1) + "行:最多承担人数须填写有效整数"); + } + travel.setSerialNumber(values.get("排序编号")); + travel.setTravelAgencyName(values.get("旅行社名称")); + travel.setSignUpTravelAgency(values.get("是否自由组团(是/否)")); + travel.setContact(values.get("旅行社联系人")); + travel.setContactMobileNumber(values.get("联系电话")); + travel.setEmail(values.get("邮箱")); + travel.setOfficialWebsite(values.get("官网")); + travel.setNote(values.get("备注")); + travel.setIsDisabled(values.get("是否启用(是/否)")); + excelList.add(travel); + excelRowNumbers.add(rowIndex + 1); + } } catch (Exception e) { - log.error(e.getMessage()); - return Result.error("读取不到数据,请检查excel文件格式"); + log.error("读取旅行社导入文件失败", e); + return Result.error("读取失败,请使用新模板;年度和最多承担人数须填写整数"); } if (Lang.isEmpty(excelList)) { return Result.error("读取不到数据,请检查excel文件格式"); } + List list = new ArrayList<>(); + Map importedNumbers = new java.util.HashMap<>(); + for (int index = 0; index < excelList.size(); index++) { + TheRapyTravelAgencyExcelMode travel = excelList.get(index); + String row = "第" + excelRowNumbers.get(index) + "行:"; + travel.setSerialNumber(StrUtil.trim(travel.getSerialNumber())); + travel.setTravelAgencyName(StrUtil.trim(travel.getTravelAgencyName())); + travel.setContact(StrUtil.trim(travel.getContact())); + travel.setContactMobileNumber(StrUtil.trim(travel.getContactMobileNumber())); + travel.setSignUpTravelAgency(StrUtil.trim(travel.getSignUpTravelAgency())); + travel.setIsDisabled(StrUtil.trim(travel.getIsDisabled())); + travel.setEmail(StrUtil.trim(travel.getEmail())); + travel.setOfficialWebsite(StrUtil.trim(travel.getOfficialWebsite())); + if (travel.getYear() == null || travel.getYear() < 1000 || travel.getYear() > 9999) { + return Result.error(row + "年度须填写4位整数"); + } + if (StrUtil.isBlank(travel.getSerialNumber()) || StrUtil.isBlank(travel.getTravelAgencyName()) + || StrUtil.isBlank(travel.getContact()) || StrUtil.isBlank(travel.getContactMobileNumber())) { + return Result.error(row + "编号、旅行社名称、旅行社联系人和联系电话不能为空"); + } + if (!List.of("是", "否").contains(travel.getSignUpTravelAgency() == null ? "" : travel.getSignUpTravelAgency())) { + return Result.error(row + "是否自由组团须填写是或否"); + } + if (StrUtil.isBlank(travel.getIsDisabled())) travel.setIsDisabled("是"); + if (!List.of("是", "否").contains(travel.getIsDisabled())) return Result.error(row + "是否启用须填写是或否"); + if (!travel.getContactMobileNumber().matches("^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\\d{8}$")) { + return Result.error(row + "联系电话格式不正确"); + } + if (travel.getSerialNumber().length() > 50 || travel.getTravelAgencyName().length() > 50 + || travel.getContact().length() > 10 || StrUtil.length(travel.getEmail()) > 50 + || StrUtil.length(travel.getOfficialWebsite()) > 100 || StrUtil.length(travel.getNote()) > 100) { + return Result.error(row + "字段长度超限:编号/名称/邮箱最多50字,联系人10字,官网/备注100字"); + } + if (StrUtil.isNotBlank(travel.getEmail()) && !cn.hutool.core.lang.Validator.isEmail(travel.getEmail())) { + return Result.error(row + "邮箱格式不正确"); + } + if (StrUtil.isNotBlank(travel.getOfficialWebsite()) && !cn.hutool.core.lang.Validator.isUrl(travel.getOfficialWebsite())) { + return Result.error(row + "官网须填写完整网址"); + } + if (travel.getMaxUndertakeNumber() != null && travel.getMaxUndertakeNumber() < 0) { + return Result.error(row + "最多承担人数不能小于0"); + } + Integer previousRow = importedNumbers.putIfAbsent(travel.getSerialNumber(), excelRowNumbers.get(index)); + if (previousRow != null) return Result.error(row + "编号与第" + previousRow + "行重复"); + List existing = dao.query(TheRapyRecuperationTravelAgency.class, + Cnd.where("serialNumber", "=", travel.getSerialNumber())); + if (existing.size() > 1) return Result.error(row + "数据库中该编号对应多条旅行社记录"); + TheRapyRecuperationTravelAgency agency = existing.isEmpty() ? new TheRapyRecuperationTravelAgency() : existing.get(0); + agency.setDisabled("否".equals(travel.getIsDisabled())); + agency.setSignUpTravelAgency("是".equals(travel.getSignUpTravelAgency())); + agency.setContact(travel.getContact()); + agency.setTravelAgencyName(travel.getTravelAgencyName()); + agency.setSerialNumber(travel.getSerialNumber()); + agency.setEmail(travel.getEmail()); + agency.setMaxUndertakeNumber(travel.getMaxUndertakeNumber()); + agency.setContactMobileNumber(travel.getContactMobileNumber()); + agency.setNote(travel.getNote()); + agency.setYear(travel.getYear()); + agency.setOfficialWebsite(travel.getOfficialWebsite()); + list.add(agency); + } try { - if (excelList.stream().anyMatch(v -> StrUtil.isBlank(v.getYear().toString())) || excelList.stream().anyMatch(v -> StrUtil.isBlank(v.getTravelAgencyName()))) { - return Result.error("年度和旅行社名称不能为空"); - } - List travelAgency = ExcelImportUtil.importExcel(file.getFile(), TheRapyTravelAgencyExcelMode.class, new ImportParams()); - - List travelAgencyList = dao.query(TheRapyRecuperationTravelAgency.class, Cnd.NEW().desc("id")); - Map map = travelAgencyList.stream().collect(Collectors.toMap(v -> v.getTravelAgencyName(), v -> v.getId())); - - List list = new ArrayList<>(); - for (TheRapyTravelAgencyExcelMode travel : travelAgency) { - TheRapyRecuperationTravelAgency agency = new TheRapyRecuperationTravelAgency(); - if (Strings.isNotBlank(map.get(travel.getTravelAgencyName()))){ - agency.setId(map.get(travel.getTravelAgencyName())); - } - if (travel.getIsDisabled().equals("是")) { - agency.setDisabled(false); - } else if (travel.getIsDisabled().equals("否")) { - agency.setDisabled(true); - } - agency.setContact(travel.getContact()); - agency.setTravelAgencyName(travel.getTravelAgencyName()); - agency.setSerialNumber(travel.getSerialNumber()); - agency.setEmail(travel.getEmail()); - agency.setMaxUndertakeNumber(travel.getMaxUndertakeNumber()); - agency.setContactMobileNumber(travel.getContactMobileNumber()); - agency.setNote(travel.getNote()); - agency.setYear(travel.getYear()); - agency.setOfficialWebsite(travel.getOfficialWebsite()); - list.add(agency); - } - dao.insertOrUpdate(list); + Trans.exec(() -> dao.insertOrUpdate(list)); } catch (Exception e) { - log.error(e.getMessage()); + log.error("导入旅行社失败", e); return Result.error("导入旅行社失败"); } - return null; + return Result.success("成功导入" + list.size() + "条旅行社"); } } diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/mode/TheRapyTravelAgencyExcelMode.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/mode/TheRapyTravelAgencyExcelMode.java index 4d9a542..cfd15b3 100644 --- a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/mode/TheRapyTravelAgencyExcelMode.java +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/mode/TheRapyTravelAgencyExcelMode.java @@ -16,6 +16,9 @@ public class TheRapyTravelAgencyExcelMode { @Excel(name = "旅行社名称") private String travelAgencyName; + @Excel(name = "是否自由组团(是/否)") + private String signUpTravelAgency; + @Excel(name = "旅行社联系人") private String contact; diff --git a/src/main/resources/static/assets/staffbenefit/therapyRecuperation/component.js b/src/main/resources/static/assets/staffbenefit/therapyRecuperation/component.js index d3dc359..9bd09d7 100644 --- a/src/main/resources/static/assets/staffbenefit/therapyRecuperation/component.js +++ b/src/main/resources/static/assets/staffbenefit/therapyRecuperation/component.js @@ -109,7 +109,7 @@ Vue.component('table-tool', {
- {{ + {{ field.label }} @@ -126,4 +126,4 @@ Vue.component('table-tool', {
`, -}) \ No newline at end of file +}) diff --git a/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/basicManage/line.html b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/basicManage/line.html index 0993076..2e7a5d6 100644 --- a/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/basicManage/line.html +++ b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/basicManage/line.html @@ -153,9 +153,11 @@ layout("/platform/zhgh/staffbenefit/therapyRecuperation/layouts/platform.html"){ header-align="center" show-overflow-tooltip v-for="column in tableColumns" + :key="column.prop" > -