ソースを参照

材料库清单功能部分提交

徐滕 3 日 前
コミット
1a8164a9d3
33 ファイル変更1545 行追加339 行削除
  1. 327 0
      src/main/java/com/jeeplus/common/utils/excel/ExportMultipleTabsExcel.java
  2. 3 0
      src/main/java/com/jeeplus/common/utils/excel/annotation/ExcelField.java
  3. 45 32
      src/main/java/com/jeeplus/modules/API/sys/RegisterMobileController.java
  4. 21 0
      src/main/java/com/jeeplus/modules/projectmaterialstorage/dao/ProjectMaterialStorageDao.java
  5. 19 0
      src/main/java/com/jeeplus/modules/projectmaterialstorage/entity/ProjectMaterialStorage.java
  6. 19 0
      src/main/java/com/jeeplus/modules/projectmaterialstorage/entity/ProjectMaterialStorageImport.java
  7. 293 0
      src/main/java/com/jeeplus/modules/projectmaterialstorage/service/ProjectMaterialStorageService.java
  8. 158 65
      src/main/java/com/jeeplus/modules/projectmaterialstorage/web/ProjectMaterialStorageController.java
  9. 0 11
      src/main/java/com/jeeplus/modules/ruralprojectrecords/web/RuralProjectMessageAllController.java
  10. 0 2
      src/main/java/com/jeeplus/modules/ruralprojectrecords/web/RuralProjectSignatureOldMessageDisposeController.java
  11. 56 6
      src/main/java/com/jeeplus/modules/sys/utils/ALiYunSmsUtil.java
  12. 22 18
      src/main/java/com/jeeplus/modules/sys/web/LoginController.java
  13. 39 24
      src/main/java/com/jeeplus/modules/sys/web/RegisterController.java
  14. 9 7
      src/main/java/com/jeeplus/modules/syswarning/service/SysWarningService.java
  15. 1 1
      src/main/java/com/jeeplus/modules/workprojectnotify/web/WorkProjectNotifyController.java
  16. 38 0
      src/main/java/com/jeeplus/modules/workstaff/service/WorkStaffBasicInfoService.java
  17. 6 1
      src/main/java/com/jeeplus/modules/workstaff/web/WorkStaffBasicInfoController.java
  18. 60 1
      src/main/resources/mappings/modules/projectMaterialStorage/ProjectMaterialStorageDao.xml
  19. 5 3
      src/main/resources/mappings/modules/sys/UserDao.xml
  20. 5 3
      src/main/resources/mappings/modules/workstaff/WorkStaffBasicInfoDao.xml
  21. BIN
      src/main/webapp/dot/材料库处理表模板.xlsx
  22. 5 5
      src/main/webapp/webpage/modules/projectMaterialStorage/projectMaterialStorageAddForm.jsp
  23. 3 3
      src/main/webapp/webpage/modules/projectMaterialStorage/projectMaterialStorageList.jsp
  24. 4 4
      src/main/webapp/webpage/modules/projectMaterialStorage/projectMaterialStorageTwoForm.jsp
  25. 1 1
      src/main/webapp/webpage/modules/workinvoice/workInvoiceAuditEnd.jsp
  26. 1 1
      src/main/webapp/webpage/modules/workinvoice/workInvoiceModify.jsp
  27. 169 101
      src/main/webapp/webpage/modules/workstaff/qualificationForm.jsp
  28. 100 11
      src/main/webapp/webpage/modules/workstaff/workStaffBasicDetailForm.jsp
  29. 103 12
      src/main/webapp/webpage/modules/workstaff/workStaffBasicDetailModify.jsp
  30. 1 1
      src/main/webapp/webpage/modules/workstaff/workStaffBasicInfoDimissionList.jsp
  31. 3 3
      src/main/webapp/webpage/modules/workstaff/workStaffBasicInfoEmploymentInList.jsp
  32. 1 0
      src/main/webapp/webpage/modules/workstaff/workStaffBasicInfoForm.jsp
  33. 28 23
      src/main/webapp/webpage/modules/workstaff/workStaffBasicInfoView.jsp

+ 327 - 0
src/main/java/com/jeeplus/common/utils/excel/ExportMultipleTabsExcel.java

@@ -0,0 +1,327 @@
+package com.jeeplus.common.utils.excel;
+
+import com.jeeplus.common.utils.excel.annotation.ExcelField;
+import com.jeeplus.modules.sys.utils.DictUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xssf.streaming.SXSSFWorkbook;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import java.text.SimpleDateFormat;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.*;
+
+/**
+ * 支持多Sheet的Excel导出工具类
+ */
+/**
+ * 多页签Excel导出工具类
+ * 支持创建多个Sheet页,每个页签可独立设置名称和数据
+ */
+/**
+ * 支持多Sheet的Excel导出工具类
+ */
+public class ExportMultipleTabsExcel {
+	private static final Logger log = LoggerFactory.getLogger(ExportMultipleTabsExcel.class);
+	private Workbook workbook; // 共享的工作簿
+	private Map<String, SheetData> sheetDataMap = new HashMap<>(); // 存储各Sheet的数据
+
+	/**
+	 * 内部类:存储单个Sheet的数据
+	 */
+	private static class SheetData {
+		String sheetName;
+		String title;
+		Class<?> entityClass;
+		List<?> dataList;
+		List<Object[]> annotationList; // 存储ExcelField注解信息
+		int rownum = 0; // 当前行号
+
+		public SheetData(String sheetName, String title, Class<?> entityClass) {
+			this.sheetName = sheetName;
+			this.title = title;
+			this.entityClass = entityClass;
+			this.annotationList = initAnnotationList(entityClass);
+		}
+
+		// 初始化注解列表
+		private List<Object[]> initAnnotationList(Class<?> cls) {
+			List<Object[]> list = new ArrayList<>();
+			// 处理字段注解
+			Field[] fields = cls.getDeclaredFields();
+			for (Field field : fields) {
+				ExcelField ef = field.getAnnotation(ExcelField.class);
+				if (ef != null && (ef.type() == 0 || ef.type() == 1)) {
+					list.add(new Object[]{ef, field});
+				}
+			}
+			// 处理方法注解
+			Method[] methods = cls.getDeclaredMethods();
+			for (Method method : methods) {
+				ExcelField ef = method.getAnnotation(ExcelField.class);
+				if (ef != null && (ef.type() == 0 || ef.type() == 1)) {
+					list.add(new Object[]{ef, method});
+				}
+			}
+			// 按排序号排序
+			list.sort(Comparator.comparingInt(o -> ((ExcelField) o[0]).sort()));
+			return list;
+		}
+	}
+
+	/**
+	 * 构造函数:初始化工作簿
+	 */
+	public ExportMultipleTabsExcel() {
+		this.workbook = new SXSSFWorkbook(1000); // 内存中保留1000行,适合大数据量
+	}
+
+	/**
+	 * 添加一个Sheet页
+	 */
+	public void addSheet(String sheetName, String title, Class<?> entityClass, List<?> dataList) {
+		SheetData sheetData = new SheetData(sheetName, title, entityClass);
+		sheetData.dataList = dataList;
+		sheetDataMap.put(sheetName, sheetData);
+	}
+
+	/**
+	 * 创建单元格样式
+	 */
+	private Map<String, CellStyle> createStyles(Workbook wb) {
+		Map<String, CellStyle> styles = new HashMap<>();
+
+		// 标题样式
+		CellStyle style = wb.createCellStyle();
+		style.setAlignment(HorizontalAlignment.CENTER);
+		style.setVerticalAlignment(VerticalAlignment.CENTER);
+		style.setBorderBottom(BorderStyle.THIN);
+		style.setBorderLeft(BorderStyle.THIN);
+		style.setBorderRight(BorderStyle.THIN);
+		style.setBorderTop(BorderStyle.THIN);
+		Font titleFont = wb.createFont();
+		titleFont.setFontName("宋体");
+		titleFont.setFontHeightInPoints((short) 16);
+		titleFont.setBold(true);
+		style.setFont(titleFont);
+		styles.put("title", style);
+
+		// 表头样式(无边框 + 更深底色 + 白色字体)
+		style = wb.createCellStyle();
+		style.setAlignment(HorizontalAlignment.CENTER);
+		style.setVerticalAlignment(VerticalAlignment.CENTER);
+		style.setBorderBottom(BorderStyle.NONE);
+		style.setBorderLeft(BorderStyle.NONE);
+		style.setBorderRight(BorderStyle.NONE);
+		style.setBorderTop(BorderStyle.NONE);
+		style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex());
+		style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+		Font headerFont = wb.createFont();
+		headerFont.setFontName("宋体");
+		headerFont.setFontHeightInPoints((short) 11);
+		headerFont.setBold(true);
+		headerFont.setColor(IndexedColors.WHITE.getIndex()); // 白色字体
+		style.setFont(headerFont);
+		styles.put("header", style);
+
+		// 数据单元格样式(区分字符串和数字对齐)
+		// 字符串居中样式
+		CellStyle stringStyle = wb.createCellStyle();
+		stringStyle.setAlignment(HorizontalAlignment.CENTER);
+		stringStyle.setVerticalAlignment(VerticalAlignment.CENTER);
+		stringStyle.setBorderBottom(BorderStyle.THIN);
+		stringStyle.setBorderLeft(BorderStyle.THIN);
+		stringStyle.setBorderRight(BorderStyle.THIN);
+		stringStyle.setBorderTop(BorderStyle.THIN);
+		Font stringFont = wb.createFont();
+		stringFont.setFontName("宋体");
+		stringFont.setFontHeightInPoints((short) 11);
+		stringStyle.setFont(stringFont);
+		styles.put("data_string", stringStyle);
+
+		// 数字靠右样式
+		CellStyle numberStyle = wb.createCellStyle();
+		numberStyle.setAlignment(HorizontalAlignment.RIGHT);
+		numberStyle.setVerticalAlignment(VerticalAlignment.CENTER);
+		numberStyle.setBorderBottom(BorderStyle.THIN);
+		numberStyle.setBorderLeft(BorderStyle.THIN);
+		numberStyle.setBorderRight(BorderStyle.THIN);
+		numberStyle.setBorderTop(BorderStyle.THIN);
+		Font numberFont = wb.createFont();
+		numberFont.setFontName("宋体");
+		numberFont.setFontHeightInPoints((short) 11);
+		numberStyle.setFont(numberFont);
+		styles.put("data_number", numberStyle);
+
+		return styles;
+	}
+
+	/**
+	 * 生成Excel文件
+	 */
+	public void write(OutputStream os) throws IOException {
+		for (SheetData sheetData : sheetDataMap.values()) {
+			createSheetContent(sheetData);
+		}
+		// 写入输出流
+		workbook.write(os);
+	}
+
+	/**
+	 * 创建单个Sheet的内容
+	 */
+	private void createSheetContent(SheetData sheetData) {
+		Sheet sheet = workbook.createSheet(sheetData.sheetName);
+		Map<String, CellStyle> styles = createStyles(workbook);
+		List<Object[]> annotationList = sheetData.annotationList;
+		int rownum = sheetData.rownum;
+
+		// 创建标题行
+		if (StringUtils.isNotBlank(sheetData.title)) {
+			Row titleRow = sheet.createRow(rownum++);
+			titleRow.setHeightInPoints(30);
+			Cell titleCell = titleRow.createCell(0);
+			titleCell.setCellStyle(styles.get("title"));
+			titleCell.setCellValue(sheetData.title);
+			sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, annotationList.size() - 1));
+		}
+
+		// 创建表头行
+		Row headerRow = sheet.createRow(rownum++);
+		headerRow.setHeightInPoints(18);
+		for (int i = 0; i < annotationList.size(); i++) {
+			Object[] os = annotationList.get(i);
+			ExcelField ef = (ExcelField) os[0];
+			String header = ef.title();
+
+			// 估算列宽:中文字符每个占2个字符宽度,英文字符每个占1个
+			int width = 0;
+			for (char c : header.toCharArray()) {
+				width += (c > 127) ? 2 : 1;
+			}
+			// 最小宽度为10,最大为50
+			width = Math.max(width, 10);
+			width = Math.min(width, 50);
+			sheet.setColumnWidth(i, width * 256 * 2); // 设置列宽
+
+			// 新增:创建表头单元格并设置标题值
+			Cell headerCell = headerRow.createCell(i);
+			headerCell.setCellStyle(styles.get("header"));
+			headerCell.setCellValue(header);
+		}
+
+		// 填充数据行(区分字符串和数字对齐)
+		if (sheetData.dataList != null && !sheetData.dataList.isEmpty()) {
+			for (Object obj : sheetData.dataList) {
+				Row dataRow = sheet.createRow(rownum++);
+				dataRow.setHeightInPoints(16);
+				for (int i = 0; i < annotationList.size(); i++) {
+					Object[] os = annotationList.get(i);
+					ExcelField ef = (ExcelField) os[0];
+					Cell cell = dataRow.createCell(i);
+
+					// 获取单元格值
+					Object value = getFieldValue(obj, ef, os);
+
+					// 根据值的类型设置对齐样式
+					if (value instanceof Number) {
+						cell.setCellStyle(styles.get("data_number")); // 数字靠右
+					} else {
+						cell.setCellStyle(styles.get("data_string")); // 字符串居中
+					}
+
+					// 设置单元格值
+					setCellValue(cell, value, ef);
+				}
+			}
+		}
+	}
+
+	/**
+	 * 使用标准反射获取字段值
+	 */
+	private Object getFieldValue(Object obj, ExcelField ef, Object[] os) {
+		try {
+			String fieldName = ef.value();
+			if (StringUtils.isBlank(fieldName)) {
+				if (os[1] instanceof Field) {
+					fieldName = ((Field) os[1]).getName();
+				} else if (os[1] instanceof Method) {
+					Method method = (Method) os[1];
+					return method.invoke(obj);
+				}
+			}
+
+			// 调用getter方法
+			if (StringUtils.isNotBlank(fieldName)) {
+				String getterMethod = "get" + fieldName.substring(0, 1).toUpperCase()
+						+ fieldName.substring(1);
+				Method method = obj.getClass().getMethod(getterMethod);
+				Object value = method.invoke(obj);
+
+				// 处理字典转换
+				if (StringUtils.isNotBlank(ef.dictType())) {
+					return DictUtils.getDictLabel(value == null ? "" : value.toString(), ef.dictType(), "");
+				}
+				return value;
+			}
+		} catch (Exception e) {
+			log.error("获取字段值失败", e);
+		}
+		return "";
+	}
+
+	/**
+	 * 设置单元格值(处理不同数据类型)
+	 */
+	private void setCellValue(Cell cell, Object value, ExcelField ef) {
+		if (value == null) {
+			cell.setCellValue("");
+			return;
+		}
+
+		// 处理日期类型
+		if (value instanceof Date) {
+			String format = StringUtils.isNotBlank(ef.format()) ? ef.format() : "yyyy-MM-dd";
+			cell.setCellValue(new SimpleDateFormat(format).format((Date) value));
+		}
+		// 处理数字类型
+		else if (value instanceof Number) {
+			cell.setCellValue(((Number) value).doubleValue());
+		}
+		// 处理布尔类型
+		else if (value instanceof Boolean) {
+			cell.setCellValue((Boolean) value);
+		}
+		// 其他类型按字符串处理
+		else {
+			cell.setCellValue(value.toString());
+		}
+	}
+
+	/**
+	 * 输出到客户端下载
+	 */
+	public void write(HttpServletResponse response, String fileName) throws IOException {
+		response.reset();
+		response.setContentType("application/octet-stream; charset=utf-8");
+		response.setHeader("Content-Disposition", "attachment; filename="
+				+ new String(fileName.getBytes("utf-8"), "ISO-8859-1"));
+		write(response.getOutputStream());
+	}
+
+	/**
+	 * 清理临时文件(避免内存泄漏)
+	 */
+	public void dispose() {
+		if (workbook instanceof SXSSFWorkbook) {
+			((SXSSFWorkbook) workbook).dispose();
+		}
+	}
+}

+ 3 - 0
src/main/java/com/jeeplus/common/utils/excel/annotation/ExcelField.java

@@ -68,4 +68,7 @@ public @interface ExcelField {
      * @return
      */
     String valiName() default "";
+
+	// 添加format属性,用于日期格式化
+	String format() default "";  // 新增这一行
 }

+ 45 - 32
src/main/java/com/jeeplus/modules/API/sys/RegisterMobileController.java

@@ -17,6 +17,7 @@ import com.jeeplus.modules.sys.entity.Role;
 import com.jeeplus.modules.sys.entity.User;
 import com.jeeplus.modules.sys.service.DictService;
 import com.jeeplus.modules.sys.service.SystemService;
+import com.jeeplus.modules.sys.utils.ALiYunSmsUtil;
 import com.jeeplus.modules.sys.utils.DictUtils;
 import com.jeeplus.modules.sys.utils.UserUtils;
 import com.jeeplus.modules.tools.utils.TwoDimensionCode;
@@ -290,39 +291,51 @@ public class RegisterMobileController extends BaseController {
             }
 
             String randomCode = String.valueOf((int) (Math.random() * 9000 + 1000));
-            HashMap<String,Object> result =UserUtils.sendRandomCodes(mobile, randomCode);
-            String statusCode = (String) result.get("statusCode");
-                //if (result.contains("Success") && result.contains("ok")) {
-                if (("000000").equals(statusCode)) {
-                    j.setSuccess(true);
-                    j.setErrorCode(ErrorCode.code_1004);
-                    j.setMsg("短信发送成功!");
-                    Map<String,Object> map = new HashMap<>();
-                    map.put("randomCode",randomCode);
-                    map.put("type",type);
-                    map.put("mobile",mobile);
-                    j.put("data",map);
-                    logger.info("../f/getRandomCode/  randomCode=" + randomCode);
-                    jedis = JedisUtils.getResource();
-                    if(jedis.get(mobile)!=null && jedis.get(type)!=null){
-                        jedis.del(mobile);
-                        jedis.del(type);
-                    }
-                    jedis.set(mobile, randomCode);
-                    jedis.setex(mobile, 300, randomCode);
-                    jedis.set(type, type);
-               /* if(request.getSession().getServletContext().getAttribute(mobile)!=null && request.getSession().getServletContext().getAttribute(type)!=null){
-                    request.getSession().getServletContext().removeAttribute(mobile);
-                    request.getSession().getServletContext().removeAttribute(type);
-                }
-                request.getSession().getServletContext().setAttribute(mobile, randomCode);
-                request.getSession().getServletContext().setAttribute(type, type);*/
-                } else {
-                    j.setSuccess(false);
-                    j.setErrorCode(ErrorCode.code_1008);
-                    j.setMsg("短信发送失败,错误代码:101,请联系管理员。");
-                    j.put("ErrorXml",result);
+            HashMap<String,Object> result = ALiYunSmsUtil.updatePasswordSendSms(mobile, randomCode);
+            Integer statusCode = (Integer) result.get("statusCode");
+            if (200 == statusCode) {
+
+                j.setSuccess(true);
+                j.setErrorCode(ErrorCode.code_1004);
+                j.setMsg("短信发送成功!");
+                //存放验证码
+                Map<String,Object> map = new HashMap<>();
+                map.put("randomCode",randomCode);
+                map.put("type",type);
+                map.put("mobile",mobile);
+                j.put("data",map);
+                logger.info("../f/getRandomCode/  randomCode=" + randomCode);
+                jedis = JedisUtils.getResource();
+                if(jedis.get(mobile)!=null && jedis.get(type)!=null){
+                    jedis.del(mobile);
+                    jedis.del(type);
                 }
+                jedis.set(mobile, randomCode);
+                jedis.setex(mobile, 300, randomCode);
+                jedis.set(type, type);
+            }else if(10001 == statusCode){
+                j.setSuccess(false);
+                j.setErrorCode("2");
+                String message = (String) result.get("message");
+                //j.setMsg("短信发送失败,错误代码:"+result+",请联系管理员。");
+                j.setMsg(message);
+                j.put("ErrorXml",result);
+            }else if(10002 == statusCode){
+                j.setSuccess(false);
+                j.setErrorCode("2");
+                j.put("message","账户短信量余额不足,请联系管理员进行充值!");
+                j.put("ErrorXml",result);
+            }else if(10003 == statusCode){
+                j.setSuccess(false);
+                j.setErrorCode("2");
+                j.put("message","手机号获取验证码次数已达每日上限!");
+                j.put("ErrorXml",result);
+            }else{
+                j.setSuccess(false);
+                j.setErrorCode(ErrorCode.code_1008);
+                j.put("message","短信发送失败,错误代码:101,请联系管理员!");
+                j.put("ErrorXml",result);
+            }
 
 
         }catch (Exception e){

+ 21 - 0
src/main/java/com/jeeplus/modules/projectmaterialstorage/dao/ProjectMaterialStorageDao.java

@@ -48,4 +48,25 @@ public interface ProjectMaterialStorageDao extends CrudDao<ProjectMaterialStorag
     void deleteListById(@Param("idList")List<String> idList);
 
     List<ProjectMaterialStorage> getByIdList(@Param("idList")List<String> idList,@Param("createBy")String createBy);
+
+
+    /**
+     * 根据项目id查询数据
+     * @param projectId
+     * @return
+     */
+    List<ProjectMaterialStorageImport> getByProjectId(String projectId);
+
+
+    /**
+     * 材料库处理的批量插入
+     */
+    Integer saveUniqueInfo(ProjectMaterialStorageImport projectMaterialStorageImport);
+
+    /**
+     * 删除
+     * @param projectMaterialStorage
+     * @return
+     */
+    Integer deleteById(ProjectMaterialStorage projectMaterialStorage);
 }

+ 19 - 0
src/main/java/com/jeeplus/modules/projectmaterialstorage/entity/ProjectMaterialStorage.java

@@ -45,6 +45,9 @@ public class ProjectMaterialStorage extends DataEntity<ProjectMaterialStorage> {
 
     private String projectId; //报告号
 
+    private String distinctStr ; //用于去重用的临时参数
+    private String errorMessage ; //错误原因
+
 
     private String beginProjectPriceIncludingTax; //开始含税工程价(元)
     private String endProjectPriceIncludingTax; //结束含税工程价(元)
@@ -322,4 +325,20 @@ public class ProjectMaterialStorage extends DataEntity<ProjectMaterialStorage> {
     public void setStorageFlag(String storageFlag) {
         this.storageFlag = storageFlag;
     }
+
+    public String getDistinctStr() {
+        return distinctStr;
+    }
+
+    public void setDistinctStr(String distinctStr) {
+        this.distinctStr = distinctStr;
+    }
+
+    public String getErrorMessage() {
+        return errorMessage;
+    }
+
+    public void setErrorMessage(String errorMessage) {
+        this.errorMessage = errorMessage;
+    }
 }

+ 19 - 0
src/main/java/com/jeeplus/modules/projectmaterialstorage/entity/ProjectMaterialStorageImport.java

@@ -31,6 +31,9 @@ public class ProjectMaterialStorageImport extends DataEntity<ProjectMaterialStor
 
     private Project project;  //项目
 
+    private String distinctStr ; //用于去重用的临时参数
+    private String errorMessage ; //错误原因
+
     public String getProjectNumber() {
         return projectNumber;
     }
@@ -144,4 +147,20 @@ public class ProjectMaterialStorageImport extends DataEntity<ProjectMaterialStor
     public void setQuotedPriceDate(Date quotedPriceDate) {
         this.quotedPriceDate = quotedPriceDate;
     }
+
+    public String getDistinctStr() {
+        return distinctStr;
+    }
+
+    public void setDistinctStr(String distinctStr) {
+        this.distinctStr = distinctStr;
+    }
+
+    public String getErrorMessage() {
+        return errorMessage;
+    }
+
+    public void setErrorMessage(String errorMessage) {
+        this.errorMessage = errorMessage;
+    }
 }

+ 293 - 0
src/main/java/com/jeeplus/modules/projectmaterialstorage/service/ProjectMaterialStorageService.java

@@ -1,10 +1,12 @@
 package com.jeeplus.modules.projectmaterialstorage.service;
 
 
+import com.alibaba.fastjson.JSON;
 import com.google.common.collect.Lists;
 import com.jeeplus.common.persistence.Page;
 import com.jeeplus.common.service.CrudService;
 import com.jeeplus.common.utils.IdGen;
+import com.jeeplus.common.utils.JedisUtils;
 import com.jeeplus.common.utils.StringUtils;
 import com.jeeplus.modules.projectmaterialstorage.dao.ProjectMaterialStorageDao;
 import com.jeeplus.modules.projectmaterialstorage.entity.ProjectMaterialStorage;
@@ -16,6 +18,7 @@ import com.jeeplus.modules.sys.utils.UserUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
+import redis.clients.jedis.Jedis;
 
 import java.util.*;
 
@@ -114,6 +117,86 @@ public class ProjectMaterialStorageService extends CrudService<ProjectMaterialSt
         }
     }
 
+
+
+    /**
+     * 查询同项目名称、价格、材料名称的数量是否只有一个
+     */
+    public Map<String, List<ProjectMaterialStorageImport>> distinctProjectMaterialStorage(
+            List<ProjectMaterialStorageImport> projectMaterialStorageImports, String projectId) {
+
+        HashMap<String, List<ProjectMaterialStorageImport>> map = new HashMap<>();
+
+        // 第一步:对本次导入数据进行去重(自身重复)
+        Set<String> seen = new HashSet<>();
+        List<ProjectMaterialStorageImport> uniqueList = new ArrayList<>();      // 本次去重后的有效值
+        List<ProjectMaterialStorageImport> duplicateList = new ArrayList<>();   // 本次自身重复值
+
+        for (ProjectMaterialStorageImport item : projectMaterialStorageImports) {
+            String distinctStr = item.getDistinctStr();
+
+            // 处理null值(视为重复)
+            if (distinctStr == null) {
+                duplicateList.add(item);
+                continue;
+            }
+
+            if (!seen.contains(distinctStr)) {
+                seen.add(distinctStr);
+                uniqueList.add(item);
+            } else {
+                duplicateList.add(item);
+            }
+        }
+
+        // 第二步:获取历史数据并处理其distinctStr
+        List<ProjectMaterialStorageImport> historyInfoList = dao.getByProjectId(projectId);
+        for (ProjectMaterialStorageImport info : historyInfoList) {
+            // 组合历史数据的distinctStr(材料名称+规格+含税价格)
+            String name = (info.getMaterialName() != null) ? info.getMaterialName() : "";
+            String spec = (info.getSpecifications() != null) ? info.getSpecifications() : "";
+            String priceStr = (info.getProjectPriceIncludingTax() != null)
+                    ? info.getProjectPriceIncludingTax().toString() : "";
+
+            info.setDistinctStr(name + "," + spec + "," + priceStr);
+        }
+
+        // 第三步:筛选历史数据中的distinctStr,用于比对
+        Set<String> historyDistinctSet = new HashSet<>();
+        for (ProjectMaterialStorageImport historyItem : historyInfoList) {
+            String historyDistinctStr = historyItem.getDistinctStr();
+            if (historyDistinctStr != null) {
+                historyDistinctSet.add(historyDistinctStr);
+            }
+        }
+
+        // 第四步:从uniqueList中移除与历史数据重复的项,并加入重复列表
+        // 使用迭代器支持边遍历边删除
+        Iterator<ProjectMaterialStorageImport> iterator = uniqueList.iterator();
+        while (iterator.hasNext()) {
+            ProjectMaterialStorageImport currentItem = iterator.next();
+            String currentDistinctStr = currentItem.getDistinctStr();
+
+            // 处理null值(从uniqueList移除并加入重复列表)
+            if (currentDistinctStr == null) {
+                iterator.remove();
+                duplicateList.add(currentItem);
+                continue;
+            }
+
+            // 与历史数据重复:从uniqueList移除并加入重复列表
+            if (historyDistinctSet.contains(currentDistinctStr)) {
+                iterator.remove();
+                duplicateList.add(currentItem);
+            }
+        }
+
+        // 最终返回处理后的列表
+        map.put("uniqueList", uniqueList);      // 仅包含本次新增且不与历史重复的数据
+        map.put("duplicateList", duplicateList); // 包含自身重复和与历史重复的数据
+        return map;
+    }
+
     /**
      * 逻辑删除
      */
@@ -122,6 +205,14 @@ public class ProjectMaterialStorageService extends CrudService<ProjectMaterialSt
         return dao.deleteByLogic(projectMaterialStorage);
     }
 
+    /**
+     * 逻辑删除
+     */
+    @Transactional(readOnly = false)
+    public Integer deleteById(ProjectMaterialStorage projectMaterialStorage){
+        return dao.deleteById(projectMaterialStorage);
+    }
+
 
     /**
      * 修改项目表中的材料库状态信息
@@ -154,6 +245,26 @@ public class ProjectMaterialStorageService extends CrudService<ProjectMaterialSt
         return map;
     }
 
+    /**
+     * 修改项目表中的材料库状态信息
+     */
+    @Transactional(readOnly = false)
+    public Map<String,Object> saveUniqueInfo(ProjectMaterialStorageImport info){
+        Map<String,Object> map = new HashMap<>();
+        try{
+            info.setId(IdGen.uuid());
+            info.preInsert();
+            Integer i = projectMaterialStorageDao.saveUniqueInfo(info);
+            map.put("success",true);
+            map.put("message","材料保存成功");
+        }catch (Exception e){
+            info.setErrorMessage(e.getMessage());
+            map.put("success",false);
+            map.put("message",e.getMessage());
+        }
+        return map;
+    }
+
 
     /**
      * 批量保存或更新
@@ -215,4 +326,186 @@ public class ProjectMaterialStorageService extends CrudService<ProjectMaterialSt
         return dao.getByIdList(idList,UserUtils.getUser().getId());
     }
 
+    // 获取Jedis实例(假设你的工具类是JedisUtils)
+    private Jedis getJedis() {
+        return JedisUtils.getResource();
+    }
+
+
+    // 过期时间:24小时(单位:秒)
+    private static final int EXPIRATION_SECONDS = 24 * 60 * 60;
+
+    /**
+     * 将列表存储到Redis的ZSET中
+     * @param key Redis键名
+     * @param list 要存储的ProjectMaterialStorageImport列表
+     */
+    public void saveListToZSet(String key, List<ProjectMaterialStorageImport> list) {
+        if (list == null || list.isEmpty()) {
+            return;
+        }
+
+        Jedis jedis = null;
+        try {
+            jedis = getJedis();
+            // 先删除可能存在的旧数据
+            jedis.del(key);
+
+            // 准备要存储的元素和分数
+            Map<String, Double> elements = new HashMap<>(list.size());
+
+            // 以元素在列表中的索引作为score,保持原有顺序
+            for (int i = 0; i < list.size(); i++) {
+                ProjectMaterialStorageImport item = list.get(i);
+                // 将实体类序列化为JSON字符串
+                String jsonStr = JSON.toJSONString(item);
+                // 使用索引作为score,确保顺序
+                elements.put(jsonStr, (double) i);
+            }
+
+            // 批量添加到ZSET
+            jedis.zadd(key, elements);
+
+            // 设置24小时过期时间
+            jedis.expire(key, EXPIRATION_SECONDS);
+        } finally {
+            if (jedis != null) {
+                jedis.close();
+            }
+        }
+    }
+
+    /**
+     * 从Redis的ZSET中获取列表
+     * @param key Redis键名
+     * @return 解析后的ProjectMaterialStorageImport列表
+     */
+    public List<ProjectMaterialStorageImport> getListFromZSet(String key) {
+        Jedis jedis = null;
+        try {
+            jedis = getJedis();
+            // 获取所有元素(按score排序,即原列表顺序)
+            List<String> jsonList = (List<String>) jedis.zrange(key, 0, -1);
+
+            // 反序列化为实体类列表
+            return jsonList.stream()
+                    .map(jsonStr -> JSON.parseObject(jsonStr, ProjectMaterialStorageImport.class))
+                    .collect(java.util.stream.Collectors.toList());
+        } finally {
+            if (jedis != null) {
+                jedis.close();
+            }
+        }
+    }
+
+    /**
+     * 从Redis获取指定key的ZSET数据并转换为List<ProjectMaterialStorage>
+     * @return 转换后的实体类列表
+     */
+    /**
+     * 从Redis获取指定key的ZSET数据并转换为List<ProjectMaterialStorage>
+     * 增加了HTML实体转换处理(如m&sup3; -> m³)
+     */
+    public List<ProjectMaterialStorage> convertFromRedis(String redisKey) {
+        Jedis jedis = null;
+        try {
+            // 验证参数
+            if (redisKey == null || redisKey.trim().isEmpty()) {
+                throw new IllegalArgumentException("Redis key不能为空");
+            }
+
+            // 获取Jedis实例
+            jedis = JedisUtils.getResource();
+
+            // 检查key是否存在
+            if (!jedis.exists(redisKey)) {
+                System.out.println("指定的Redis key不存在: " + redisKey);
+                return new ArrayList<>();
+            }
+
+            // 从ZSET中获取所有元素(按分数排序,保持原列表顺序)
+            Set<String> jsonSet = jedis.zrange(redisKey, 0, -1);
+            if (jsonSet == null || jsonSet.isEmpty()) {
+                System.out.println("Redis key对应的集合为空: " + redisKey);
+                return new ArrayList<>();
+            }
+
+            // 转换为List<ProjectMaterialStorage>并处理特殊字符
+            List<ProjectMaterialStorage> resultList = new ArrayList<>(jsonSet.size());
+            for (String jsonStr : jsonSet) {
+                // 跳过空字符串
+                if (jsonStr == null || jsonStr.trim().isEmpty()) {
+                    continue;
+                }
+
+                // 将JSON字符串反序列化为实体类
+                ProjectMaterialStorage material = JSON.parseObject(jsonStr, ProjectMaterialStorage.class);
+                if (material != null) {
+                    // 处理HTML实体转换
+                    processHtmlEntities(material);
+                    resultList.add(material);
+                }
+            }
+
+            return resultList;
+        } catch (Exception e) {
+            System.err.println("转换Redis数据出错: " + e.getMessage());
+            e.printStackTrace();
+            return new ArrayList<>();
+        } finally {
+            // 释放资源
+            if (jedis != null) {
+                try {
+                    jedis.close();
+                } catch (Exception e) {
+                    System.err.println("关闭Jedis连接出错: " + e.getMessage());
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    /**
+     * 处理实体类中的HTML实体编码(如m&sup3; -> m³)
+     */
+    private void processHtmlEntities(ProjectMaterialStorage material) {
+        if (material == null) {
+            return;
+        }
+
+        // 处理材料名称
+        material.setMaterialName(convertHtmlEntity(material.getMaterialName()));
+
+        // 处理规格型号
+        material.setSpecifications(convertHtmlEntity(material.getSpecifications()));
+
+        // 处理单位(重点转换m&sup3;等)
+        material.setUnit(convertHtmlEntity(material.getUnit()));
+
+        // 处理其他可能包含HTML实体的字段
+        material.setExplain(convertHtmlEntity(material.getExplain()));
+        material.setSupplier(convertHtmlEntity(material.getSupplier()));
+        material.setRemarks(convertHtmlEntity(material.getRemarks()));
+        material.setDistinctStr(convertHtmlEntity(material.getDistinctStr()));
+        material.setErrorMessage(convertHtmlEntity(material.getErrorMessage()));
+    }
+
+    /**
+     * 转换HTML实体编码为对应的Unicode字符
+     */
+    private String convertHtmlEntity(String input) {
+        if (input == null) {
+            return "";
+        }
+
+        // 替换常见的HTML实体
+        return input.replace("&sup3;", "³")    // 立方符号
+                .replace("&sup2;", "²")    // 平方符号
+                .replace("&amp;", "&")     // &符号
+                .replace("&lt;", "<")      // 小于号
+                .replace("&gt;", ">")      // 大于号
+                .replace("&quot;", "\"")   // 双引号
+                .replace("&apos;", "'");   // 单引号
+    }
 }
+

+ 158 - 65
src/main/java/com/jeeplus/modules/projectmaterialstorage/web/ProjectMaterialStorageController.java

@@ -3,9 +3,9 @@ package com.jeeplus.modules.projectmaterialstorage.web;
 import com.google.common.collect.Lists;
 import com.jeeplus.common.config.Global;
 import com.jeeplus.common.persistence.Page;
-import com.jeeplus.common.utils.MyBeanUtils;
-import com.jeeplus.common.utils.StringUtils;
-import com.jeeplus.common.utils.ThisLocalityDownloadUtil;
+import com.jeeplus.common.utils.*;
+import com.jeeplus.common.utils.excel.ExportExcel;
+import com.jeeplus.common.utils.excel.ExportMultipleTabsExcel;
 import com.jeeplus.common.utils.excel.ImportExcel;
 import com.jeeplus.common.web.BaseController;
 import com.jeeplus.modules.projectmaterialstorage.entity.ProjectMaterialStorage;
@@ -16,6 +16,7 @@ import com.jeeplus.modules.projectrecord.enums.ProjectStatusEnum;
 import com.jeeplus.modules.projectrecord.service.ProjectRecordsService;
 import com.jeeplus.modules.ruralprojectrecords.entity.RuralProjectRecords;
 import com.jeeplus.modules.ruralprojectrecords.service.RuralProjectRecordsService;
+import com.jeeplus.modules.sys.entity.User;
 import com.jeeplus.modules.sys.utils.UserUtils;
 import com.jeeplus.modules.workreceiptsregister.entity.ResponseEntity;
 import org.apache.shiro.authz.annotation.RequiresPermissions;
@@ -25,6 +26,7 @@ import org.springframework.ui.Model;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 import org.springframework.web.servlet.mvc.support.RedirectAttributes;
+import redis.clients.jedis.Jedis;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -161,45 +163,115 @@ public class ProjectMaterialStorageController extends BaseController {
     @RequestMapping(value = "storageSave")
     public String storageSave(ProjectMaterialStorage projectMaterialStorage, Model model, RedirectAttributes redirectAttributes) throws Exception {
         int i = 1;
-        List<ProjectMaterialStorageImport> projectMaterialStorageList = new ArrayList<ProjectMaterialStorageImport>();
-        List<ProjectMaterialStorageImport> projectMaterialStorageList2 = projectMaterialStorage.getProjectMaterialStorageList();
+        List<ProjectMaterialStorageImport> projectMaterialStorageList = Lists.newArrayList();
+        List<ProjectMaterialStorageImport> metadataList = projectMaterialStorage.getProjectMaterialStorageList();
 
-        if(null == projectMaterialStorageList2 || projectMaterialStorageList2.size() == 0 ){
+        if(null == metadataList || metadataList.isEmpty()){
             addMessage(redirectAttributes, "请填写材料信息");
             return "redirect:"+Global.getAdminPath()+"/project/projectMaterialStorage/?repage";
         }
 //        此处需要修改为迭代器形式
-        Iterator<ProjectMaterialStorageImport> iterator = projectMaterialStorageList2.iterator();
+        Iterator<ProjectMaterialStorageImport> iterator = metadataList.iterator();
         while (iterator.hasNext()){
             ProjectMaterialStorageImport projectMaterialStorageImport = iterator.next();
-            if(projectMaterialStorageImport.getSpecifications() == null || projectMaterialStorageImport.getMaterialName() == null || projectMaterialStorageImport.getUnit()== null || "1".equals(projectMaterialStorageImport.getDelFlag())){
+            if("1".equals(projectMaterialStorageImport.getDelFlag())){
                 iterator.remove();
-            }else {
+            }else{
                 projectMaterialStorageList.add(projectMaterialStorageImport);
             }
         }
-        for(int k=0;k<projectMaterialStorageList.size();k++){
-            projectMaterialStorageList.get(k).setProjectNumber(projectMaterialStorage.getProjectId());
-            projectMaterialStorageList.get(k).setIsNewRecord(true);
-            //       判断项目名称、材料名称、价格是否为空
-            if(projectMaterialStorageList.get(k).getMaterialName() ==null || projectMaterialStorageList.get(k).getSpecifications() == null || projectMaterialStorageList.get(k).getUnit()== null){
-                addMessage(redirectAttributes, "第"+i+"个材料名称、规格型号、单位等获取失败,请重试");
-                return "redirect:"+Global.getAdminPath()+"/project/projectMaterialStorage/?repage";
+
+        //对相对有效的数据进行处理
+        //有效的数据
+        List<ProjectMaterialStorageImport> effectiveList = Lists.newArrayList();
+        //错误的数据
+        List<ProjectMaterialStorageImport> errorList = Lists.newArrayList();
+        Iterator<ProjectMaterialStorageImport> projectMaterialStorageListIterator = projectMaterialStorageList.iterator();
+        while (projectMaterialStorageListIterator.hasNext()){
+            ProjectMaterialStorageImport projectMaterialStorageImport = projectMaterialStorageListIterator.next();
+            if(StringUtils.isNotBlank(projectMaterialStorageImport.getMaterialName()) || StringUtils.isNotBlank(projectMaterialStorageImport.getUnit())){
+                effectiveList.add(projectMaterialStorageImport);
+            }else {
+                if(StringUtils.isNotBlank(projectMaterialStorageImport.getMaterialName()) && StringUtils.isNotBlank(projectMaterialStorageImport.getUnit())){
+                    projectMaterialStorageImport.setErrorMessage("数据中缺少材料名称、材料单位");
+                }else if(StringUtils.isNotBlank(projectMaterialStorageImport.getMaterialName())){
+                    projectMaterialStorageImport.setErrorMessage("数据中缺少材料名称");
+                }else if(StringUtils.isNotBlank(projectMaterialStorageImport.getUnit())){
+                    projectMaterialStorageImport.setErrorMessage("数据中缺少材料单位");
+                }
+                errorList.add(projectMaterialStorageImport);
             }
         }
-        Map map = projectMaterialStorageService.qureyCountAboutProjectMaterialStorage(projectMaterialStorageList);
-        if((map.containsKey("failure"))){
-            addMessage(redirectAttributes, map.get("failure").toString());
-            return "redirect:"+Global.getAdminPath()+"/project/projectMaterialStorage/?repage";
+        //对有效的数据进行去重处理
+        for (ProjectMaterialStorageImport info : effectiveList) {
+            // 处理可能的null值,转为空字符串
+            String name = (info.getMaterialName() != null) ? info.getMaterialName() : "";
+            String spec = (info.getSpecifications() != null) ? info.getSpecifications() : "";
+            String projectPriceIncludingTaxStr = (info.getProjectPriceIncludingTax() != null) ? info.getProjectPriceIncludingTax().toString() : "";
+            // 以逗号分隔组合
+            String result = name + "," + spec + "," + projectPriceIncludingTaxStr;
+            info.setDistinctStr(result);
+        }
+
+        Map<String,List<ProjectMaterialStorageImport>> map = projectMaterialStorageService.distinctProjectMaterialStorage(effectiveList,projectMaterialStorage.getProjectId());
+        //有效数据
+        List<ProjectMaterialStorageImport> uniqueList = map.get("uniqueList");
+        //重复数据
+        List<ProjectMaterialStorageImport> duplicateList = map.get("duplicateList");
+        for (ProjectMaterialStorageImport info : duplicateList) {
+            info.setErrorMessage("重复数据");
+        }
+
+        Iterator<ProjectMaterialStorageImport> uniqueIterator = uniqueList.iterator();
+        while (uniqueIterator.hasNext()){
+            ProjectMaterialStorageImport info = uniqueIterator.next();
+            info.setProjectNumber(projectMaterialStorage.getProjectId());
+            Map<String, Object> saveResultMap = projectMaterialStorageService.saveUniqueInfo(info);
+            Boolean success = (Boolean) saveResultMap.get("success");
+            String message = (String) saveResultMap.get("message");
+            if(!success){
+                info.setErrorMessage(message);
+                errorList.add(info);
+                uniqueIterator.remove();
+            }
+        }
+        //有效数据:uniqueList
+        //错误数据:errorList
+        //重复数据:duplicateList
+        //元数据:metadataList
+        //判定,如果 错误数据 中存在数据,则表示前端传过来的数据并没有完全保存。需要将数据转存成exce文档并给下载接口
+        //可先将数据存储到redis中,保存的redis 的key可以按照 项目id + 登陆人id + uniqueList 这种格式
+        if(!duplicateList.isEmpty()){
+            User user = UserUtils.getUser();
+            String uniqueRedisKey = projectMaterialStorage.getProjectId() + "_" + user.getId() + "_uniqueList";
+            String errorRedisKey = projectMaterialStorage.getProjectId() + "_" + user.getId() + "_errorList";
+            String duplicateRedisKey = projectMaterialStorage.getProjectId() + "_" + user.getId() + "_duplicateList";
+            String metadataRedisKey = projectMaterialStorage.getProjectId() + "_" + user.getId() + "_metadataList";
+
+            // 分别存储各个列表
+
+            if (!errorList.isEmpty()) {
+                projectMaterialStorageService.saveListToZSet(errorRedisKey, errorList);
+            }
+            if (!uniqueList.isEmpty()) {
+                projectMaterialStorageService.saveListToZSet(uniqueRedisKey, uniqueList);
+            }
+            if (!duplicateList.isEmpty()) {
+                projectMaterialStorageService.saveListToZSet(duplicateRedisKey, duplicateList);
+            }
+            if (!metadataList.isEmpty()) {
+                projectMaterialStorageService.saveListToZSet(metadataRedisKey, metadataList);
+            }
+
         }
 
-        projectMaterialStorageService.batchSave(projectMaterialStorageList);
         if(StringUtils.isNotBlank(projectMaterialStorage.getProjectId())){
             RuralProjectRecords ruralProjectRecords = ruralProjectRecordsService.get(projectMaterialStorage.getProjectId());
             //修改2代表已处理
             ruralProjectRecords.setprojectMaterialStorageStatus("2");
             projectMaterialStorageService.modifyProjectMaterialStorageStatus(ruralProjectRecords);
         }
+
         return "redirect:"+Global.getAdminPath()+"/project/projectMaterialStorage/?repage";
     }
 
@@ -236,23 +308,54 @@ public class ProjectMaterialStorageController extends BaseController {
 
 
     /**
-     * 导出excel文件
+     * 下载处理后的文档信息
      */
-//    @RequiresPermissions("project:projectMaterialStorage:export")
-//    @RequestMapping(value = "export", method= RequestMethod.POST)
-//    public String exportFile(ProjectMaterialStorage projectMaterialStorage, HttpServletRequest request, HttpServletResponse response, RedirectAttributes redirectAttributes) {
-//        try {
-//            //添加查询类型(造价审核)
-//            String fileName = "材料库"+ DateUtils.getDate("yyyyMMddHHmmss")+".xlsx";
-//            List<RuralProjectRecordsExport> list = projectRecordsService.findPageExport(new Page<RuralProjectRecords>(request, response, -1), projectRecords);
-//            new ExportExcel("项目", RuralProjectRecordsExport.class).setDataList(list).write(response, fileName).dispose();
-//            return null;
-//        } catch (Exception e) {
-//            addMessage(redirectAttributes, "导出项目记录失败!失败信息:"+e.getMessage());
-//            logger.error("Exception e:"+e);
-//        }
-//        return "redirect:"+Global.getAdminPath()+"/ruralProject/ruralProjectRecords/?repage";
-//    }
+    @RequiresPermissions("project:projectMaterialStorage:export")
+    @RequestMapping(value = "export", method= RequestMethod.POST)
+    public String exportFile(ProjectMaterialStorage projectMaterialStorage, HttpServletRequest request, HttpServletResponse response, RedirectAttributes redirectAttributes) {
+        try {
+            projectMaterialStorage.setProjectId("c8e0cb8a12f84403b0acce09bfbd0191");
+            // 1. 创建多页签导出工具实例
+            ExportMultipleTabsExcel exporter = new ExportMultipleTabsExcel();
+
+            // 2. 获取各类数据(从Redis或数据库)
+            String projectId = projectMaterialStorage.getProjectId();
+            String userId = UserUtils.getUser().getId();
+
+            // 错误数据列表
+            List<ProjectMaterialStorage> errorList = projectMaterialStorageService.convertFromRedis(
+                    projectId + "_" + userId + "_errorList");
+
+            // 重复数据列表
+            List<ProjectMaterialStorage> duplicateList = projectMaterialStorageService.convertFromRedis(
+                    projectId + "_" + userId + "_duplicateList");
+
+            // 有效数据列表
+            List<ProjectMaterialStorage> uniqueList = projectMaterialStorageService.convertFromRedis(
+                    projectId + "_" + userId + "_uniqueList");
+
+            // 原数据列表
+            List<ProjectMaterialStorage> metadataList = projectMaterialStorageService.convertFromRedis(
+                    projectId + "_" + userId + "_metadataList");
+
+            // 3. 添加Sheet页(页签名称、标题、实体类、数据列表)
+            exporter.addSheet("错误数据", "材料库导入错误数据", ProjectMaterialStorage.class, errorList);
+            exporter.addSheet("重复数据", "材料库导入重复数据", ProjectMaterialStorage.class, duplicateList);
+            exporter.addSheet("有效数据", "材料库导入有效数据", ProjectMaterialStorage.class, uniqueList);
+            exporter.addSheet("原数据", "材料库导入原数据", ProjectMaterialStorage.class, metadataList);
+
+            // 4. 导出文件
+            String fileName = "材料库导入数据汇总_" + DateUtils.getDate("yyyyMMddHHmmss") + ".xlsx";
+            exporter.write(response, fileName);
+            exporter.dispose(); // 清理资源
+            return null;
+
+        } catch (Exception e) {
+            addMessage(redirectAttributes, "导出失败!错误信息:" + e.getMessage());
+            logger.error("多页签导出异常", e);
+        }
+        return "redirect:"+Global.getAdminPath()+"/project/projectMaterialStorage/?repage";
+    }
 
 
     /**
@@ -266,9 +369,6 @@ public class ProjectMaterialStorageController extends BaseController {
         String storageFlag = projectRecords.getStorageFlag();
         if (projectRecords != null && StringUtils.isNotBlank(projectRecords.getId())) {
             projectRecords = ruralProjectRecordsService.getQueryProjectUsers(projectRecords.getId());
-//            RuralProjectcontentinfo ruralProjectcontentinfo = projectRecordsService.formAccessory(projectRecords);
-//            projectRecordsService.disposeData(ruralProjectcontentinfo);
-//            model.addAttribute("projectcontentinfo", ruralProjectcontentinfo);
         }
         projectRecords.setStorageFlag(storageFlag);
         model.addAttribute("pageId",pageId);
@@ -287,13 +387,20 @@ public class ProjectMaterialStorageController extends BaseController {
         try {
             ImportExcel ei = new ImportExcel(file, 1, 0);
             List<ProjectMaterialStorage> list = ei.getDataList(ProjectMaterialStorage.class);
-            List<ProjectMaterialStorage> listAll = new ArrayList<>();
+
+            /*List<ProjectMaterialStorage> listAll = new ArrayList<>();
+            //创建材料名称或单位为空的数据
+            List<ProjectMaterialStorage> materialNameOrUnitIsNullList = new ArrayList<>();
+
             for (ProjectMaterialStorage materialStorage : list) {
-                if(StringUtils.isNotBlank(materialStorage.getMaterialName()) && null != materialStorage.getSpecifications()  && null != materialStorage.getUnit() ){
+                //判断材料名称或单位是否为空
+                if(StringUtils.isNotBlank(materialStorage.getMaterialName()) && StringUtils.isNotBlank(materialStorage.getUnit())){
                     listAll.add(materialStorage);
+                }else{
+                    materialNameOrUnitIsNullList.add(materialStorage);
                 }
-            }
-            responseEntity.setData(listAll);
+            }*/
+            responseEntity.setData(list);
         } catch (Exception e) {
             logger.error("导入材料费用失败!",e);
             responseEntity.setCode(400);
@@ -310,14 +417,6 @@ public class ProjectMaterialStorageController extends BaseController {
         } catch (Exception e) {
             logger.error("材料库处理表模板下载失败!",e);
         }
-    	/*try {
-            String fileName = "设计概算编制审核调整数据导入模板.xlsx";
-    		List<WorkPreliminaryDesignEstimate> list = Lists.newArrayList();
-    		new ExportExcel("设计概算编制审核调整数据", WorkPreliminaryDesignEstimate.class, 1).setDataList(list).write(response, fileName).dispose();
-    		return null;
-		} catch (Exception e) {
-			addMessage(redirectAttributes, "导入模板下载失败!失败信息:"+e.getMessage());
-		}*/
         return "redirect:"+Global.getAdminPath()+"/project/projectMaterialStorage/?repage";
     }
 
@@ -343,7 +442,7 @@ public class ProjectMaterialStorageController extends BaseController {
 
 
     /**
-     * 选择开票项目
+     * 选择材料关联项目
      */
     @RequestMapping(value = "selectproject")
     public String selectproject(ProjectRecords project, String url, String fieldLabels, String fieldKeys, String searchLabel, String searchKey, String ids, Integer isProject, Integer isProjectFalg, String details, HttpServletRequest request, HttpServletResponse response, Model model) {
@@ -386,9 +485,6 @@ public class ProjectMaterialStorageController extends BaseController {
     public String ProjectMessageform(RuralProjectRecords projectRecords, Model model) {
         if (projectRecords != null && StringUtils.isNotBlank(projectRecords.getId())) {
             projectRecords = ruralProjectRecordsService.getQueryProjectUsers(projectRecords.getId());
-//            RuralProjectcontentinfo ruralProjectcontentinfo = projectRecordsService.formAccessory(projectRecords);
-//            projectRecordsService.disposeData(ruralProjectcontentinfo);
-//            model.addAttribute("projectcontentinfo", ruralProjectcontentinfo);
         }
         model.addAttribute("projectRecords",projectRecords);
         return "modules/ruralprojectrecords/ruralporjectmessage/ruralProjectMessageList";
@@ -406,9 +502,6 @@ public class ProjectMaterialStorageController extends BaseController {
     public String ruralCostProjectMessageForm(RuralProjectRecords projectRecords, Model model) {
         if (projectRecords != null && StringUtils.isNotBlank(projectRecords.getId())) {
             projectRecords = ruralProjectRecordsService.getQueryProjectUsers(projectRecords.getId());
-//            RuralProjectcontentinfo ruralProjectcontentinfo = projectRecordsService.formAccessory(projectRecords);
-//            projectRecordsService.disposeData(ruralProjectcontentinfo);
-//            model.addAttribute("projectcontentinfo", ruralProjectcontentinfo);
         }
         model.addAttribute("projectRecords",projectRecords);
         return "modules/ruralprojectrecords/cost/ruralCostProjectMessageList";
@@ -426,20 +519,20 @@ public class ProjectMaterialStorageController extends BaseController {
             String projectNumber = projectMaterialStorage.getProjectName().substring(0,projectMaterialStorage.getProjectName().indexOf(","));
             projectMaterialStorage.setProjectNumber(projectNumber);
         }
-        if(projectMaterialStorage.getProjectNumber()==null){
+        if(StringUtils.isBlank(projectMaterialStorage.getProjectNumber()) && StringUtils.isNotBlank(projectMaterialStorage.getId())){
             projectMaterialStorage = projectMaterialStorageService.get(projectMaterialStorage.getId());
         }
-//      判断项目名称、材料名称、价格是否为空
-        if(projectMaterialStorage.getProjectNumber()==null && projectMaterialStorage.getMaterialName() ==null && projectMaterialStorage.getPrice() == null ){
-            addMessage(redirectAttributes, "项目名称、材料名称、价格等获取失败,请重试");
+//      判断项目名称、材料名称、是否为空
+        if(StringUtils.isBlank(projectMaterialStorage.getProjectNumber()) && StringUtils.isBlank(projectMaterialStorage.getMaterialName())){
+            addMessage(redirectAttributes, "项目名称、材料名称等获取失败,请重试");
             if("1".equals(pageId)){
                 return "redirect:"+Global.getAdminPath()+"/ruralProject/ruralProjectMessageAll/?repage";
             }
             return "redirect:"+Global.getAdminPath()+"/project/projectMaterialStorage";
         }
 //        进行项目名称、材料名称、价格重复的判断
-        if(projectMaterialStorage.getProjectNumber()==null && projectMaterialStorage.getMaterialName() ==null && projectMaterialStorage.getPrice() == null ){
-            addMessage(redirectAttributes, "项目名称、材料名称、价格等获取失败,请重试");
+        if(StringUtils.isBlank(projectMaterialStorage.getProjectNumber()) && StringUtils.isBlank(projectMaterialStorage.getMaterialName())){
+            addMessage(redirectAttributes, "项目名称、材料名称等获取失败,请重试");
             return "redirect:"+Global.getAdminPath()+"/project/projectMaterialStorage";
         }
 

+ 0 - 11
src/main/java/com/jeeplus/modules/ruralprojectrecords/web/RuralProjectMessageAllController.java

@@ -96,7 +96,6 @@ public class RuralProjectMessageAllController extends BaseController {
     @RequiresPermissions("ruralProject:ruralProjectMessageAll:list")
     @RequestMapping(value = {"list", ""})
     public String list(RuralProjectRecords projectRecords, HttpServletRequest request, HttpServletResponse response, Model model) {
-        long s1 = System.currentTimeMillis();
         if(UserUtils.isManager()){
             model.addAttribute("flag","1");
         }
@@ -142,8 +141,6 @@ public class RuralProjectMessageAllController extends BaseController {
         List<User> auditUserList = userService.getShowAuditUserList();
         model.addAttribute("userList", auditUserList);
 
-        long s2 = System.currentTimeMillis();
-        System.out.println("s2-s1: " + (s2-s1));
         //添加查询类型list
         projectRecords.setTypeList(typeList);
         Page<RuralProjectRecords> page = ruralProjectMessageAllService.findPage(new Page<RuralProjectRecords>(request, response), projectRecords);
@@ -154,8 +151,6 @@ public class RuralProjectMessageAllController extends BaseController {
                 model.addAttribute("workContractInfoClientName", projectRecords.getWorkContractInfo().getClient().getName());
             }
         }
-        long s3 = System.currentTimeMillis();
-        System.out.println("s3-s2: " + (s3-s2));
         //无合同状态下,获取委托方的名称
         List<RuralProjectRecords> list = page.getList();
         for (int i = 0; i < list.size(); i++) {
@@ -174,15 +169,11 @@ public class RuralProjectMessageAllController extends BaseController {
         if(StringUtils.isNotBlank(oldSubmitMoney)){
             projectRecords.setSubmitMoney(oldSubmitMoney);
         }
-        long s4 = System.currentTimeMillis();
-        System.out.println("s4-s3: " + (s4-s3));
         //查询工程类型
         if (projectRecords.getEngineeringType()!=null){
             ProjectEngineeringInfo engineeringInfo=engineeringService.get(projectRecords.getEngineeringType());
             model.addAttribute("engineeringInfo", engineeringInfo);
         }
-        long s5 = System.currentTimeMillis();
-        System.out.println("s5-s4: " + (s5-s4));
         model.addAttribute("beginDate", projectRecords.getBeginDate());
         model.addAttribute("endDate", projectRecords.getEndDate());
         model.addAttribute("moneyAll", ruralProjectMessageAllService.getMoneyAll(projectRecords));
@@ -190,8 +181,6 @@ public class RuralProjectMessageAllController extends BaseController {
         if (StringUtils.isNotBlank(oldProjectSort)){
             model.addAttribute("oldProjectSort", oldProjectSort);
         }
-        long s6 = System.currentTimeMillis();
-        System.out.println("s6-s5: " + (s6-s5));
         return "modules/ruralprojectrecords/ruralporjectmessage/all/ruralProjectMessageAllList";
     }
 

+ 0 - 2
src/main/java/com/jeeplus/modules/ruralprojectrecords/web/RuralProjectSignatureOldMessageDisposeController.java

@@ -256,8 +256,6 @@ public class RuralProjectSignatureOldMessageDisposeController extends BaseContro
         Map<String,Object> map = new HashMap<>();
         final Calendar c = Calendar.getInstance();
         Integer year = c.get(Calendar.YEAR);
-        System.out.println(c.get(Calendar.DATE));
-        System.out.println(c.getActualMaximum(Calendar.DATE));
         long l1 = System.currentTimeMillis();
         Integer month = c.get(Calendar.MONTH) + 1; //第一个月从0开始,所以得到月份+1
         //当月最后一天

+ 56 - 6
src/main/java/com/jeeplus/modules/sys/utils/ALiYunSmsUtil.java

@@ -13,16 +13,16 @@ import java.util.HashMap;
  * @version: 2024-09-06 11:20
  */
 public class ALiYunSmsUtil {
-    private static final String ACCESS_KEY_ID = "LTAI5tPcDWKAh5iG7z8veXfk";//AccessKey自己账号的
-    private static final String ACCESS_KEY_SECRET = "GrY2L9GegHNKB2y62V5RcRtJU6iYr2";
+    private static final String ACCESS_KEY_ID = "LTAI5tSnsAbzQZMV8zmbqPX1";//AccessKey自己账号的
+    private static final String ACCESS_KEY_SECRET = "954QtufvhGG5tssdpn7prH9fmJBq4P";
     private static final String ENDPOINT = "dysmsapi.aliyuncs.com";//固定死
-    private static final String SIGNNAME = "大屏展示";//签名名称
+    private static final String SIGNNAME = "江苏兴光会计师事务所";//签名名称
     private static final String TCODE = "";//模版的编号
 
 
 
     /**
-     * 登录验证码
+     * 快捷登录验证码
      * @param phoneNumbers
      * @param randomCode
      * @return
@@ -40,7 +40,57 @@ public class ALiYunSmsUtil {
                 .setPhoneNumbers(phoneNumbers)
                 .setSignName(SIGNNAME)
                 /*.setTemplateCode("SMS_472770050")*/
-                .setTemplateCode("SMS_482810075")
+                .setTemplateCode("SMS_491315361")
+                //此处是设计模版的时候预留的变量${code}就验证码,用下面的随机生成4位数字传入
+                .setTemplateParam(String.format("{\"code\":\"%s\"}", randomCode));
+            
+        try {
+            SendSmsResponse sendSmsResponse = client.sendSms(sendSmsRequest);
+            System.out.println(sendSmsResponse);
+            if(sendSmsResponse.body.code.equals("isv.BUSINESS_LIMIT_CONTROL")){
+                if(sendSmsResponse.body.message.contains("触发分钟级流控")){
+                    map.put("message","手机号获取验证码次数已触发每分钟可发送数量上限,请稍后进行重试!");
+                }else if(sendSmsResponse.body.message.contains("触发小时级流控")){
+                    map.put("message","手机号获取验证码次数已触发每小时可发送数量上限,请稍后进行重试!");
+                }else{
+                    map.put("message","手机号获取验证码次数已触发每小时可发送数量上限,请稍后进行重试!");
+                }
+                //触发云通信流控限制 每小时限量
+                map.put("statusCode",10001);
+            }else if(sendSmsResponse.body.code.contains("isv.AMOUNT_NOT_ENOUGH")){
+                //触发账户余额不足
+                map.put("statusCode",10002);
+            }else if(sendSmsResponse.body.code.contains("isv.DAY_LIMIT_CONTROL")){
+                //触发触发日发送限额
+                map.put("statusCode",10003);
+            }else if(sendSmsResponse.body.code.contains("OK")){
+                map.put("statusCode",sendSmsResponse.getStatusCode());
+            }
+            return map;
+        } catch (TeaException error) {
+            return map;
+        }
+    }
+
+    /**
+     * 发送系统预警
+     * @param phoneNumbers
+     * @param randomCode
+     * @return
+     * @throws Exception
+     */
+    public static HashMap<String,Object> sendWarningSms(String phoneNumbers, String randomCode) throws Exception {
+        HashMap<String,Object> map = new HashMap<>();
+        Config config = new Config()
+                .setAccessKeyId(ACCESS_KEY_ID)
+                .setAccessKeySecret(ACCESS_KEY_SECRET)
+                .setEndpoint(ENDPOINT);
+
+        Client client = new Client(config);
+        SendSmsRequest sendSmsRequest = new SendSmsRequest()
+                .setPhoneNumbers(phoneNumbers)
+                .setSignName(SIGNNAME)
+                .setTemplateCode("SMS_491360336")
                 //此处是设计模版的时候预留的变量${code}就验证码,用下面的随机生成4位数字传入
                 .setTemplateParam(String.format("{\"code\":\"%s\"}", randomCode));
 
@@ -91,7 +141,7 @@ public class ALiYunSmsUtil {
                 .setPhoneNumbers(phoneNumbers)
                 .setSignName(SIGNNAME)
                 /*.setTemplateCode("SMS_472770050")*/
-                .setTemplateCode("SMS_482810075")
+                .setTemplateCode("SMS_491460317")
                 //此处是设计模版的时候预留的变量${code}就验证码,用下面的随机生成4位数字传入
                 .setTemplateParam(String.format("{\"code\":\"%s\"}", randomCode));
 

+ 22 - 18
src/main/java/com/jeeplus/modules/sys/web/LoginController.java

@@ -41,6 +41,7 @@ import com.jeeplus.modules.sys.security.FormAuthenticationFilter;
 import com.jeeplus.modules.sys.security.SystemAuthorizingRealm.Principal;
 import com.jeeplus.modules.sys.service.OfficeService;
 import com.jeeplus.modules.sys.service.SystemService;
+import com.jeeplus.modules.sys.utils.ALiYunSmsUtil;
 import com.jeeplus.modules.sys.utils.DictUtils;
 import com.jeeplus.modules.sys.utils.UserUtils;
 import com.jeeplus.modules.sys.utils.VerifyCodeUtils;
@@ -520,7 +521,6 @@ public class LoginController extends BaseController{
 		if (message != null) {
 			model.addAttribute("message", message);
 		}
-		long s1 = System.currentTimeMillis();
 		User user = UserUtils.getUser();
 		OaNotify oaNotify = new OaNotify();
 		oaNotify.setSelf(true);
@@ -532,7 +532,6 @@ public class LoginController extends BaseController{
 		//获取通知类别信息
 		List<MainDictDetail> notifytype = DictUtils.getMainDictList("oa_notify_type");
 
-		long s2 = System.currentTimeMillis();
 		User loginUser = UserUtils.getUser();
 		if(null != loginUser.getOffice() && "897d1bf0975a4598b3bb248049e2d1cf".equals(loginUser.getOffice().getId())){
 
@@ -543,7 +542,6 @@ public class LoginController extends BaseController{
 		}else{
 			//知识分享类别信息
 			List<KnowledgeSharingTypeInfo> typeInfoList = typeService.findList(new KnowledgeSharingTypeInfo());
-			System.out.println("s2-s1: " + (s2-s1));
 
 			List<OaNotify> showNotifyList = page.getList();
 			for (OaNotify info: showNotifyList) {
@@ -640,8 +638,6 @@ public class LoginController extends BaseController{
 		JSONArray json = JSONArray.fromObject(mapList);
 		model.addAttribute("oaNotifyList", json);*/
 
-		long s3 = System.currentTimeMillis();
-		System.out.println("s3-s2: " + (s3-s2));
 		//待办事项
 		WorkProjectNotify workProjectNotify = new WorkProjectNotify();
 		workProjectNotify.setUser(user);
@@ -729,8 +725,6 @@ public class LoginController extends BaseController{
 		}
 		workProjectNotify.setStatus("0");
 		workProjectNotify.setRemarks("待通知");
-		long s4 = System.currentTimeMillis();
-		System.out.println("s4-s3: " + (s4-s3));
 		//通知信息
 		Page<WorkProjectNotify> notifyPageShow = workProjectNotifyService.notifyFindPage(new Page<WorkProjectNotify>(request, response), workProjectNotify);
 		model.addAttribute("notifyShowPage", notifyPageShow.getList());
@@ -739,8 +733,6 @@ public class LoginController extends BaseController{
 
 		model.addAttribute("notifyTypeList", notifytype);//未读通知条数
 
-		long s5 = System.currentTimeMillis();
-		System.out.println("s5-s4: " + (s5-s4));
 		//我的日程
 		/*WorkCalendar workCalendar = new WorkCalendar();
 		Page<WorkCalendar> workCalendars=workCalendarService.findHomePage(new Page<WorkCalendar>(request, response), workCalendar);
@@ -754,8 +746,6 @@ public class LoginController extends BaseController{
 		model.addAttribute("projectCount", projectPage.getList());
 		model.addAttribute("projectPage", projectPage.getList().size());
 		model.addAttribute("projectSize", projectPage.getCount());
-		long s6 = System.currentTimeMillis();
-		System.out.println("s6-s5: " + (s6-s5));
 
 		/*MailBox mailBox = new MailBox();
 		mailBox.setReceiver(user);
@@ -834,9 +824,10 @@ public class LoginController extends BaseController{
 			HashMap<String,Object> result = null;
 			try{
 				//调用工具类返回结果
-				result = UserUtils.sendRandomCodes(mobile, randomCode);
-				String statusCode = (String) result.get("statusCode");
-				if (("000000").equals(statusCode)) {
+				result = ALiYunSmsUtil.quickLoginSendSms(mobile, randomCode);
+				Integer statusCode = (Integer) result.get("statusCode");
+
+				if (200 == statusCode) {
 					j.setSuccess(true);
 					j.setErrorCode("-1");
 					j.setMsg("短信发送成功!");
@@ -851,15 +842,28 @@ public class LoginController extends BaseController{
 					} finally {
 						JedisUtils.returnResource(jedis);
 					}
-				}else if(statusCode.equals("160040")){
+				}else if(10001 == statusCode){
+
+					j.setSuccess(false);
+					j.setErrorCode("2");
+					String message = (String) result.get("message");
+					//j.setMsg("短信发送失败,错误代码:"+result+",请联系管理员。");
+					j.setMsg(message);
+					j.put("ErrorXml",result);
+				}else if(10002 == statusCode){
 					j.setSuccess(false);
 					j.setErrorCode("2");
-					j.setMsg("号码获取验证码次数已达每日上限!");
+					j.put("message","账户短信量余额不足,请联系管理员进行充值!");
+					j.put("ErrorXml",result);
+				}else if(10003 == statusCode){
+					j.setSuccess(false);
+					j.setErrorCode("2");
+					j.put("message","手机号获取验证码次数已达每日上限!");
+					j.put("ErrorXml",result);
 				}else{
 					j.setSuccess(false);
 					j.setErrorCode("2");
-					//j.setMsg("短信发送失败,错误代码:"+result+",请联系管理员。");
-					j.setMsg("短信发送失败,错误代码:101,请联系管理员。");
+					j.put("message","短信发送失败,错误代码:101,请联系管理员!");
 					j.put("ErrorXml",result);
 				}
 

+ 39 - 24
src/main/java/com/jeeplus/modules/sys/web/RegisterController.java

@@ -32,6 +32,7 @@ import javax.servlet.http.HttpServletResponse;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import com.jeeplus.modules.sys.utils.ALiYunSmsUtil;
 
 /**
  * 用户Controller
@@ -307,32 +308,46 @@ public class RegisterController extends BaseController {
 		//验证手机号是否已经注册
 		if(userDao.validateMobile(mobile) == null||("resetPassword").equals(type)){
 		String randomCode = String.valueOf((int) (Math.random() * 9000 + 1000));
-		System.out.println(randomCode);
-		// String result = UserUtils.sendRandomCode(config.getSmsName(),config.getSmsPassword(), mobile, randomCode);
-			HashMap<String,Object> result = null;
+		HashMap<String,Object> result = null;
 		Jedis jedis = null;
 		try{
-				//调用工具类返回结果
-				result = UserUtils.sendRandomCodes(mobile, randomCode);
-				String statusCode = (String) result.get("statusCode");
-				//if (result.contains("Success") && result.contains("ok")) {
-				if (("000000").equals(statusCode)) {
-					j.setSuccess(true);
-					j.setErrorCode("-1");
-					j.setMsg("短信发送成功!");
-					//存放验证码
-					jedis = JedisUtils.getResource();
-					jedis.set(mobile, randomCode);
-
-					jedis.setex(mobile, 300, randomCode);
-					//request.getSession().getServletContext().setAttribute(mobile, randomCode);
-				}else{
-					j.setSuccess(false);
-					j.setErrorCode("2");
-					//j.setMsg("短信发送失败,错误代码:"+result+",请联系管理员。");
-					j.setMsg("短信发送失败,错误代码:101,请联系管理员。");
-					j.put("ErrorXml",result);
-				}
+			//调用工具类返回结果
+			result = ALiYunSmsUtil.updatePasswordSendSms(mobile, randomCode);
+			Integer statusCode = (Integer) result.get("statusCode");
+			if (200 == statusCode) {
+
+				j.setSuccess(true);
+				j.setErrorCode("-1");
+				j.setMsg("短信发送成功!");
+				//存放验证码
+				jedis = JedisUtils.getResource();
+				jedis.set(mobile, randomCode);
+
+				jedis.setex(mobile, 300, randomCode);
+			}else if(10001 == statusCode){
+
+				j.setSuccess(false);
+				j.setErrorCode("2");
+				String message = (String) result.get("message");
+				//j.setMsg("短信发送失败,错误代码:"+result+",请联系管理员。");
+				j.setMsg(message);
+				j.put("ErrorXml",result);
+			}else if(10002 == statusCode){
+				j.setSuccess(false);
+				j.setErrorCode("2");
+				j.put("message","账户短信量余额不足,请联系管理员进行充值!");
+				j.put("ErrorXml",result);
+			}else if(10003 == statusCode){
+				j.setSuccess(false);
+				j.setErrorCode("2");
+				j.put("message","手机号获取验证码次数已达每日上限!");
+				j.put("ErrorXml",result);
+			}else{
+				j.setSuccess(false);
+				j.setErrorCode("2");
+				j.put("message","短信发送失败,错误代码:101,请联系管理员!");
+				j.put("ErrorXml",result);
+			}
 		}catch (Exception e){
 			e.printStackTrace();
 			logger.info("5");

+ 9 - 7
src/main/java/com/jeeplus/modules/syswarning/service/SysWarningService.java

@@ -15,6 +15,7 @@ import com.jeeplus.common.utils.SendMailUtil;
 import com.jeeplus.common.utils.StringUtils;
 import com.jeeplus.modules.sys.dao.UserDao;
 import com.jeeplus.modules.sys.entity.User;
+import com.jeeplus.modules.sys.utils.ALiYunSmsUtil;
 import com.jeeplus.modules.sys.utils.DictUtils;
 import com.jeeplus.modules.sys.utils.UserUtils;
 import com.jeeplus.modules.sysmodular.dao.SysModularDao;
@@ -235,13 +236,14 @@ public class SysWarningService extends CrudService<SysWarningDao, SysWarning> {
 		if (userList!=null && userList.size()!=0) {
 			for (User u : userList) {
 				try{
-						result = UserUtils.sendRandomCodes(u.getMobile(), sysWarning.getComment());
-					    String statusCode = (String) result.get("statusCode");
-						if (("000000").equals(statusCode)) {
-							System.out.println("短信发送成功!");
-						}else{
-							System.out.println("短信发送失败!");
-						}
+					//result = UserUtils.sendRandomCodes(u.getMobile(), sysWarning.getComment());
+					result = ALiYunSmsUtil.updatePasswordSendSms(u.getMobile(), sysWarning.getComment());
+					Integer statusCode = (Integer) result.get("statusCode");
+					if (200 == statusCode) {
+						System.out.println("短信发送成功!");
+					}else{
+						System.out.println("短信发送失败!");
+					}
 
 				}catch (Exception e){
 					e.printStackTrace();

+ 1 - 1
src/main/java/com/jeeplus/modules/workprojectnotify/web/WorkProjectNotifyController.java

@@ -2281,7 +2281,7 @@ public class WorkProjectNotifyController extends BaseController {
 					}
 
 					//查询关联红冲发票的开票号
-					if("1".equals(workInvoice.getRedInvoiceFlag()) && StringUtils.isNotBlank(workInvoice.getRedInvoiceRelevancyId())){
+					if(1 == workInvoice.getRedInvoiceFlag() && StringUtils.isNotBlank(workInvoice.getRedInvoiceRelevancyId())){
 						String invoiceNumberStr = workInvoiceService.getInvoiceNumberStr(workInvoice.getRedInvoiceRelevancyId());
 						workInvoice.setInvoiceNumberStr(invoiceNumberStr);
 					}

+ 38 - 0
src/main/java/com/jeeplus/modules/workstaff/service/WorkStaffBasicInfoService.java

@@ -918,6 +918,25 @@ public class WorkStaffBasicInfoService extends CrudService<WorkStaffBasicInfoDao
     }
 
     @Transactional(readOnly = false)
+    public void completeBack(String achiveIds, String actComment) {
+        if (StringUtils.isBlank(achiveIds)) {
+            return;
+        }
+        String[] split = achiveIds.split(",");
+        String contentStr = "您的员工档案填写格式不正确已被驳回,请及时完善";
+        String titleStr = "您的员工档案填写格式不正确已被驳回,请及时完善";
+        if(StringUtils.isNotBlank(actComment)) {
+            contentStr = "您的员工档案填写格式不正确。驳回原因为:" + actComment + "请及时完善";
+            titleStr = "您的员工档案填写格式不正确。驳回原因为:" + actComment + "请及时完善";
+        }
+        String remark = "待处理";
+        for (String s : split) {
+            WorkStaffBasicInfo workStaffBasicInfo = workStaffAchivesDao.get(s);
+            this.sendMessage(workStaffBasicInfo, contentStr, titleStr, remark);
+        }
+    }
+
+    @Transactional(readOnly = false)
     public void completeDirectly(String achiveIds) {
         if (StringUtils.isBlank(achiveIds)) {
             return;
@@ -1261,12 +1280,20 @@ public class WorkStaffBasicInfoService extends CrudService<WorkStaffBasicInfoDao
         if (StringUtils.isNotEmpty(workStaffBasicInfo.getIdCardPortraitPath())) {
             workStaffBasicInfo.setIdCardPortraitPathStr(WorkattachmentService.fileUrlThumbnailManageWithWatermark(workStaffBasicInfo.getIdCardPortraitPath()));
             workStaffBasicInfo.setIdCardPortraitPathThumbnailStr(WorkattachmentService.getThumbnailTemporaryWithWatermarkDimLookUrl(workStaffBasicInfo.getIdCardPortraitPath()));
+        }else{
+            workStaffBasicInfo.setIdCardPortraitPathStr("");
+            workStaffBasicInfo.setIdCardPortraitPathThumbnailStr("");
         }
         if (StringUtils.isNotEmpty(workStaffBasicInfo.getIdCardNationalEmblemPath())) {
             //获取水印图
             workStaffBasicInfo.setIdCardNationalEmblemPathStr(WorkattachmentService.fileUrlThumbnailManageWithWatermark(workStaffBasicInfo.getIdCardNationalEmblemPath()));
             //获取虚化图
             workStaffBasicInfo.setIdCardNationalEmblemPathThumbnailStr(WorkattachmentService.getThumbnailTemporaryWithWatermarkDimLookUrl(workStaffBasicInfo.getIdCardNationalEmblemPath()));
+        }else{
+            //获取水印图
+            workStaffBasicInfo.setIdCardNationalEmblemPathStr("");
+            //获取虚化图
+            workStaffBasicInfo.setIdCardNationalEmblemPathThumbnailStr("");
         }
     }
 
@@ -1621,6 +1648,11 @@ public class WorkStaffBasicInfoService extends CrudService<WorkStaffBasicInfoDao
                         Method getIdMethod = newInvoke.getClass().getMethod("getId");
                         newInvoke = getIdMethod.invoke(newInvoke);
                     }
+                    if ("picture".equals(name)) {
+                        if(null == newInvoke){
+                            newInvoke = "";
+                        }
+                    }
                     Object oldInvoke = wClass.getMethod(methodName).invoke(w);//修改前
                     String describes = CODE_MAP.get(name);
                     if (newInvoke == null) continue;
@@ -1656,6 +1688,12 @@ public class WorkStaffBasicInfoService extends CrudService<WorkStaffBasicInfoDao
                                         oldValue, newValue, oldValue, newValue, "", "修改");
                             }
 
+                        }else{
+                            if ("picture".equals(name)) {
+                                workStaffAchivesLogService.storeStaffLog(workStaffAchivesLog, workStaffBasicInfo.getId(),
+                                        "基本信息", describes, name,
+                                        oldValue, newValue, oldValue, newValue, "", "修改");
+                            }
                         }
                     }
                     if (newInvoke instanceof Integer) {

+ 6 - 1
src/main/java/com/jeeplus/modules/workstaff/web/WorkStaffBasicInfoController.java

@@ -258,6 +258,7 @@ public class WorkStaffBasicInfoController extends BaseController {
 		if(StringUtils.isNotBlank(workStaffBasicInfo.getId())){
             workStaffBasicInfoService.queryDetails(workStaffBasicInfo);
         }
+		workStaffBasicInfoService.storeQuerys(workStaffBasicInfo);
 		List<WorkStaffCertificate> certificateList = workStaffBasicInfo.getCertificateList();
 		List<MainDictDetail> certificateType = DictUtils.getMainDictList("certificate_type");
 		for (MainDictDetail type : certificateType) {
@@ -1155,10 +1156,14 @@ public class WorkStaffBasicInfoController extends BaseController {
 			workProjectNotify.setType("86");
 			workProjectNotifyService.readByNotifyId(workProjectNotify);
 		}
-		workStaffBasicInfoService.complete(workStaffBasicInfo.getId());
+		String actComment="";
 		if(null != workStaffBasicInfo.getAct() && StringUtils.isNotBlank(workStaffBasicInfo.getAct().getComment())){
 			workStaffBasicInfoService.updateActComment(workStaffBasicInfo);
+			actComment = workStaffBasicInfo.getAct().getComment();
 		}
+
+		workStaffBasicInfoService.completeBack(workStaffBasicInfo.getId(),actComment);
+
 		workStaffBasicInfoService.updateAuditStatus(workStaffBasicInfo.getId(), "1");
 
 		workStaffAchivesLogDao.updateBackOnTS(workStaffBasicInfo.getId());

+ 60 - 1
src/main/resources/mappings/modules/projectMaterialStorage/ProjectMaterialStorageDao.xml

@@ -48,6 +48,15 @@
 		WHERE a.id = #{id}
 	</select>
 
+
+	<select id="getByProjectId" resultType="com.jeeplus.modules.projectmaterialstorage.entity.ProjectMaterialStorageImport" >
+		SELECT
+		<include refid="projectMaterialStorageColumns"/>
+		FROM project_material_storage a
+		left join rural_project_records r on a.project_number = r.id
+		WHERE r.id = #{projectId} and a.del_flag = 0
+	</select>
+
 	<select id="findList" resultType="com.jeeplus.modules.projectmaterialstorage.entity.ProjectMaterialStorage" >
 		SELECT
 		<include refid="projectMaterialStorageColumns"/>
@@ -198,6 +207,50 @@
 		)
 	</insert>
 
+	<insert id="saveUniqueInfo">
+		INSERT INTO project_material_storage(
+			id,
+			create_by,
+			create_date,
+			update_by,
+			update_date,
+			del_flag,
+			material_name,
+			price,
+			project_number,
+			brand,
+			specifications,
+			project_price_including_tax,
+			market_price_including_tax,
+			tax_rate,
+			unit,
+			`explain`,
+			supplier,
+			remarks,
+			quoted_price_date
+		) VALUES (
+			#{id},
+			#{createBy.id},
+			#{createDate},
+			#{updateBy.id},
+			#{updateDate},
+			#{delFlag},
+			#{materialName},
+			#{price},
+			#{projectNumber},
+			#{brand},
+			#{specifications},
+			#{projectPriceIncludingTax},
+			#{marketPriceIncludingTax},
+			#{taxRate},
+			#{unit},
+			#{explain},
+			#{supplier},
+			#{remarks},
+			#{quotedPriceDate}
+		)
+	</insert>
+
 	<update id="update">
 		UPDATE project_material_storage SET
 			update_by = #{updateBy.id},
@@ -226,6 +279,12 @@
 		WHERE id = #{id}
 	</update>
 
+	<!--物理删除-->
+	<update id="deleteById">
+		DELETE FROM project_material_storage
+		WHERE id = #{id}
+	</update>
+
 	<!--逻辑删除-->
 	<update id="deleteByLogic">
 		UPDATE project_material_storage SET
@@ -237,7 +296,7 @@
 		select DISTINCT(r.project_name)
 		 from project_material_storage s left join rural_project_records r
 		 on s.project_number = r.id
-		 where s.project_number = #{projectNumber}
+		 where s.project_number = #{projectNumber} and s.del_flag = 0
 	</select>
 
 

+ 5 - 3
src/main/resources/mappings/modules/sys/UserDao.xml

@@ -688,9 +688,11 @@
 		update_by = #{updateBy.id},
 		update_date = #{updateDate},
 		remarks = #{remarks},
-		login_flag = #{loginFlag},
-		other_service_flag = #{otherServiceFlag},
-		photo = #{photo},
+		login_flag = #{loginFlag}
+		<if test="otherServiceFlag!=null and otherServiceFlag != ''">
+			,other_service_flag = #{otherServiceFlag}
+		</if>
+		,photo = #{photo},
 		default_photo = #{defaultPhoto},
 		password_remake = #{passwordRemake},
 		qrcode = #{qrCode}

+ 5 - 3
src/main/resources/mappings/modules/workstaff/WorkStaffBasicInfoDao.xml

@@ -541,9 +541,11 @@
 			try_out_job = #{tryOutJob},
 			trial_period = #{trialPeriod},
 			individual_resume = #{individualResume},
-			hand_signature = #{handSignature},
-			other_service_flag = #{otherServiceFlag},
-			id_card_portrait_name = #{idCardPortraitName},
+			hand_signature = #{handSignature}
+			<if test="otherServiceFlag!=null and otherServiceFlag != ''">
+				,other_service_flag = #{otherServiceFlag}
+			</if>
+			,id_card_portrait_name = #{idCardPortraitName},
 			id_card_portrait_path = #{idCardPortraitPath},
 			id_card_national_emblem_name = #{idCardNationalEmblemName},
 			id_card_national_emblem_path = #{idCardNationalEmblemPath}

BIN
src/main/webapp/dot/材料库处理表模板.xlsx


+ 5 - 5
src/main/webapp/webpage/modules/projectMaterialStorage/projectMaterialStorageAddForm.jsp

@@ -214,10 +214,10 @@
 			<div class="form-group layui-row first">
 				<div class="form-group-label"><h2>项目信息</h2></div>
 				<div class="layui-item layui-col-sm6">
-					<label class="layui-form-label">项目名称</label>
+					<label class="layui-form-label"><span class="require-item invoicetype">*</span>项目名称</label>
 					<div class="layui-input-block">
 						<sys:gridselectprojectmaterial disabled="true" url="${ctx}/project/projectMaterialStorage/selectproject" id="project" name="projectNumber"  value="${projectMaterialStorage.projectName}"  title="选择所属项目" labelName="projectName" cssStyle="background-color: #fff"
-													  labelValue="${projectMaterialStorage.projectName}" cssClass="form-control layui-input" fieldLabels="项目名称" fieldKeys="projectName" searchLabel="项目名称" searchKey="projectName"  ></sys:gridselectprojectmaterial>
+													  labelValue="${projectMaterialStorage.projectName}" cssClass="form-control required layui-input" fieldLabels="项目名称" fieldKeys="projectName" searchLabel="项目名称" searchKey="projectName"  ></sys:gridselectprojectmaterial>
 					</div>
 				</div>
 				<div class="layui-item layui-col-sm6">
@@ -251,7 +251,7 @@
 						<tr>
 							<th width="200px"><font color="red">*</font>材料名称</th>
 							<th width="150px">品牌</th>
-							<th width="200px"><font color="red">*</font>规格型号</th>
+							<th width="200px">规格型号</th>
 							<th width="100px">含税工程价(元)</th>
 							<th width="100px">含税市场价(元)</th>
 							<th width="100px">税率</th>
@@ -274,7 +274,7 @@
 							<input id="projectMaterialStorageList{{idx}}_delFlag" name="projectMaterialStorageList[{{idx}}].delFlag" type="hidden" value="0"/>
                         </td>
                         <td>
-							<input id="projectMaterialStorageList{{idx}}_materialName" name = "projectMaterialStorageList[{{idx}}].materialName"  type="text" value="{{row.materialName}}"  class="form-control"/>
+							<input id="projectMaterialStorageList{{idx}}_materialName" name = "projectMaterialStorageList[{{idx}}].materialName"  type="text" value="{{row.materialName}}"  class="form-control required"/>
                         </td>
                         <td>
 							<input id="projectMaterialStorageList{{idx}}_brand" name = "projectMaterialStorageList[{{idx}}].brand"  type="text" value="{{row.brand}}"  class="form-control"/>
@@ -292,7 +292,7 @@
 							<input id="projectMaterialStorageList{{idx}}_taxRate" name = "projectMaterialStorageList[{{idx}}].taxRate"  type="text" value="{{row.taxRate}}" onkeyup="num(this)"  class="form-control"/>
                         </td>
                         <td>
-							<input id="projectMaterialStorageList{{idx}}_unit" name = "projectMaterialStorageList[{{idx}}].unit"  type="text" value="{{row.unit}}"  class="form-control"/>
+							<input id="projectMaterialStorageList{{idx}}_unit" name = "projectMaterialStorageList[{{idx}}].unit"  type="text" value="{{row.unit}}"  class="form-control required"/>
                         </td>
                         <td>
 							<input id="projectMaterialStorageList{{idx}}_explain" name = "projectMaterialStorageList[{{idx}}].explain"  type="text" value="{{row.explain}}"  class="form-control"/>

+ 3 - 3
src/main/webapp/webpage/modules/projectMaterialStorage/projectMaterialStorageList.jsp

@@ -447,9 +447,9 @@
 						<%--</shiro:hasPermission>--%>
 						<button class="layui-btn layui-btn-sm" data-toggle="tooltip" data-placement="left" onclick="sortOrRefresh()" title="刷新"> 刷新</button>
 						</div>
-<%--					<shiro:hasPermission name="ruralProject:ruralProjectRecords:export">--%>
-<%--						<table:exportExcel url="${ctx}/ruralProject/ruralProjectRecords/export"></table:exportExcel><!-- 导出按钮 -->--%>
-<%--					</shiro:hasPermission>--%>
+					<shiro:hasPermission name="project:projectMaterialStorage:list">
+						<table:exportExcel url="${ctx}/project/projectMaterialStorage/export"></table:exportExcel><!-- 导出按钮 -->
+					</shiro:hasPermission>
 					<div style="clear: both;"></div>
 				</div>
 				<table class="oa-table layui-table" id="contentTable1"></table>

+ 4 - 4
src/main/webapp/webpage/modules/projectMaterialStorage/projectMaterialStorageTwoForm.jsp

@@ -97,10 +97,10 @@
 			<div class="form-group layui-row first">
 				<div class="form-group-label"><h2>材料详情</h2></div>
 				<div class="layui-item layui-col-sm6">
-					<label class="layui-form-label">项目名称</label>
+					<label class="layui-form-label"><span class="require-item invoicetype">*</span>项目名称</label>
 					<div class="layui-input-block">
 						<sys:gridselectprojectmaterial url="${ctx}/project/projectMaterialStorage/selectproject" id="project" name="projectName"  value="${projectMaterialStorage.projectName}"  title="选择所属项目" labelName="projectName" cssStyle="background-color: #fff"
-													  labelValue="${projectMaterialStorage.projectName}" cssClass="form-control layui-input" fieldLabels="项目名称" fieldKeys="projectName" searchLabel="项目名称" searchKey="projectName"  ></sys:gridselectprojectmaterial>
+													  labelValue="${projectMaterialStorage.projectName}" cssClass="form-control required layui-input" fieldLabels="项目名称" fieldKeys="projectName" searchLabel="项目名称" searchKey="projectName"  ></sys:gridselectprojectmaterial>
 					</div>
 				</div>
 				<div class="layui-item layui-col-sm6">
@@ -116,9 +116,9 @@
 					</div>
 				</div>
 				<div class="layui-item layui-col-sm6">
-					<label class="layui-form-label"><span class="require-item invoicetype">*</span>规格型号</label>
+					<label class="layui-form-label">规格型号</label>
 					<div class="layui-input-block">
-						<form:input id="specifications" path="specifications" htmlEscape="false"  placeholder="请输入规格型号"  class="form-control layui-input" required="true"/>
+						<form:input id="specifications" path="specifications" htmlEscape="false"  placeholder="请输入规格型号"  class="form-control layui-input"/>
 					</div>
 				</div>
 				<div class="layui-item layui-col-sm6">

+ 1 - 1
src/main/webapp/webpage/modules/workinvoice/workInvoiceAuditEnd.jsp

@@ -704,7 +704,7 @@
 			<div class="layui-item layui-col-sm6 redInvoice">
 				<label class="layui-form-label">关联发票号:</label>
 				<div class="layui-input-block">
-					<input id="invoiceNumberStr" htmlEscape="false" readonly="true" class="form-control layui-input" value=""/>
+					<input id="invoiceNumberStr" htmlEscape="false" readonly="true" class="form-control layui-input" value="${workInvoice.invoiceNumberStr}"/>
 				</div>
 			</div>
 			<div class="layui-item layui-col-sm12">

+ 1 - 1
src/main/webapp/webpage/modules/workinvoice/workInvoiceModify.jsp

@@ -1212,7 +1212,7 @@
 				<div class="layui-item layui-col-sm6 redInvoice">
 					<label class="layui-form-label">关联发票号:</label>
 					<div class="layui-input-block">
-						<input id="invoiceNumberStr" htmlEscape="false" readonly="true" class="form-control layui-input" value=""/>
+						<input id="invoiceNumberStr" htmlEscape="false" readonly="true" class="form-control layui-input" value="${workInvoice.invoiceNumberStr}"/>
 					</div>
 				</div>
 

ファイルの差分が大きいため隠しています
+ 169 - 101
src/main/webapp/webpage/modules/workstaff/qualificationForm.jsp


ファイルの差分が大きいため隠しています
+ 100 - 11
src/main/webapp/webpage/modules/workstaff/workStaffBasicDetailForm.jsp


ファイルの差分が大きいため隠しています
+ 103 - 12
src/main/webapp/webpage/modules/workstaff/workStaffBasicDetailModify.jsp


+ 1 - 1
src/main/webapp/webpage/modules/workstaff/workStaffBasicInfoDimissionList.jsp

@@ -243,7 +243,7 @@
             <div class="contentShadow layui-form contentDetails">
                 <div class="nav-btns">
                     <div class="layui-btn-group">
-                        <shiro:hasPermission name="workstaff:workStaffBasicInfo:export">
+                        <shiro:hasPermission name="workstaff:workStaffBasicInfoDimission:export">
                             <table:exportExcel url="${ctx}/workstaff/workStaffBasicInfoDimission/exportAchive"></table:exportExcel><!-- 导出按钮 -->
                         </shiro:hasPermission>
                         <button class="layui-btn layui-btn-sm" data-toggle="tooltip" data-placement="left" onclick="sortOrRefresh()" title="刷新"> 刷新</button>

+ 3 - 3
src/main/webapp/webpage/modules/workstaff/workStaffBasicInfoEmploymentInList.jsp

@@ -251,10 +251,10 @@
             <div class="contentShadow layui-form contentDetails">
                 <div class="nav-btns">
                     <div class="layui-btn-group">
-                        <shiro:hasPermission name="workstaff:workStaffBasicInfo:add">
-                            <table:addRow url="${ctx}/workstaff/workStaffBasicInfoEmploymentIn/form" title="员工信息"></table:addRow><!-- 增加按钮 -->
+                        <shiro:hasPermission name="workstaff:workStaffBasicInfoEmploymentIn:add">
+                            <table:addRow url="${ctx}/workstaff/workStaffBasicInfoEmploymentIn/form" title="返聘员工信息"></table:addRow><!-- 增加按钮 -->
                         </shiro:hasPermission>
-                        <shiro:hasPermission name="workstaff:workStaffBasicInfo:export">
+                        <shiro:hasPermission name="workstaff:workStaffBasicInfoEmploymentIn:export">
                             <table:exportExcel url="${ctx}/workstaff/workStaffBasicInfoEmploymentIn/exportAchive"></table:exportExcel><!-- 导出按钮 -->
                         </shiro:hasPermission>
                         <button class="layui-btn layui-btn-sm" data-toggle="tooltip" data-placement="left" onclick="sortOrRefresh()" title="刷新"> 刷新</button>

+ 1 - 0
src/main/webapp/webpage/modules/workstaff/workStaffBasicInfoForm.jsp

@@ -312,6 +312,7 @@
                 checkMobile();
 
             });
+            certificateList();
 
             var certificateList = JSON.parse('${fns:toJson(workStaffBasicInfo.certificateList)}');
 

+ 28 - 23
src/main/webapp/webpage/modules/workstaff/workStaffBasicInfoView.jsp

@@ -300,43 +300,48 @@
                         </div>
                     </div>
                     <div class="layui-item layui-col-sm6 lw7">
-                        <label class="layui-form-label double-line"><span class="require-item">*</span>身份证人像面:</label>
+                        <label class="layui-form-label double-line">身份证人像面:</label>
                         <div class="layui-input-block">
+                            <a class="op-btn op-btn-add" title="上传" onclick="this_upload_file_button('idCardPortrait')"><i class="fa fa-plus"></i>&nbsp;上传</a>
                             <!-- 图片展示区域 -->
                             <span id="idCardPortraitName1">
-                              <c:if test="${not empty workStaffBasicInfo.idCardPortraitPathStr}">
-                                <div style="position:relative; display:inline-block;">
-                                  <img src="${workStaffBasicInfo.idCardPortraitPathStr}" width="50" height="50" style="cursor:pointer;" onclick="openLayerPreview('${workStaffBasicInfo.idCardPortraitPathStr}')" alt="身份证照片">
-                                </div>
-                                  <!-- 下载按钮(重点)-->
-                                  <a href="javascript:void(0);" title="下载 ${workStaffBasicInfo.idCardPortraitName}" style="color: #28a745; margin-left: 5px; text-decoration: none;" onclick="downloadFile('${ctx}', '${workStaffBasicInfo.idCardPortraitPath}', '${workStaffBasicInfo.idCardPortraitName}')"><i class="fa fa-download"></i></a>
-                              </c:if>
-                            </span>
-
-                            <!-- ✅ 后端路径字段(用于提交) -->
-                            <input type="hidden" id="idCardPortraitName" name="idCardPortraitName" value="${workStaffBasicInfo.idCardPortraitName}">
+                          <c:if test="${not empty workStaffBasicInfo.idCardPortraitPathStr}">
+                            <div style="position:relative; display:inline-block;">
+                              <img src="${workStaffBasicInfo.idCardPortraitPathStr}" width="50" height="50" style="cursor:pointer;" onclick="openLayerPreview('${workStaffBasicInfo.idCardPortraitPathStr}')" alt="身份证照片">
+                                <!-- 删除按钮 -->
+                              <i class="fa fa-times-circle" style="position:absolute; top:-8px; right:-8px; color:red; cursor:pointer;" onclick="deleteImage('idCardPortraitName1', 'idCardPortrait')"></i>
+                            </div>
+                              <!-- 下载按钮(重点)-->
+                              <a href="javascript:void(0);" title="下载 ${workStaffBasicInfo.idCardPortraitName}" style="color: #28a745; margin-left: 5px; text-decoration: none;" onclick="downloadFile('${ctx}', '${workStaffBasicInfo.idCardPortraitPath}', '${workStaffBasicInfo.idCardPortraitName}')"><i class="fa fa-download"></i></a>
+                          </c:if>
+                        </span>
+                            <!-- 文件上传控件 -->
+                            <input id="idCardPortrait" name="idCardPortrait" style="display:none" type="file" onchange="changeIdCardFileName(this,1)" />
                             <!-- ✅ 后端路径字段(用于提交) -->
                             <input type="hidden" id="idCardPortraitPath" name="idCardPortraitPath" value="${workStaffBasicInfo.idCardPortraitPath}">
                         </div>
                     </div>
 
-
                     <div class="layui-item layui-col-sm6 lw7">
-                        <label class="layui-form-label double-line"><span class="require-item">*</span>身份证国徽面:</label>
+                        <label class="layui-form-label double-line">身份证国徽面:</label>
                         <div class="layui-input-block">
+                            <a class="op-btn op-btn-add" title="上传" onclick="this_upload_file_button('idCardNationalEmblem')"><i class="fa fa-plus"></i>&nbsp;上传</a>
                             <!-- 图片展示区域 -->
                             <span id="idCardNationalEmblemName1">
-                              <c:if test="${not empty workStaffBasicInfo.idCardNationalEmblemPathStr}">
-                                <div style="position:relative; display:inline-block;">
-                                  <img src="${workStaffBasicInfo.idCardNationalEmblemPathStr}" width="50" height="50" style="cursor:pointer;" onclick="openLayerPreview('${workStaffBasicInfo.idCardNationalEmblemPathStr}')" alt="身份证照片">
-                                </div>
-                                  <!-- 下载按钮 -->
-                                  <a href="javascript:void(0);" title="下载 ${workStaffBasicInfo.idCardNationalEmblemName}" style="color: #28a745; margin-left: 5px; text-decoration: none;" onclick="downloadFile('${ctx}', '${workStaffBasicInfo.idCardNationalEmblemPath}', '${workStaffBasicInfo.idCardNationalEmblemName}')"><i class="fa fa-download"></i></a>
+                          <c:if test="${not empty workStaffBasicInfo.idCardNationalEmblemPathStr}">
+                            <div style="position:relative; display:inline-block;">
+                              <img src="${workStaffBasicInfo.idCardNationalEmblemPathStr}" width="50" height="50" style="cursor:pointer;" onclick="openLayerPreview('${workStaffBasicInfo.idCardNationalEmblemPathStr}')" alt="身份证照片">
+                                <!-- 删除按钮 -->
+                              <i class="fa fa-times-circle" style="position:absolute; top:-8px; right:-8px; color:red; cursor:pointer;" onclick="deleteImage('idCardNationalEmblemName1', 'idCardNationalEmblem')"></i>
+                            </div>
+                              <!-- 下载按钮 -->
+                              <a href="javascript:void(0);" title="下载 ${workStaffBasicInfo.idCardNationalEmblemName}" style="color: #28a745; margin-left: 5px; text-decoration: none;" onclick="downloadFile('${ctx}', '${workStaffBasicInfo.idCardNationalEmblemPath}', '${workStaffBasicInfo.idCardNationalEmblemName}')"><i class="fa fa-download"></i></a>
 
-                              </c:if>
-                            </span>
+                          </c:if>
+                        </span>
+                            <!-- 文件上传控件 -->
+                            <input id="idCardNationalEmblem" name="idCardNationalEmblem" style="display:none" type="file" onchange="changeIdCardFileName(this,1)" />
                             <!-- ✅ 后端路径字段(用于提交) -->
-                            <input type="hidden" id="idCardNationalEmblemName" name="idCardNationalEmblemName" value="${workStaffBasicInfo.idCardNationalEmblemName}">
                             <input type="hidden" id="idCardNationalEmblemPath" name="idCardNationalEmblemPath" value="${workStaffBasicInfo.idCardNationalEmblemPath}">
                         </div>
                     </div>