Commit 8539b86e9c6e047766bba290d379f4e8560be110

Authored by 王彪总
2 parents f41986d9 0b398542

Merge remote-tracking branch 'origin/dev'

urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/costfee/CostFeeController.java
... ... @@ -5,16 +5,24 @@ import com.zteits.urbanops.framework.excel.core.util.ExcelUtils;
5 5 import com.zteits.urbanops.module.garden.controller.admin.costfee.vo.WaterFeeImport;
6 6 import com.zteits.urbanops.module.garden.enums.TemplateEnum;
7 7 import com.zteits.urbanops.module.garden.service.costfee.CostFeeService;
  8 +import com.zteits.urbanops.module.system.api.dept.DeptApi;
  9 +import com.zteits.urbanops.module.system.api.dept.dto.DeptRespDTO;
8 10 import io.swagger.v3.oas.annotations.Operation;
9 11 import io.swagger.v3.oas.annotations.tags.Tag;
  12 +import jakarta.annotation.security.PermitAll;
10 13 import jakarta.servlet.http.HttpServletResponse;
11 14 import lombok.AllArgsConstructor;
12 15 import lombok.Data;
13 16 import lombok.extern.slf4j.Slf4j;
  17 +import org.apache.poi.ss.usermodel.*;
  18 +import org.apache.poi.ss.util.CellRangeAddressList;
  19 +import org.apache.poi.xssf.usermodel.XSSFWorkbook;
14 20 import org.springframework.beans.factory.annotation.Autowired;
15 21 import org.springframework.beans.factory.annotation.Value;
16   -import org.springframework.core.io.ClassPathResource;
  22 +import org.springframework.core.io.Resource;
  23 +import org.springframework.core.io.ResourceLoader;
17 24 import org.springframework.util.CollectionUtils;
  25 +import org.springframework.util.StringUtils;
18 26 import org.springframework.web.bind.annotation.*;
19 27 import org.springframework.web.multipart.MultipartFile;
20 28  
... ... @@ -23,7 +31,6 @@ import java.io.InputStream;
23 31 import java.io.OutputStream;
24 32 import java.lang.reflect.Method;
25 33 import java.net.URLEncoder;
26   -import java.nio.charset.StandardCharsets;
27 34 import java.util.*;
28 35  
29 36 import static com.zteits.urbanops.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST;
... ... @@ -49,6 +56,12 @@ public class CostFeeController{
49 56 @Value("${static.resource.server.enable}")
50 57 private Boolean staticResourceServerenable;
51 58  
  59 + @Autowired
  60 + private ResourceLoader resourceLoader;
  61 +
  62 + @jakarta.annotation.Resource
  63 + private DeptApi deptApi;
  64 +
52 65 // Excel文件校验相关
53 66 private static final List<String> ALLOWED_EXCEL_SUFFIX = Arrays.asList(".xlsx", ".xlsm");
54 67 private static final String EXCEL_MIME_TYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
... ... @@ -59,6 +72,7 @@ public class CostFeeController{
59 72 */
60 73 @GetMapping("/get-import-template")
61 74 @Operation(summary = "获得导入用户模板")
  75 + @PermitAll
62 76 public void importTemplate(HttpServletResponse response,
63 77 @RequestParam("templateName") String templateName) throws IOException {
64 78 // 参数校验
... ... @@ -74,29 +88,145 @@ public class CostFeeController{
74 88 return;
75 89 }
76 90  
77   - if (staticResourceServerenable) {
78   - // 构建完整的静态服务器URL(确保路径正确)
79   - String serverUrl = staticResourceServerUrl;
80   - if (serverUrl != null && !serverUrl.endsWith("/")) {
81   - serverUrl += "/"; // 确保URL以/结尾,避免拼接错误
82   - }
  91 + writeAndModifyTemplate(response, template.getName(), template.getStartIndex());
  92 + }
  93 +
  94 + private void writeAndModifyTemplate(HttpServletResponse response,
  95 + String downloadFileName,
  96 + int startIndexRow) throws IOException {
  97 +
  98 + // 拼接模板路径
  99 + String serverUrl = staticResourceServerUrl;
  100 + if (serverUrl != null && !serverUrl.endsWith("/")) {
  101 + serverUrl += "/";
  102 + }
  103 + String fullPath = serverUrl + downloadFileName;
  104 + fullPath = fullPath.replace("\\", "/");
83 105  
84   - String encodedFileName = URLEncoder.encode(template.getName().split("\\.")[0], StandardCharsets.UTF_8.name());
  106 + Resource resource = resourceLoader.getResource(fullPath);
85 107  
86   - String templateFileName = encodedFileName + "." + template.getName().split("\\.")[1];
  108 + // 检查文件是否存在
  109 + if (!resource.exists()) {
  110 + response.sendError(HttpServletResponse.SC_NOT_FOUND, "模板文件不存在");
  111 + return;
  112 + }
87 113  
88   - String templateUrl = serverUrl + templateFileName; // 包含templates目录
  114 + // 设置下载响应头
  115 + response.reset();
  116 + response.setContentType(EXCEL_MIME_TYPE);
  117 + // response.setCharacterEncoding("UTF-8");
  118 + String encodedName = URLEncoder.encode(downloadFileName, "UTF-8").replaceAll("\\+", "%20");
  119 + response.setHeader("Content-Disposition", "attachment;filename=" + encodedName);
  120 + response.setHeader("Cache-Control", "no-store"); // 禁止缓存
  121 +
  122 + try (InputStream in = resource.getInputStream();
  123 + XSSFWorkbook workbook = new XSSFWorkbook(in);
  124 + OutputStream out = response.getOutputStream()) {
89 125  
90   - // 方式1:重定向到静态资源服务器
91   - response.sendRedirect(templateUrl);
92   - } else {
93   - String templateFileName = templateName + "." + template.getName().split("\\.")[1];
  126 + Sheet sheet = workbook.getSheetAt(0);
94 127  
95   - // 写入模板文件到响应
96   - writeTemplateToResponse(response, template.getName(), templateFileName);
  128 + // ==============================================
  129 + // 获取最新单位列表
  130 + // ==============================================
  131 + List<DeptRespDTO> companyList = deptApi.getSubDeptList();
  132 + List<String> newUnits = companyList.stream()
  133 + .map(DeptRespDTO::getName)
  134 + .filter(Objects::nonNull)
  135 + .toList();
  136 +
  137 + log.info("加载到单位列表:{},共{}条", newUnits, newUnits.size());
  138 +
  139 + // ==============================================
  140 + // 生成新下拉 + 自动赋值
  141 + // ==============================================
  142 + createDropdownAndSetValue(sheet, newUnits, startIndexRow);
  143 +
  144 + // 写入并强制刷新
  145 + workbook.write(out);
  146 + out.flush();
  147 +
  148 + } catch (Exception e) {
  149 + log.error("模板处理失败", e);
  150 + throw new IOException("文件处理失败", e);
97 151 }
98 152 }
99 153  
  154 + /**
  155 + * 创建下拉框 + 给单元格赋值
  156 + */
  157 + private void createDropdownAndSetValue(Sheet sheet, List<String> options, int startRow) {
  158 + if (options.isEmpty()) {
  159 + log.error("下拉选项为空,不创建");
  160 + return;
  161 + }
  162 +
  163 + // 获取表头行
  164 + Row headerRow = sheet.getRow(startRow - 1);
  165 + if (headerRow == null) {
  166 + log.error("表头行不存在:{}", startRow - 1);
  167 + return;
  168 + }
  169 +
  170 + // 查找“所属单位”列
  171 + int targetCol = -1;
  172 + for (Cell cell : headerRow) {
  173 + if (cell != null && cell.getCellType() == CellType.STRING) {
  174 + String val = cell.getStringCellValue().trim();
  175 + if (val.contains("所属单位") || val.contains("所属公司") ) {
  176 + targetCol = cell.getColumnIndex();
  177 + break;
  178 + }
  179 + }
  180 + }
  181 +
  182 + if (targetCol == -1) {
  183 + log.error("未找到【所属单位】列表头");
  184 + return;
  185 + }
  186 +
  187 + // 取消列隐藏
  188 + sheet.setColumnHidden(targetCol, false);
  189 +
  190 + // ==============================================
  191 + // 遍历行:清空原有内容 + 设置默认值
  192 + // ==============================================
  193 + int endRow = 100;
  194 + for (int r = startRow; r <= endRow; r++) {
  195 + Row row = sheet.getRow(r);
  196 + if (row == null) {
  197 + row = sheet.createRow(r);
  198 + }
  199 +
  200 + Cell cell = row.getCell(targetCol);
  201 + if (cell == null) {
  202 + cell = row.createCell(targetCol);
  203 + }
  204 + String unit = cell.getStringCellValue();
  205 + // 默认赋值【第一个单位】,你可以根据业务改成其他值
  206 + if (!StringUtils.isEmpty(unit)) {
  207 + cell.setCellValue(options.get(2));
  208 + }
  209 + }
  210 +
  211 + // ==============================================
  212 + // 创建下拉框(作用范围:startRow ~ 1000行)
  213 + // ==============================================
  214 + CellRangeAddressList regions = new CellRangeAddressList(startRow, endRow, targetCol, targetCol);
  215 + DataValidationHelper helper = sheet.getDataValidationHelper();
  216 + DataValidationConstraint constraint = helper.createExplicitListConstraint(
  217 + options.toArray(new String[0])
  218 + );
  219 + DataValidation validation = helper.createValidation(constraint, regions);
  220 + // 下拉框基础配置
  221 + validation.setEmptyCellAllowed(true);
  222 + validation.setSuppressDropDownArrow(true); // 显示箭头
  223 + validation.setShowErrorBox(true);
  224 + validation.setShowPromptBox(true); // 启用点击弹出提示
  225 + sheet.addValidationData(validation);
  226 +
  227 + log.info("【成功】为列{}添加下拉并赋值,行{}~{},选项数:{}",
  228 + targetCol, startRow, endRow, options.size());
  229 + }
100 230  
101 231 /**
102 232 * Excel文件上传预览
... ... @@ -214,31 +344,6 @@ public class CostFeeController{
214 344 }
215 345  
216 346 /**
217   - * 写入模板文件到响应流
218   - */
219   - private void writeTemplateToResponse(HttpServletResponse response, String filename, String templatePath) throws IOException {
220   - // 设置响应头
221   - response.setContentType(EXCEL_MIME_TYPE);
222   - response.setCharacterEncoding("UTF-8");
223   - String encodedFileName = URLEncoder.encode(filename, "UTF-8").replaceAll("\\+", "%20");
224   - response.setHeader("Content-Disposition", "attachment;filename=" + encodedFileName);
225   - response.setHeader("Cache-Control", "no-store"); // 禁止缓存
226   -
227   - // 读取模板文件并写入响应
228   - try (InputStream in = new ClassPathResource("template/" + templatePath).getInputStream();
229   - OutputStream out = response.getOutputStream()) {
230   -
231   - byte[] buffer = new byte[4096];
232   - int bytesRead;
233   - while ((bytesRead = in.read(buffer)) != -1) {
234   - out.write(buffer, 0, bytesRead);
235   - }
236   - out.flush();
237   - }
238   - }
239   -
240   -
241   - /**
242 347 * 校验Excel文件有效性(后缀+MIME类型)
243 348 */
244 349 private boolean isValidExcelFile(MultipartFile file) {
... ...
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/convert/AppGardenWorkOrderConvert.java
... ... @@ -24,7 +24,7 @@ public interface AppGardenWorkOrderConvert {
24 24 orderReqVO.setPressingType(2);//紧急
25 25 orderReqVO.setOrderName(inspectionPlanDO.getPlanName());
26 26 orderReqVO.setSourceId(1);//来源ID 工单来源 1、巡查
27   - orderReqVO.setSourceName("园林巡查上报");
  27 + orderReqVO.setSourceName("巡查上报");
28 28 orderReqVO.setThirdWorkNo(planNo);
29 29 orderReqVO.setOrderType("C");
30 30 orderReqVO.setPressingType(createReqVO.getPressingType());
... ...
urbanops-module-workorder/src/main/java/com/zteits/urbanops/module/workorder/enums/BusiLineTeamLeaderRoleCodeEnum.java
... ... @@ -25,6 +25,10 @@ public enum BusiLineTeamLeaderRoleCodeEnum { // 注意:枚举类必须用enum
25 25 ROLECODE_WY("wy", "team_leader_wy"),
26 26 /** 市政业务线-角色编码 */
27 27 ROLECODE_SZ("sz", "team_leader_sz"),
  28 + /** 秩序管理业务线-角色编码 */
  29 + ROLECODE_ZX("zx", "team_leader_zxgl"),
  30 + /** 环境卫生业务线-角色编码 */
  31 + ROLECODE_HJ("hj", "team_leader_hjws"),
28 32 /** 园林业务线-角色编码 */
29 33 ROLECODE_YL("yl", "team_leader_yl"); // 最后一个常量必须以分号结尾
30 34  
... ...
urbanops-module-workorder/src/main/java/com/zteits/urbanops/module/workorder/enums/BusiLineWorkerRoleCodeEnum.java
... ... @@ -25,6 +25,10 @@ public enum BusiLineWorkerRoleCodeEnum {
25 25 ROLECODE_WORKER_WY("wy", "wy_worker"),
26 26 /** 市政业务线-角色编码 */
27 27 ROLECODE_WORKER_SZ("sz", "sz_worker"),
  28 + /** 环境卫生业务线-角色编码 */
  29 + ROLECODE_HJ("hj", "hjws_worker"),
  30 + /** 秩序管理业务线-角色编码 */
  31 + ROLECODE_ZX("zx", "zxgl_worker"),
28 32 /** 园林业务线-角色编码 */
29 33 ROLECODE_WORKER_YL("yl", "yl_worker"); // 最后一个常量必须以分号结尾
30 34  
... ...