yuansh 1 неделя назад
Родитель
Сommit
cf3f168048
47 измененных файлов с 2259 добавлено и 95 удалено
  1. 17 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysDictController.java
  2. 2 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysDepartMapper.java
  3. 3 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysDictMapper.java
  4. 4 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysDepartMapper.xml
  5. 6 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysDictMapper.xml
  6. 2 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysDepartService.java
  7. 1 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysDictService.java
  8. 4 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysDepartServiceImpl.java
  9. 6 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysDictServiceImpl.java
  10. 33 0
      srm-module-code/src/main/java/org/jeecg/modules/baseCode/controller/BaseProductClassController.java
  11. 3 0
      srm-module-code/src/main/java/org/jeecg/modules/baseCode/entity/BaseProductClass.java
  12. 3 1
      srm-module-code/src/main/java/org/jeecg/modules/cuspCode/controller/CuspCustomerProfileController.java
  13. 15 3
      srm-module-code/src/main/java/org/jeecg/modules/cuspCode/controller/CuspSupplierProfileController.java
  14. 42 42
      srm-module-code/src/main/java/org/jeecg/modules/cuspCode/service/impl/CuspSupplierProfileServiceImpl.java
  15. 239 0
      srm-module-code/src/main/java/org/jeecg/modules/otherCode/controller/SysEmailDraftController.java
  16. 309 0
      srm-module-code/src/main/java/org/jeecg/modules/otherCode/controller/SysMailConfigController.java
  17. 152 0
      srm-module-code/src/main/java/org/jeecg/modules/otherCode/entity/SysEmailDraft.java
  18. 159 0
      srm-module-code/src/main/java/org/jeecg/modules/otherCode/entity/SysMailConfig.java
  19. 17 0
      srm-module-code/src/main/java/org/jeecg/modules/otherCode/mapper/SysEmailDraftMapper.java
  20. 17 0
      srm-module-code/src/main/java/org/jeecg/modules/otherCode/mapper/SysMailConfigMapper.java
  21. 5 0
      srm-module-code/src/main/java/org/jeecg/modules/otherCode/mapper/xml/SysEmailDraftMapper.xml
  22. 5 0
      srm-module-code/src/main/java/org/jeecg/modules/otherCode/mapper/xml/SysMailConfigMapper.xml
  23. 15 0
      srm-module-code/src/main/java/org/jeecg/modules/otherCode/service/ISysEmailDraftService.java
  24. 14 0
      srm-module-code/src/main/java/org/jeecg/modules/otherCode/service/ISysMailConfigService.java
  25. 293 0
      srm-module-code/src/main/java/org/jeecg/modules/otherCode/service/impl/SysEmailDraftServiceImpl.java
  26. 19 0
      srm-module-code/src/main/java/org/jeecg/modules/otherCode/service/impl/SysMailConfigServiceImpl.java
  27. 194 23
      srm-module-code/src/main/java/org/jeecg/modules/purCode/controller/PurInquiryFormController.java
  28. 9 0
      srm-module-code/src/main/java/org/jeecg/modules/purCode/controller/PurOrderController.java
  29. 4 1
      srm-module-code/src/main/java/org/jeecg/modules/purCode/entity/PurInquiryForm.java
  30. 1 0
      srm-module-code/src/main/java/org/jeecg/modules/purCode/mapper/PurInquiryFormMapper.java
  31. 2 1
      srm-module-code/src/main/java/org/jeecg/modules/purCode/mapper/PurInquiryFormProductMapper.java
  32. 5 0
      srm-module-code/src/main/java/org/jeecg/modules/purCode/mapper/xml/PurInquiryFormMapper.xml
  33. 61 1
      srm-module-code/src/main/java/org/jeecg/modules/purCode/mapper/xml/PurInquiryFormProductMapper.xml
  34. 2 1
      srm-module-code/src/main/java/org/jeecg/modules/purCode/service/IPurInquiryFormProductService.java
  35. 2 1
      srm-module-code/src/main/java/org/jeecg/modules/purCode/service/impl/PurInquiryFormProductServiceImpl.java
  36. 4 0
      srm-module-code/src/main/java/org/jeecg/modules/purCode/vo/PurInquiryFormAlert.java
  37. 2 0
      srm-module-code/src/main/java/org/jeecg/modules/purCode/vo/PurInquiryFormPage.java
  38. 52 10
      srm-module-code/src/main/java/org/jeecg/modules/saleCode/controller/SaleInquiryFormController.java
  39. 22 0
      srm-module-code/src/main/java/org/jeecg/modules/saleCode/controller/SaleInvoiceController.java
  40. 48 0
      srm-module-code/src/main/java/org/jeecg/modules/saleCode/controller/SaleQuotationController.java
  41. 4 0
      srm-module-code/src/main/java/org/jeecg/modules/saleCode/entity/SaleInvoice.java
  42. 6 0
      srm-module-code/src/main/java/org/jeecg/modules/saleCode/entity/SaleQuotation.java
  43. 1 1
      srm-module-code/src/main/java/org/jeecg/modules/saleCode/entity/SaleQuotationProduct.java
  44. 346 6
      srm-module-code/src/main/java/org/jeecg/modules/saleCode/service/impl/SaleInterfaceSyncServiceImpl.java
  45. 50 0
      srm-module-code/src/main/java/org/jeecg/modules/saleCode/util/CoordinateTextStripper.java
  46. 1 1
      srm-module-code/src/main/java/org/jeecg/modules/saleCode/vo/SaleInquiryFormAlert.java
  47. 58 3
      srm-module-code/src/main/java/org/jeecg/modules/utils/ExcelExportUtils.java

+ 17 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysDictController.java

@@ -51,6 +51,7 @@ import javax.servlet.http.HttpServletResponse;
 import java.io.UnsupportedEncodingException;
 import java.net.URLDecoder;
 import java.util.*;
+import java.util.stream.Collectors;
 
 /**
  * <p>
@@ -139,6 +140,22 @@ public class SysDictController {
 		return result;
 	}
 
+	/**
+	 *
+	 * @return
+	 */
+	@RequestMapping(value = "/selectAgreement", method = RequestMethod.GET)
+	public Result<?> selectAgreement(HttpServletRequest request) {
+		List<DictModel> res = sysDictService.selectAgreement();
+		List<Map<String, Object>> result = res.stream().map(option -> {
+			Map<String, Object> map = new HashMap<>();
+			map.put("key", option.getLabel());
+			map.put("label", option.getLabel());
+			map.put("value", option.getValue());
+			return map;
+		}).collect(Collectors.toList());
+		return Result.ok(result);
+	}
 	/**
 	 * 获取全部字典数据
 	 *

+ 2 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysDepartMapper.java

@@ -35,6 +35,8 @@ public interface SysDepartMapper extends BaseMapper<SysDepart> {
 	 */
 	public List<SysDepart> queryUserDeparts(@Param("userId") String userId);
 
+	public List<SysDepart> queryDeptByName(@Param("departName") String departName);
+
 	/**
 	 * 根据用户名查询部门
 	 *

+ 3 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysDictMapper.java

@@ -50,6 +50,9 @@ public interface SysDictMapper extends BaseMapper<SysDict> {
      */
 	public List<DictModel> queryDictItemsByCode(@Param("code") String code);
 
+
+	public List<DictModel> selectAgreement();
+
 	/**
 	 * 查询有效的数据字典项
 	 * @param code

+ 4 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysDepartMapper.xml

@@ -67,6 +67,10 @@
     <select id="queryDeptByCode" resultType="org.jeecg.modules.system.entity.SysDepart">
 		select * from sys_depart where del_flag = '0' and org_code= #{orgCode,jdbcType=VARCHAR}
 	</select>
+    <!-- 根据Cod查询公司信息 -->
+    <select id="queryDeptByName" resultType="org.jeecg.modules.system.entity.SysDepart">
+		select * from sys_depart where del_flag = '0' and depart_name= #{departName,jdbcType=VARCHAR}
+	</select>
 
     <!--通过父级id和租户id查询部门-->
     <select id="queryBookDepTreeSync" resultType="org.jeecg.modules.system.entity.SysDepart">

+ 6 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysDictMapper.xml

@@ -2,6 +2,12 @@
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="org.jeecg.modules.system.mapper.SysDictMapper">
 
+	<select id="selectAgreement" parameterType="String" resultType="org.jeecg.common.system.vo.DictModel">
+
+		select s.name as "text",s.content as "value" from base_agreement_terms s order by create_time desc
+
+	</select>
+
 	<select id="selectByChild" parameterType="String" resultType="org.jeecg.common.system.vo.DictModel">
 
 		select s.item_value as "value",s.item_text as "text",s.item_color as color from sys_dict_item s

+ 2 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysDepartService.java

@@ -246,4 +246,6 @@ public interface ISysDepartService extends IService<SysDepart>{
     void importSysDepart(List<SysDepartExportVo> listSysDeparts, List<String> errorMessageList);
 
     public String queryNameByCode(String code);
+
+    public List<SysDepart> queryDeptByName(String code);
 }

+ 1 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysDictService.java

@@ -22,6 +22,7 @@ import java.util.Map;
  */
 public interface ISysDictService extends IService<SysDict> {
 
+	public List<DictModel> selectAgreement();
 	/**
 	 * 根据名称获取 协议条款
 	 * @param name

+ 4 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysDepartServiceImpl.java

@@ -920,6 +920,10 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
 	public String queryNameByCode(String code) {
 		return departMapper.queryNameByCode(code);
 	}
+	@Override
+	public List<SysDepart> queryDeptByName(String code) {
+		return departMapper.queryDeptByName(code);
+	}
 
 	@Override
 	public IPage<SysDepart> getMaxCodeDepart(Page<SysDepart> page, String parentId) {

+ 6 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysDictServiceImpl.java

@@ -74,6 +74,12 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
 	@Autowired
 	private RedisUtil redisUtil;
 
+
+	@Override
+	public List<DictModel> selectAgreement(){
+		return sysDictMapper.selectAgreement();
+	}
+
 	@Override
 	public String queryDescriptionByKey(String code){
 		return sysDictMapper.queryDescriptionByKey(code);

+ 33 - 0
srm-module-code/src/main/java/org/jeecg/modules/baseCode/controller/BaseProductClassController.java

@@ -18,6 +18,8 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import lombok.extern.slf4j.Slf4j;
 
 import org.jeecg.common.system.base.controller.JeecgController;
+import org.jeecg.modules.system.entity.SysDepart;
+import org.jeecg.modules.system.service.ISysDepartService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.servlet.ModelAndView;
@@ -41,6 +43,8 @@ public class BaseProductClassController extends JeecgController<BaseProductClass
     private IBaseProductClassService baseProductClassService;
     @Autowired
     private ISerialPatternService serialPatternService;
+    @Autowired
+    private ISysDepartService sysDepartService;
 
     /**
      * 分页列表查询
@@ -231,6 +235,35 @@ public class BaseProductClassController extends JeecgController<BaseProductClass
         return Result.OK(baseProductClass);
     }
 
+    /**
+     * 通过id查询
+     *
+     * @param id
+     * @return
+     */
+    //@AutoLog(value = "产品分类-通过id查询")
+    @ApiOperation(value = "产品分类-通过id查询", notes = "产品分类-通过id查询")
+    @GetMapping(value = "/queryByIdAndOrg")
+    public Result<BaseProductClass> queryByIdAndOrg(@RequestParam(name = "id", required = true) String id) {
+        BaseProductClass baseProductClass = baseProductClassService.getById(id);
+        if (baseProductClass == null) {
+            return Result.error("未找到对应数据");
+        }
+        if(StringUtils.isNotBlank(baseProductClass.getBusinessAttribute())){
+
+            if("SALES".equals(baseProductClass.getBusinessAttribute())){
+
+                baseProductClass.setBusinessAttribute("SALES");
+                return Result.OK(baseProductClass);
+            }
+            SysDepart sysDepart = sysDepartService.queryDeptByCode(baseProductClass.getBusinessAttribute());
+            if(sysDepart != null){
+                baseProductClass.setBusinessAttribute(sysDepart.getId());
+            }
+        }
+        return Result.OK(baseProductClass);
+    }
+
 
     /**
      * 通过id查询

+ 3 - 0
srm-module-code/src/main/java/org/jeecg/modules/baseCode/entity/BaseProductClass.java

@@ -43,6 +43,9 @@ public class BaseProductClass implements Serializable {
     private String createBy;
     private String sysOrgCode;
 
+    //业务属性(SALES/PURCHASE/BOTH)采购,销售,通用
+    private String businessAttribute;
+
 	/**创建时间*/
 	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
     @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")

+ 3 - 1
srm-module-code/src/main/java/org/jeecg/modules/cuspCode/controller/CuspCustomerProfileController.java

@@ -102,6 +102,7 @@ public class CuspCustomerProfileController {
 	public Result<String> add(@RequestBody CuspCustomerProfilePage cuspCustomerProfilePage) {
 
 		String name = cuspCustomerProfilePage.getName();
+		String code = cuspCustomerProfilePage.getCode();
 		if (StringUtils.isNotBlank(name)) {
 
 			QueryWrapper<CuspCustomerProfile> queryWrapper = new QueryWrapper();
@@ -112,7 +113,8 @@ public class CuspCustomerProfileController {
 			if (list.size() != 0) {
 				return Result.error("客户档案名称重复,请修改!");
 			}
-		} else {
+		}
+		if(StringUtils.isBlank(code)) {
 
 			Result<String> result = serialPatternService.getNextSerial("cusp_customer_profile", "code");
 			if (!result.isSuccess()) {

+ 15 - 3
srm-module-code/src/main/java/org/jeecg/modules/cuspCode/controller/CuspSupplierProfileController.java

@@ -25,6 +25,7 @@ import org.apache.commons.lang.StringUtils;
 import org.jeecg.modules.cuspCode.entity.CuspSupplierProfile;
 import org.jeecg.modules.cuspCode.entity.CuspSupplierProfileMan;
 import org.jeecg.modules.cuspCode.entity.CuspSupplierProfileQualification;
+import org.jeecg.modules.message.handle.impl.EmailSendMsgHandle;
 import org.jeecg.modules.system.service.ISysDictService;
 import org.jeecgframework.poi.excel.ExcelImportUtil;
 import org.jeecgframework.poi.excel.def.NormalExcelConstants;
@@ -80,6 +81,8 @@ public class CuspSupplierProfileController {
     ISysBaseAPI sysBaseAPI;
     @Autowired
     private ISysDictService sysDictService;
+    @Autowired
+    private EmailSendMsgHandle emailSendMsgHandle;
 
 
     /**
@@ -101,7 +104,7 @@ public class CuspSupplierProfileController {
         // 自定义查询规则
         Map<String, QueryRuleEnum> customeRuleMap = new HashMap<>();
         // 自定义多选的查询规则为:LIKE_WITH_OR
-        customeRuleMap.put("status", QueryRuleEnum.LIKE_WITH_OR);
+        customeRuleMap.put("status", QueryRuleEnum.EQ);
         customeRuleMap.put("supplierNature", QueryRuleEnum.LIKE_WITH_OR);
         customeRuleMap.put("country", QueryRuleEnum.LIKE_WITH_OR);
         customeRuleMap.put("originalFactory", QueryRuleEnum.LIKE_WITH_OR);
@@ -173,6 +176,7 @@ public class CuspSupplierProfileController {
 
 
         String name = cuspSupplierProfilePage.getName();
+        String code = cuspSupplierProfilePage.getCode();
         if (StringUtils.isNotBlank(name)) {
 
             QueryWrapper<CuspSupplierProfile> queryWrapper = new QueryWrapper();
@@ -184,7 +188,9 @@ public class CuspSupplierProfileController {
             if (list.size() != 0) {
                 return Result.error("供应商档案名称重复,请修改!");
             }
-        } else {
+        }
+
+        if(StringUtils.isBlank(code)) {
 
             Result<String> result = serialPatternService.getNextSerial("cusp_supplier_profile", "code");
             if (!result.isSuccess()) {
@@ -361,8 +367,14 @@ public class CuspSupplierProfileController {
         cuspSupplierProfile.setReasonFor(info);
         cuspSupplierProfileService.updateById(cuspSupplierProfile);
 
-        sendSysAnnouncement(ent.getCreateBy(),ent.getName(),st,info);
+        if(StringUtils.isNotBlank(ent.getCreateBy())){
 
+            sendSysAnnouncement(ent.getCreateBy(),ent.getName(),st,info);
+        }
+//        String es_receiver = "1059252703@qq.com";
+//        String es_title = "jeecg测试邮件2";
+//        String es_content = "测试内容2";
+//        emailSendMsgHandle.sendMsg(es_receiver ,es_title ,es_content );
         return Result.OK("执行成功!");
     }
 

+ 42 - 42
srm-module-code/src/main/java/org/jeecg/modules/cuspCode/service/impl/CuspSupplierProfileServiceImpl.java

@@ -163,8 +163,8 @@ public class CuspSupplierProfileServiceImpl extends ServiceImpl<CuspSupplierProf
 
 		StringBuffer sb = new StringBuffer();
 
-		LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
-		String loginCode = sysUser.getUsername();
+//		LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+//		String loginCode = sysUser.getUsername();
 
 		for(Serializable id:idList) {
 			CuspSupplierProfile supplierProfile = cuspSupplierProfileMapper.selectById(id);
@@ -182,49 +182,49 @@ public class CuspSupplierProfileServiceImpl extends ServiceImpl<CuspSupplierProf
 				continue;
 			}
 
-			String approveNow = supplierProfile.getApproveNow();
-			String approveNowName = supplierProfile.getApproveNowName();
-			if(!loginCode.equals(approveNow)){
-				sb.append("供应商 "+name+"当前审批人为:").append(approveNowName+";");
-				continue;
-			}
-
-			String approveAll = supplierProfile.getApproveAll();
-			String approveHis = supplierProfile.getApproveHis();
-
-			if(StringUtils.isBlank(approveHis)){
-				approveHis = approveNow;
-			}else{
-				approveHis = approveHis+","+approveNow;
-			}
-			supplierProfile.setApproveHis(approveHis);
-
-			if(approveHis.equals(approveAll)){
-
+//			String approveNow = supplierProfile.getApproveNow();
+//			String approveNowName = supplierProfile.getApproveNowName();
+//			if(!loginCode.equals(approveNow)){
+//				sb.append("供应商 "+name+"当前审批人为:").append(approveNowName+";");
+//				continue;
+//			}
+
+//			String approveAll = supplierProfile.getApproveAll();
+//			String approveHis = supplierProfile.getApproveHis();
+//
+//			if(StringUtils.isBlank(approveHis)){
+//				approveHis = approveNow;
+//			}else{
+//				approveHis = approveHis+","+approveNow;
+//			}
+//			supplierProfile.setApproveHis(approveHis);
+
+//			if(approveHis.equals(approveAll)){
+//
 				supplierProfile.setApproveNow("审批完成");
 				supplierProfile.setApproveNowName("审批完成");
 				supplierProfile.setTemporarySupplier(2);//临时供应商(0-是,1-申请中,2-否)
-
-			}else{
-
-				String[] approves = approveAll.split(",");
-				int index = getCharIndex(approves, approveNow);
-
-				String nowApp = approves[index+1];
-
-				supplierProfile.setApproveNow(nowApp);
-
-				SysUser user = sysUserService.getUserByName(nowApp);
-
-				if(user == null){
-					sb.append("供应商 "+name+"下一级审批人异常,请维护;");
-					continue;
-				}
-
-				supplierProfile.setApproveNowName(user.getRealname());
-
-				supplierProfile.setTemporarySupplier(1);//临时供应商(0-是,1-申请中,2-否)
-			}
+//
+//			}else{
+//
+//				String[] approves = approveAll.split(",");
+//				int index = getCharIndex(approves, approveNow);
+//
+//				String nowApp = approves[index+1];
+//
+//				supplierProfile.setApproveNow(nowApp);
+//
+//				SysUser user = sysUserService.getUserByName(nowApp);
+//
+//				if(user == null){
+//					sb.append("供应商 "+name+"下一级审批人异常,请维护;");
+//					continue;
+//				}
+//
+//				supplierProfile.setApproveNowName(user.getRealname());
+//
+//				supplierProfile.setTemporarySupplier(1);//临时供应商(0-是,1-申请中,2-否)
+//			}
 
 
 			cuspSupplierProfileMapper.updateById(supplierProfile);

+ 239 - 0
srm-module-code/src/main/java/org/jeecg/modules/otherCode/controller/SysEmailDraftController.java

@@ -0,0 +1,239 @@
+package org.jeecg.modules.otherCode.controller;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang.StringUtils;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.aspect.annotation.PermissionData;
+import org.jeecg.common.system.query.QueryGenerator;
+import org.jeecg.common.system.query.QueryRuleEnum;
+import org.jeecg.common.util.oConvertUtils;
+import org.jeecg.modules.baseCode.service.ISerialPatternService;
+import org.jeecg.modules.otherCode.entity.SysEmailDraft;
+import org.jeecg.modules.otherCode.service.ISysEmailDraftService;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.extern.slf4j.Slf4j;
+
+import org.jeecgframework.poi.excel.ExcelImportUtil;
+import org.jeecgframework.poi.excel.def.NormalExcelConstants;
+import org.jeecgframework.poi.excel.entity.ExportParams;
+import org.jeecgframework.poi.excel.entity.ImportParams;
+import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
+import org.jeecg.common.system.base.controller.JeecgController;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.multipart.MultipartHttpServletRequest;
+import org.springframework.web.servlet.ModelAndView;
+import com.alibaba.fastjson.JSON;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.jeecg.common.aspect.annotation.AutoLog;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+
+ /**
+ * @Description: 邮件草稿箱
+ * @Author: jeecg-boot
+ * @Date:   2026-03-23
+ * @Version: V1.0
+ */
+@Api(tags="邮件草稿箱")
+@RestController
+@RequestMapping("/otherCode/sysEmailDraft")
+@Slf4j
+public class SysEmailDraftController extends JeecgController<SysEmailDraft, ISysEmailDraftService> {
+	@Autowired
+	private ISysEmailDraftService sysEmailDraftService;
+	 @Autowired
+	 private ISerialPatternService serialPatternService;
+
+
+	 /**
+	 * 分页列表查询
+	 *
+	 * @param sysEmailDraft
+	 * @param pageNo
+	 * @param pageSize
+	 * @param req
+	 * @return
+	 */
+	//@AutoLog(value = "邮件草稿箱-分页列表查询")
+	@ApiOperation(value="邮件草稿箱-分页列表查询", notes="邮件草稿箱-分页列表查询")
+	@GetMapping(value = "/list")
+	@PermissionData(pageComponent = "otherCode/sysEmailDraft/sysEmailDraftList")
+	public Result<IPage<SysEmailDraft>> queryPageList(SysEmailDraft sysEmailDraft,
+								   @RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
+								   @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
+								   HttpServletRequest req) {
+        QueryWrapper<SysEmailDraft> queryWrapper = QueryGenerator.initQueryWrapper(sysEmailDraft, req.getParameterMap());
+		Page<SysEmailDraft> page = new Page<SysEmailDraft>(pageNo, pageSize);
+		IPage<SysEmailDraft> pageList = sysEmailDraftService.page(page, queryWrapper);
+		return Result.OK(pageList);
+	}
+	
+	/**
+	 *   添加
+	 *
+	 * @param sysEmailDraft
+	 * @return
+	 */
+	@AutoLog(value = "邮件草稿箱-添加")
+	@ApiOperation(value="邮件草稿箱-添加", notes="邮件草稿箱-添加")
+	@RequiresPermissions("otherCode:sys_email_draft:add")
+	@PostMapping(value = "/add")
+	public Result<String> add(@RequestBody SysEmailDraft sysEmailDraft) {
+		String code = sysEmailDraft.getCode();
+		if(StringUtils.isBlank(code)) {
+			Result<String> result = serialPatternService.getNextSerial("sys_email_draft", "code");
+			if (!result.isSuccess()) {
+				return result;
+			}
+			sysEmailDraft.setCode(result.getMessage());
+		}
+
+		sysEmailDraft.setStatus("草稿");
+		sysEmailDraftService.save(sysEmailDraft);
+
+		//save,saveAndSend
+		String submitSt = sysEmailDraft.getSubmitSt();
+		if(StringUtils.isNotBlank(submitSt) && submitSt.equals("saveAndSend")){
+
+			Result<String> result = this.sysEmailDraftService.sendBatch(sysEmailDraft.getId());
+			return result;
+		}
+
+		return Result.OK("添加成功!");
+	}
+	
+	/**
+	 *  编辑
+	 *
+	 * @param sysEmailDraft
+	 * @return
+	 */
+	@AutoLog(value = "邮件草稿箱-编辑")
+	@ApiOperation(value="邮件草稿箱-编辑", notes="邮件草稿箱-编辑")
+	@RequiresPermissions("otherCode:sys_email_draft:edit")
+	@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
+	public Result<String> edit(@RequestBody SysEmailDraft sysEmailDraft) {
+		String code = sysEmailDraft.getCode();
+		if(StringUtils.isBlank(code)) {
+			Result<String> result = serialPatternService.getNextSerial("sys_email_draft", "code");
+			if (!result.isSuccess()) {
+				return result;
+			}
+			sysEmailDraft.setCode(result.getMessage());
+		}
+		sysEmailDraft.setStatus("草稿");
+		sysEmailDraftService.updateById(sysEmailDraft);
+
+		//save,saveAndSend
+		String submitSt = sysEmailDraft.getSubmitSt();
+		if(StringUtils.isNotBlank(submitSt) && submitSt.equals("saveAndSend")){
+
+			Result<String> result = this.sysEmailDraftService.sendBatch(sysEmailDraft.getId());
+			return result;
+		}
+
+		return Result.OK("编辑成功!");
+	}
+	
+	/**
+	 *   通过id删除
+	 *
+	 * @param id
+	 * @return
+	 */
+	@AutoLog(value = "邮件草稿箱-通过id删除")
+	@ApiOperation(value="邮件草稿箱-通过id删除", notes="邮件草稿箱-通过id删除")
+	@RequiresPermissions("otherCode:sys_email_draft:delete")
+	@DeleteMapping(value = "/delete")
+	public Result<String> delete(@RequestParam(name="id",required=true) String id) {
+		sysEmailDraftService.removeById(id);
+		return Result.OK("删除成功!");
+	}
+	
+	/**
+	 *  批量删除
+	 *
+	 * @param ids
+	 * @return
+	 */
+	@AutoLog(value = "邮件草稿箱-批量删除")
+	@ApiOperation(value="邮件草稿箱-批量删除", notes="邮件草稿箱-批量删除")
+	@RequiresPermissions("otherCode:sys_email_draft:deleteBatch")
+	@DeleteMapping(value = "/deleteBatch")
+	public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
+		this.sysEmailDraftService.removeByIds(Arrays.asList(ids.split(",")));
+		return Result.OK("批量删除成功!");
+	}
+
+	/**
+	 *  批量发送
+	 *
+	 * @param ids
+	 * @return
+	 */
+	@AutoLog(value = "邮件草稿箱-批量发送")
+	@ApiOperation(value="邮件草稿箱-批量发送", notes="邮件草稿箱-批量发送")
+	@GetMapping(value = "/sendBatch")
+	public Result<String> sendBatch(@RequestParam(name="ids",required=true) String ids) {
+
+		return this.sysEmailDraftService.sendBatch(ids);
+	}
+
+	/**
+	 * 通过id查询
+	 *
+	 * @param id
+	 * @return
+	 */
+	//@AutoLog(value = "邮件草稿箱-通过id查询")
+	@ApiOperation(value="邮件草稿箱-通过id查询", notes="邮件草稿箱-通过id查询")
+	@GetMapping(value = "/queryById")
+	public Result<SysEmailDraft> queryById(@RequestParam(name="id",required=true) String id) {
+		SysEmailDraft sysEmailDraft = sysEmailDraftService.getById(id);
+		if(sysEmailDraft==null) {
+			return Result.error("未找到对应数据");
+		}
+		return Result.OK(sysEmailDraft);
+	}
+
+    /**
+    * 导出excel
+    *
+    * @param request
+    * @param sysEmailDraft
+    */
+    @RequiresPermissions("otherCode:sys_email_draft:exportXls")
+    @RequestMapping(value = "/exportXls")
+    public ModelAndView exportXls(HttpServletRequest request, SysEmailDraft sysEmailDraft) {
+        return super.exportXls(request, sysEmailDraft, SysEmailDraft.class, "邮件草稿箱");
+    }
+
+    /**
+      * 通过excel导入数据
+    *
+    * @param request
+    * @param response
+    * @return
+    */
+    @RequiresPermissions("otherCode:sys_email_draft:importExcel")
+    @RequestMapping(value = "/importExcel", method = RequestMethod.POST)
+    public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
+        return super.importExcel(request, response, SysEmailDraft.class);
+    }
+
+}

+ 309 - 0
srm-module-code/src/main/java/org/jeecg/modules/otherCode/controller/SysMailConfigController.java

@@ -0,0 +1,309 @@
+package org.jeecg.modules.otherCode.controller;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.beanutils.BeanUtils;
+import org.apache.commons.lang.StringUtils;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.aspect.annotation.PermissionData;
+import org.jeecg.common.system.query.QueryGenerator;
+import org.jeecg.common.system.query.QueryRuleEnum;
+import org.jeecg.common.util.oConvertUtils;
+import org.jeecg.modules.cuspCode.entity.CuspSupplierProfile;
+import org.jeecg.modules.cuspCode.service.ICuspSupplierProfileService;
+import org.jeecg.modules.otherCode.entity.SysMailConfig;
+import org.jeecg.modules.otherCode.service.ISysMailConfigService;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.extern.slf4j.Slf4j;
+
+import org.jeecg.modules.purCode.controller.PurInquiryFormController;
+import org.jeecg.modules.purCode.entity.PurInquiryForm;
+import org.jeecg.modules.purCode.service.IPurInquiryFormService;
+import org.jeecg.modules.system.entity.SysDepart;
+import org.jeecg.modules.system.service.ISysDepartService;
+import org.jeecgframework.poi.excel.ExcelImportUtil;
+import org.jeecgframework.poi.excel.def.NormalExcelConstants;
+import org.jeecgframework.poi.excel.entity.ExportParams;
+import org.jeecgframework.poi.excel.entity.ImportParams;
+import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
+import org.jeecg.common.system.base.controller.JeecgController;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.multipart.MultipartHttpServletRequest;
+import org.springframework.web.servlet.ModelAndView;
+import com.alibaba.fastjson.JSON;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.jeecg.common.aspect.annotation.AutoLog;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+
+ /**
+ * @Description: 邮件配置
+ * @Author: jeecg-boot
+ * @Date:   2026-03-23
+ * @Version: V1.0
+ */
+@Api(tags="邮件配置")
+@RestController
+@RequestMapping("/otherCode/sysMailConfig")
+@Slf4j
+public class SysMailConfigController extends JeecgController<SysMailConfig, ISysMailConfigService> {
+	@Autowired
+	private ISysMailConfigService sysMailConfigService;
+	 @Autowired
+	 private IPurInquiryFormService purInquiryFormService;
+	 @Autowired
+	 private ICuspSupplierProfileService cuspSupplierProfileService;
+	 @Autowired
+	 private PurInquiryFormController purInquiryFormController;
+	 @Autowired
+	 private ISysDepartService sysDepartService;
+	/**
+	 * 分页列表查询
+	 *
+	 * @param sysMailConfig
+	 * @param pageNo
+	 * @param pageSize
+	 * @param req
+	 * @return
+	 */
+	//@AutoLog(value = "邮件配置-分页列表查询")
+	@ApiOperation(value="邮件配置-分页列表查询", notes="邮件配置-分页列表查询")
+	@GetMapping(value = "/list")
+	@PermissionData(pageComponent = "otherCode/sysMailConfig/sysMailConfigList")
+	public Result<IPage<SysMailConfig>> queryPageList(SysMailConfig sysMailConfig,
+								   @RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
+								   @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
+								   HttpServletRequest req) {
+        QueryWrapper<SysMailConfig> queryWrapper = QueryGenerator.initQueryWrapper(sysMailConfig, req.getParameterMap());
+		Page<SysMailConfig> page = new Page<SysMailConfig>(pageNo, pageSize);
+		IPage<SysMailConfig> pageList = sysMailConfigService.page(page, queryWrapper);
+		return Result.OK(pageList);
+	}
+	
+	/**
+	 *   添加
+	 *
+	 * @param sysMailConfig
+	 * @return
+	 */
+	@AutoLog(value = "邮件配置-添加")
+	@ApiOperation(value="邮件配置-添加", notes="邮件配置-添加")
+//	@RequiresPermissions("otherCode:sys_mail_config:add")
+	@PostMapping(value = "/add")
+	public Result<String> add(@RequestBody SysMailConfig sysMailConfig) {
+
+		if(StringUtils.isNotBlank(sysMailConfig.getDeptCode())){
+			String[] ids = sysMailConfig.getDeptCode().split(",");
+			String name = "";
+			for(String o:ids){
+				SysDepart dept = sysDepartService.getById(o);
+				if(StringUtils.isBlank(name)){
+					name = dept.getOrgCode();
+				}else{
+					name = name+","+dept.getOrgCode();
+				}
+			}
+			sysMailConfig.setDeptName(name);
+		}
+
+		sysMailConfigService.save(sysMailConfig);
+		return Result.OK("添加成功!");
+	}
+	
+	/**
+	 *  编辑
+	 *
+	 * @param sysMailConfig
+	 * @return
+	 */
+	@AutoLog(value = "邮件配置-编辑")
+	@ApiOperation(value="邮件配置-编辑", notes="邮件配置-编辑")
+//	@RequiresPermissions("otherCode:sys_mail_config:edit")
+	@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
+	public Result<String> edit(@RequestBody SysMailConfig sysMailConfig) {
+
+		if(StringUtils.isNotBlank(sysMailConfig.getDeptCode())){
+			String[] ids = sysMailConfig.getDeptCode().split(",");
+			String name = "";
+			for(String o:ids){
+				SysDepart dept = sysDepartService.getById(o);
+				if(StringUtils.isBlank(name)){
+					name = dept.getOrgCode();
+				}else{
+					name = name+","+dept.getOrgCode();
+				}
+			}
+			sysMailConfig.setDeptName(name);
+		}
+		sysMailConfigService.updateById(sysMailConfig);
+		return Result.OK("编辑成功!");
+	}
+	
+	/**
+	 *   通过id删除
+	 *
+	 * @param id
+	 * @return
+	 */
+	@AutoLog(value = "邮件配置-通过id删除")
+	@ApiOperation(value="邮件配置-通过id删除", notes="邮件配置-通过id删除")
+//	@RequiresPermissions("otherCode:sys_mail_config:delete")
+	@DeleteMapping(value = "/delete")
+	public Result<String> delete(@RequestParam(name="id",required=true) String id) {
+		sysMailConfigService.removeById(id);
+		return Result.OK("删除成功!");
+	}
+	
+	/**
+	 *  批量删除
+	 *
+	 * @param ids
+	 * @return
+	 */
+	@AutoLog(value = "邮件配置-批量删除")
+	@ApiOperation(value="邮件配置-批量删除", notes="邮件配置-批量删除")
+//	@RequiresPermissions("otherCode:sys_mail_config:deleteBatch")
+	@DeleteMapping(value = "/deleteBatch")
+	public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
+		this.sysMailConfigService.removeByIds(Arrays.asList(ids.split(",")));
+		return Result.OK("批量删除成功!");
+	}
+	
+	/**
+	 * 通过id查询
+	 *
+	 * @param id //配置id
+	 * @param sourceCode 询价单来源
+	 * @param draftId 草稿箱id,如果是编辑则存在,如果是新增则为空
+	 * @return
+	 */
+	//@AutoLog(value = "邮件配置-通过id查询")
+	@ApiOperation(value="邮件配置-通过id查询", notes="邮件配置-通过id查询")
+	@GetMapping(value = "/queryById")
+	public Result<SysMailConfig> queryById(@RequestParam(name="id",required=true) String id, String sourceCode, String draftId) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException, UnsupportedEncodingException {
+
+		SysMailConfig sysMailConfig = sysMailConfigService.getById(id);
+		if(sysMailConfig==null) {
+			return Result.error("未找到对应数据");
+		}
+
+		if(StringUtils.isNotBlank(sourceCode)){
+
+			String templateTitle = sysMailConfig.getTemplateTitle();
+			String templateString = sysMailConfig.getTemplateString();
+			if(StringUtils.isBlank(templateTitle)&&StringUtils.isBlank(templateString)){
+
+				return Result.OK(sysMailConfig);
+			}
+
+			QueryWrapper<PurInquiryForm> queryWrapper = new QueryWrapper<>();
+			queryWrapper.eq("bill_code",sourceCode);
+			queryWrapper.eq("del_flag",0);
+			List<PurInquiryForm> listEnt = purInquiryFormService.list(queryWrapper);
+			if(listEnt.size()>0){
+
+				String pkSupplier = listEnt.get(0).getInquirySuppiler();
+				String inquiryId = listEnt.get(0).getId();
+				if(StringUtils.isNotBlank(pkSupplier)){
+
+					CuspSupplierProfile cuspSupplierProfile = cuspSupplierProfileService.getById(pkSupplier);
+					if(cuspSupplierProfile != null){
+						sysMailConfig.setTempField(cuspSupplierProfile.getEmail());
+					}
+				}
+
+				Map<String, String> map = BeanUtils.describe(listEnt.get(0));
+
+				for (Map.Entry<String, String> entry : map.entrySet()) {
+					String str = "{" + entry.getKey() + "}";
+					if(StringUtils.isNotBlank(templateTitle)){
+
+						templateTitle = templateTitle.replace(str, entry.getValue()==null?"":entry.getValue());
+					}
+					if(StringUtils.isNotBlank(templateString)){
+
+						templateString = templateString.replace(str, entry.getValue()==null?"":entry.getValue());
+					}
+				}
+				sysMailConfig.setTemplateTitle(templateTitle);
+				sysMailConfig.setTemplate(templateString.getBytes("UTF-8"));
+				//新增时 生成询价单附件
+				if(StringUtils.isBlank(draftId)){
+
+					String tempField2 = purInquiryFormController.exportInquiryXlsTest(inquiryId);
+					if(StringUtils.isNotBlank(tempField2) && tempField2.equals("true")){
+						sysMailConfig.setTempField2("temp\\"+sourceCode+".xlsx");
+					}else{
+						sysMailConfig.setTempField2("false");
+					}
+				}
+			}
+		}else{
+
+//			sysMailConfig.setTemplateTitle(null);
+//			sysMailConfig.setTemplateString(null);
+//			sysMailConfig.setTemplate(null);
+		}
+
+		return Result.OK(sysMailConfig);
+	}
+
+	 public static void main(String[] args) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
+		 PurInquiryForm ent = new PurInquiryForm();
+		 ent.setBillCode("afasdfsf");
+		 Map<String, String> map = BeanUtils.describe(ent);
+
+		 String aa = "单号{billCode}";
+		 for (Map.Entry<String, String> entry : map.entrySet()) {
+			 System.out.println(entry.getKey());
+			 System.out.println(entry.getValue());
+			 aa = aa.replace("{" + entry.getKey()+ "}", entry.getValue()==null?"":entry.getValue());
+			 System.out.println(aa);
+		 }
+
+
+	 }
+
+
+    /**
+    * 导出excel
+    *
+    * @param request
+    * @param sysMailConfig
+    */
+	//   @RequiresPermissions("otherCode:sys_mail_config:exportXls")
+    @RequestMapping(value = "/exportXls")
+    public ModelAndView exportXls(HttpServletRequest request, SysMailConfig sysMailConfig) {
+        return super.exportXls(request, sysMailConfig, SysMailConfig.class, "邮件配置");
+    }
+
+    /**
+      * 通过excel导入数据
+    *
+    * @param request
+    * @param response
+    * @return
+    */
+	//   @RequiresPermissions("otherCode:sys_mail_config:importExcel")
+    @RequestMapping(value = "/importExcel", method = RequestMethod.POST)
+    public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
+        return super.importExcel(request, response, SysMailConfig.class);
+    }
+
+}

+ 152 - 0
srm-module-code/src/main/java/org/jeecg/modules/otherCode/entity/SysEmailDraft.java

@@ -0,0 +1,152 @@
+package org.jeecg.modules.otherCode.entity;
+
+import java.io.Serializable;
+import java.io.UnsupportedEncodingException;
+import java.util.Date;
+import java.math.BigDecimal;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import org.jeecg.common.constant.ProvinceCityArea;
+import org.jeecg.common.util.SpringContextUtils;
+import lombok.Data;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import org.springframework.format.annotation.DateTimeFormat;
+import org.jeecgframework.poi.excel.annotation.Excel;
+import org.jeecg.common.aspect.annotation.Dict;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * @Description: 邮件草稿箱
+ * @Author: jeecg-boot
+ * @Date:   2026-03-23
+ * @Version: V1.0
+ */
+@Data
+@TableName("sys_email_draft")
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value="sys_email_draft对象", description="邮件草稿箱")
+public class SysEmailDraft implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+	/**主键*/
+	@TableId(type = IdType.ASSIGN_ID)
+    @ApiModelProperty(value = "主键")
+    private String id;
+    /**删除状态(0-正常,1-已删除)*/
+    @ApiModelProperty(value = "删除状态(0-正常,1-已删除)")
+    @TableLogic
+    private Integer delFlag;
+	/**创建人*/
+    @ApiModelProperty(value = "创建人")
+    private String createBy;
+	/**创建日期*/
+	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    @ApiModelProperty(value = "创建日期")
+    private Date createTime;
+	/**更新人*/
+    @ApiModelProperty(value = "更新人")
+    private String updateBy;
+	/**更新日期*/
+	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    @ApiModelProperty(value = "更新日期")
+    private Date updateTime;
+	/**所属部门*/
+    @ApiModelProperty(value = "所属部门")
+    private String sysOrgCode;
+
+    @ApiModelProperty(value = "邮箱助记码")
+    @Dict(dictTable = "sys_mail_config", dicCode = "id", dicText = "config_code")
+    private String configCode;
+	/**编码*/
+	@Excel(name = "编码", width = 15)
+    @ApiModelProperty(value = "编码")
+    private String code;
+	/**邮件发送人*/
+	@Excel(name = "邮件发送人", width = 15)
+    @ApiModelProperty(value = "邮件发送人")
+    private String sender;
+	/**邮件接收人*/
+	@Excel(name = "邮件接收人", width = 15)
+    @ApiModelProperty(value = "邮件接收人")
+    private String recipient;
+	/**邮件抄送人*/
+	@Excel(name = "邮件抄送人", width = 15)
+    @ApiModelProperty(value = "邮件抄送人")
+    private String carbonCopy;
+	/**主题*/
+	@Excel(name = "主题", width = 15)
+    @ApiModelProperty(value = "主题")
+    private String title;
+	/**来源*/
+	@Excel(name = "来源", width = 15)
+    @ApiModelProperty(value = "来源")
+    private String sourceCode;
+	//异常信息
+    private String errorMsg;
+	/**内容*/
+//	@Excel(name = "内容", width = 15)
+    private transient String contentString;
+
+    private byte[] content;
+
+    public byte[] getContent(){
+        if(contentString==null){
+            return null;
+        }
+        try {
+            return contentString.getBytes("UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    public String getContentString(){
+        if(content==null || content.length==0){
+            return "";
+        }
+        try {
+            return new String(content,"UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        }
+        return "";
+    }
+	/**文件*/
+//	@Excel(name = "文件", width = 15)
+    private String files;
+
+	/**图片*/
+//	@Excel(name = "图片", width = 15)
+    @ApiModelProperty(value = "图片")
+    private String pictures;
+	/**状态*/
+	@Excel(name = "状态", width = 15)
+    @ApiModelProperty(value = "状态")
+    @Dict(dicCode = "email_st")
+    private String status;
+	/**发送时间*/
+	@Excel(name = "发送时间", width = 20, format = "yyyy-MM-dd HH:mm:ss")
+	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    @ApiModelProperty(value = "发送时间")
+    private Date sendTime;
+	/**发送用户*/
+	@Excel(name = "发送用户", width = 15)
+    @ApiModelProperty(value = "发送用户")
+    private String sentBy;
+	//仅保存,保存并发送
+    private String submitSt;
+
+    @Excel(name = "发送次数", width = 15)
+    @ApiModelProperty(value = "发送次数")
+    private Integer sentNumber;
+}

+ 159 - 0
srm-module-code/src/main/java/org/jeecg/modules/otherCode/entity/SysMailConfig.java

@@ -0,0 +1,159 @@
+package org.jeecg.modules.otherCode.entity;
+
+import java.io.Serializable;
+import java.io.UnsupportedEncodingException;
+import java.util.Date;
+import java.math.BigDecimal;
+
+import com.baomidou.mybatisplus.annotation.*;
+import org.jeecg.common.constant.ProvinceCityArea;
+import org.jeecg.common.util.SpringContextUtils;
+import lombok.Data;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import org.springframework.format.annotation.DateTimeFormat;
+import org.jeecgframework.poi.excel.annotation.Excel;
+import org.jeecg.common.aspect.annotation.Dict;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * @Description: 邮件配置
+ * @Author: jeecg-boot
+ * @Date:   2026-03-23
+ * @Version: V1.0
+ */
+@Data
+@TableName("sys_mail_config")
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value="sys_mail_config对象", description="邮件配置")
+public class SysMailConfig implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+	/**主键*/
+	@TableId(type = IdType.ASSIGN_ID)
+    @ApiModelProperty(value = "主键")
+    private String id;
+	/**创建人*/
+    @ApiModelProperty(value = "创建人")
+    private String createBy;
+	/**创建日期*/
+	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    @ApiModelProperty(value = "创建日期")
+    private Date createTime;
+	/**更新人*/
+    @ApiModelProperty(value = "更新人")
+    private String updateBy;
+	/**更新日期*/
+	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    @ApiModelProperty(value = "更新日期")
+    private Date updateTime;
+	/**所属部门*/
+    @ApiModelProperty(value = "所属部门")
+    private String sysOrgCode;
+    /**助记码*/
+    @Excel(name = "助记码", width = 15)
+    @ApiModelProperty(value = "助记码")
+    private String configCode;
+	/**邮箱账号*/
+	@Excel(name = "邮箱账号", width = 15)
+    @ApiModelProperty(value = "邮箱账号")
+    private String username;
+	/**密码(授权码)*/
+//	@Excel(name = "密码(授权码)", width = 15)
+    @ApiModelProperty(value = "密码(授权码)")
+    private String password;
+
+	/**SMTP地址*/
+	@Excel(name = "SMTP地址", width = 15)
+    @ApiModelProperty(value = "SMTP地址")
+    private String smtpHost;
+	/**SMTP端口*/
+	@Excel(name = "SMTP端口", width = 15)
+    @ApiModelProperty(value = "SMTP端口")
+    private String smtpPort;
+	/**发件人邮箱*/
+	@Excel(name = "发件人邮箱", width = 15)
+    @ApiModelProperty(value = "发件人邮箱")
+    private String fromEmail;
+	/**发件人名称*/
+	@Excel(name = "发件人名称", width = 15)
+    @ApiModelProperty(value = "发件人名称")
+    private String fromName;
+    /**邮件抄送人*/
+    @Excel(name = "邮件抄送人", width = 15)
+    @ApiModelProperty(value = "邮件抄送人")
+    private String carbonCopy;
+	/**启用SSL*/
+	@Excel(name = "启用SSL", width = 15, dicCode = "yn")
+	@Dict(dicCode = "yn")
+    @ApiModelProperty(value = "启用SSL")
+    private String sslEnabled;
+	/**启用STARTTLS*/
+	@Excel(name = "启用STARTTLS", width = 15, dicCode = "yn")
+	@Dict(dicCode = "yn")
+    @ApiModelProperty(value = "启用STARTTLS")
+    private String starttlsEnabled;
+	/**关联部门*/
+	@Excel(name = "关联部门", width = 15, dictTable = "sys_depart", dicText = "depart_name", dicCode = "id")
+	@Dict(dictTable = "sys_depart", dicText = "depart_name", dicCode = "id")
+    @ApiModelProperty(value = "关联部门")
+    private String deptCode;
+	/**描述*/
+	@Excel(name = "描述", width = 15)
+    @ApiModelProperty(value = "描述")
+    private String description;
+	/**关联部门*/
+    @ApiModelProperty(value = "关联部门")
+    private String deptName;
+	/**删除*/
+    @ApiModelProperty(value = "删除")
+    @TableLogic
+    private Integer delFlag;
+	/**状态(1启用 0停用)*/
+    @ApiModelProperty(value = "状态(1启用 0停用)")
+    private Integer status;
+
+
+    @TableField(exist = false)
+    private String tempField;
+    @TableField(exist = false)
+    private String tempField2;
+
+    //模板主题
+    private String templateTitle;
+    /**内容*/
+//    @Excel(name = "模板正文", width = 15)
+    private transient String templateString;
+
+    //模板正文
+    private byte[] template;
+
+    public byte[] getTemplate(){
+        if(templateString==null){
+            return null;
+        }
+        try {
+            return templateString.getBytes("UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    public String getTemplateString(){
+        if(template==null || template.length==0){
+            return "";
+        }
+        try {
+            return new String(template,"UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        }
+        return "";
+    }
+}

+ 17 - 0
srm-module-code/src/main/java/org/jeecg/modules/otherCode/mapper/SysEmailDraftMapper.java

@@ -0,0 +1,17 @@
+package org.jeecg.modules.otherCode.mapper;
+
+import java.util.List;
+
+import org.apache.ibatis.annotations.Param;
+import org.jeecg.modules.otherCode.entity.SysEmailDraft;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * @Description: 邮件草稿箱
+ * @Author: jeecg-boot
+ * @Date:   2026-03-23
+ * @Version: V1.0
+ */
+public interface SysEmailDraftMapper extends BaseMapper<SysEmailDraft> {
+
+}

+ 17 - 0
srm-module-code/src/main/java/org/jeecg/modules/otherCode/mapper/SysMailConfigMapper.java

@@ -0,0 +1,17 @@
+package org.jeecg.modules.otherCode.mapper;
+
+import java.util.List;
+
+import org.apache.ibatis.annotations.Param;
+import org.jeecg.modules.otherCode.entity.SysMailConfig;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * @Description: 邮件配置
+ * @Author: jeecg-boot
+ * @Date:   2026-03-23
+ * @Version: V1.0
+ */
+public interface SysMailConfigMapper extends BaseMapper<SysMailConfig> {
+
+}

+ 5 - 0
srm-module-code/src/main/java/org/jeecg/modules/otherCode/mapper/xml/SysEmailDraftMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.jeecg.modules.otherCode.mapper.SysEmailDraftMapper">
+
+</mapper>

+ 5 - 0
srm-module-code/src/main/java/org/jeecg/modules/otherCode/mapper/xml/SysMailConfigMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.jeecg.modules.demo.otherCode.mapper.SysMailConfigMapper">
+
+</mapper>

+ 15 - 0
srm-module-code/src/main/java/org/jeecg/modules/otherCode/service/ISysEmailDraftService.java

@@ -0,0 +1,15 @@
+package org.jeecg.modules.otherCode.service;
+
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.modules.otherCode.entity.SysEmailDraft;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * @Description: 邮件草稿箱
+ * @Author: jeecg-boot
+ * @Date:   2026-03-23
+ * @Version: V1.0
+ */
+public interface ISysEmailDraftService extends IService<SysEmailDraft> {
+    public Result<String> sendBatch(String ids);
+}

+ 14 - 0
srm-module-code/src/main/java/org/jeecg/modules/otherCode/service/ISysMailConfigService.java

@@ -0,0 +1,14 @@
+package org.jeecg.modules.otherCode.service;
+
+import org.jeecg.modules.otherCode.entity.SysMailConfig;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * @Description: 邮件配置
+ * @Author: jeecg-boot
+ * @Date:   2026-03-23
+ * @Version: V1.0
+ */
+public interface ISysMailConfigService extends IService<SysMailConfig> {
+
+}

+ 293 - 0
srm-module-code/src/main/java/org/jeecg/modules/otherCode/service/impl/SysEmailDraftServiceImpl.java

@@ -0,0 +1,293 @@
+package org.jeecg.modules.otherCode.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.google.gson.Gson;
+import org.apache.commons.lang.StringUtils;
+import org.apache.shiro.SecurityUtils;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.system.vo.LoginUser;
+import org.jeecg.common.util.PmsUtil;
+import org.jeecg.modules.otherCode.entity.SysEmailDraft;
+import org.jeecg.modules.otherCode.entity.SysMailConfig;
+import org.jeecg.modules.otherCode.mapper.SysEmailDraftMapper;
+import org.jeecg.modules.otherCode.service.ISysEmailDraftService;
+import org.jeecg.modules.otherCode.service.ISysMailConfigService;
+import org.jeecg.modules.purCode.mapper.PurInquiryFormMapper;
+import org.jeecg.modules.saleCode.entity.SaleInvoice;
+import org.jeecg.modules.system.service.ISysDataLogService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.io.FileSystemResource;
+import org.springframework.mail.javamail.JavaMailSender;
+import org.springframework.mail.javamail.JavaMailSenderImpl;
+import org.springframework.mail.javamail.MimeMessageHelper;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+
+import javax.annotation.Resource;
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeMessage;
+import java.io.File;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * @Description: 邮件草稿箱
+ * @Author: jeecg-boot
+ * @Date: 2026-03-23
+ * @Version: V1.0
+ */
+@Service
+public class SysEmailDraftServiceImpl extends ServiceImpl<SysEmailDraftMapper, SysEmailDraft> implements ISysEmailDraftService {
+
+    @Autowired
+    private ISysMailConfigService sysMailConfigService;
+    @Autowired
+    private SysEmailDraftMapper sysEmailDraftMapper;
+    @Autowired
+    private PurInquiryFormMapper purInquiryFormMapper;
+    @Resource
+    private ISysDataLogService sysDataLogService;
+
+    @Value(value = "${jeecg.path.upload}")
+    private String uploadpath;
+
+    //邮件发送
+    public Result<String> sendBatch(String ids) {
+
+        QueryWrapper<SysEmailDraft> queryWrapper = new QueryWrapper<>();
+        queryWrapper.in("id", Arrays.asList(ids.split(",")));
+        List<SysEmailDraft> list = sysEmailDraftMapper.selectList(queryWrapper);
+        if (list.size() == 0) {
+            return Result.error("数据为空!");
+        }
+
+        int success = 0;
+        int error = 0;
+
+        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+
+        for (SysEmailDraft o : list) {
+
+            Integer sentNumber = o.getSentNumber();
+            String sourceCodeOld = o.getSourceCode();
+            String sourceCode = StringUtils.isBlank(o.getSourceCode())?"自定义":"询价"+o.getSourceCode();
+
+            if (sentNumber == null) {
+                o.setSentNumber(1);
+            } else {
+                o.setSentNumber(sentNumber + 1);
+            }
+
+
+            String st = sendMailAsync(o);
+            if(st.equals("true")){
+
+                success++;
+                o.setStatus("发送成功");
+                o.setErrorMsg("发送成功");
+            }else{
+                error++;
+                o.setStatus("发送失败");
+                o.setErrorMsg(st);
+            }
+
+            o.setSentBy(sysUser.getUsername());
+            o.setSendTime(new Date());
+
+            sysEmailDraftMapper.updateById(o);
+
+            Gson gson = new Gson();
+            String json = gson.toJson(o);
+
+            if(StringUtils.isNotBlank(sourceCodeOld)){
+                purInquiryFormMapper.changeSentNumber(sourceCodeOld);
+            }
+
+            sysDataLogService.addDataLog(sourceCode+"邮件发送", o.getCode()+ o.getStatus(), json);
+        }
+
+        if(error > 0){
+            return Result.error("执行结束! 已成功发送" + success + "条邮件,失败" + error + "条!");
+        }
+        return Result.OK("执行结束! 已成功发送" + success + "条邮件,失败" + error + "条!");
+    }
+
+
+    @Async
+    public String sendMailAsync(SysEmailDraft sysEmailDraft) {
+        try {
+
+            String configCode = sysEmailDraft.getConfigCode();
+            if(StringUtils.isBlank(configCode)){
+                return "邮件发送失败:邮件配置信息异常";
+//                throw new RuntimeException("邮件发送失败:邮件配置信息异常");
+            }
+            SysMailConfig sysMailConfig = sysMailConfigService.getById(configCode);
+            if(sysMailConfig == null){
+                return "邮件发送失败:邮件配置不存在";
+//                throw new RuntimeException("邮件发送失败:邮件配置不存在");
+            }
+
+            // ========== 1. 配置邮件服务器信息(请修改为你的实际配置) ==========
+            String host = sysMailConfig.getSmtpHost();          // SMTP 服务器地址
+            int port = Integer.valueOf(sysMailConfig.getSmtpPort());                       // 端口,QQ 邮箱 587 或 465
+            String username = sysMailConfig.getUsername(); // 发件人邮箱账号
+            String password = sysMailConfig.getPassword(); // 授权码(不是登录密码)
+            boolean sslEnabled = sysMailConfig.getSslEnabled().equals("1");            // 是否启用 SSL(根据端口决定,587 通常用 STARTTLS)
+            boolean starttlsEnabled = sysMailConfig.getStarttlsEnabled().equals("1");        // 是否启用 STARTTLS
+
+            // ========== 2. 配置邮件内容 ==========
+            String fromEmail = username;           // 发件人邮箱(通常与 username 一致)
+            String fromName = sysEmailDraft.getSender();         // 发件人显示名称
+            String toEmail = sysEmailDraft.getRecipient(); // 收件人邮箱
+            String subject = sysEmailDraft.getTitle();
+            String content = sysEmailDraft.getContentString();
+
+            String files = sysEmailDraft.getFiles();
+            String pictures = sysEmailDraft.getPictures();
+            String carbonCopy = sysEmailDraft.getCarbonCopy();
+
+            // ========== 3. 创建 JavaMailSender 并发送 ==========
+            JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
+            mailSender.setHost(host);
+            mailSender.setPort(port);
+            mailSender.setUsername(username);
+            mailSender.setPassword(password);
+
+            Properties props = mailSender.getJavaMailProperties();
+            props.put("mail.transport.protocol", "smtp");
+            props.put("mail.smtp.auth", "true");
+            props.put("mail.smtp.starttls.enable", String.valueOf(starttlsEnabled));
+            props.put("mail.smtp.ssl.enable", String.valueOf(sslEnabled));
+            props.put("mail.debug", "true"); // 输出详细日志,便于调试
+
+            MimeMessage mimeMessage = mailSender.createMimeMessage();
+            MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true, "UTF-8");
+            helper.setFrom(fromEmail, fromName);
+            helper.setSubject(subject);
+            helper.setText(content, true); // true 表示 HTML 内容
+
+//            String inlineImages = "";
+//            // 添加内联图片
+//            if (StringUtils.isNotBlank(inlineImages)) {
+//                for (String inlineImage : inlineImages.split(",")) {
+//                    File file = new File(inlineImages);
+//                    if (file.exists()) {
+//                        FileSystemResource resource = new FileSystemResource(file);
+//                        helper.addInline(file.getName(), resource);
+//                    }
+//                }
+//            }
+            // 添加附件
+            if(StringUtils.isNotBlank(files)){
+
+                for (String filePath : files.split(",")) {
+                    File file = new File(uploadpath+"/"+filePath);
+                    if (file.exists()) {
+                        FileSystemResource resource = new FileSystemResource(file);
+                        helper.addAttachment(file.getName(), resource);
+                    }
+                }
+            }
+            // 添加图片附件
+            if(StringUtils.isNotBlank(pictures)){
+
+                for (String filePath : pictures.split(",")) {
+                    File file = new File(uploadpath+"/"+filePath);
+                    if (file.exists()) {
+                        FileSystemResource resource = new FileSystemResource(file);
+                        helper.addAttachment(file.getName(), resource);
+                    }
+                }
+            }
+
+            // 设置收件人
+            helper.setTo(toEmail);
+            // 设置抄送人(多个以数组形式传输)
+            if(StringUtils.isNotBlank(carbonCopy)){
+
+                helper.setCc(carbonCopy);
+            }
+            // 设置密送人(多个以数组形式传输)
+//            helper.setBcc(toEmail);
+
+            mailSender.send(mimeMessage);
+
+            System.out.println("邮件发送成功!");
+        } catch (Exception e) {
+            log.error("邮件发送失败", e);
+
+            return "邮件发送失败:"+e.getMessage();
+//            throw new RuntimeException("邮件发送失败", e);
+        }
+
+        return "true";
+    }
+
+    public static void main(String[] args) {
+        // ========== 1. 配置邮件服务器信息(请修改为你的实际配置) ==========
+//        String host = "smtp.qq.com";          // SMTP 服务器地址
+//        int port = 587;                       // 端口,QQ 邮箱 587 或 465
+//        String username = "1059252703@qq.com"; // 发件人邮箱账号
+//        String password = "jfvplcyovygxbeib"; // 授权码(不是登录密码)
+        String host = "116.236.227.116";          // SMTP 服务器地址
+        int port = 12525;                       // 端口,QQ 邮箱 587 或 465
+        String username = "mjiezhu@gmscn.com"; // 发件人邮箱账号
+        String password = "Shanghai@159"; // 授权码(不是登录密码)
+        boolean sslEnabled = false;            // 是否启用 SSL(根据端口决定,587 通常用 STARTTLS)
+        boolean starttlsEnabled = true;        // 是否启用 STARTTLS
+
+        // ========== 2. 配置邮件内容 ==========
+        String fromEmail = username;           // 发件人邮箱(通常与 username 一致)
+        String fromName = "测试发件人";         // 发件人显示名称
+        String toEmail = "1059252703@qq.com"; // 收件人邮箱
+        String subject = "测试邮件主题2";
+        String content = "<h1>Hello!</h1><p>这是一封通过独立测试类发送的邮件2。</p>";
+
+        // ========== 3. 创建 JavaMailSender 并发送 ==========
+        try {
+            JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
+            mailSender.setHost(host);
+            mailSender.setPort(port);
+            mailSender.setUsername(username);
+            mailSender.setPassword(password);
+
+            Properties props = mailSender.getJavaMailProperties();
+            props.put("mail.transport.protocol", "smtp");
+            props.put("mail.smtp.auth", "true");
+            props.put("mail.smtp.starttls.enable", String.valueOf(starttlsEnabled));
+            props.put("mail.smtp.ssl.enable", String.valueOf(sslEnabled));
+            props.put("mail.debug", "true"); // 输出详细日志,便于调试
+
+            MimeMessage mimeMessage = mailSender.createMimeMessage();
+            MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true, "UTF-8");
+            helper.setFrom(fromEmail, fromName);
+            helper.setSubject(subject);
+            helper.setText(content, true); // true 表示 HTML 内容
+
+//            File file = new File("E:\\新建 XLSX 工作表.xlsx");
+//            if (file.exists()) {
+//                FileSystemResource resource = new FileSystemResource(file);
+//                helper.addAttachment(file.getName(), resource);
+//            }
+            // 设置收件人
+            helper.setTo(toEmail);
+            // 设置抄送人(多个以数组形式传输)
+//            helper.setCc(toEmail);
+//            // 设置密送人(多个以数组形式传输)
+//            helper.setBcc(toEmail);
+
+            mailSender.send(mimeMessage);
+            System.out.println("邮件发送成功!");
+
+        } catch (Exception e) {
+            System.err.println("邮件发送失败:" + e.getMessage());
+            e.printStackTrace();
+        }
+    }
+}

+ 19 - 0
srm-module-code/src/main/java/org/jeecg/modules/otherCode/service/impl/SysMailConfigServiceImpl.java

@@ -0,0 +1,19 @@
+package org.jeecg.modules.otherCode.service.impl;
+
+import org.jeecg.modules.otherCode.entity.SysMailConfig;
+import org.jeecg.modules.otherCode.mapper.SysMailConfigMapper;
+import org.jeecg.modules.otherCode.service.ISysMailConfigService;
+import org.springframework.stereotype.Service;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+
+/**
+ * @Description: 邮件配置
+ * @Author: jeecg-boot
+ * @Date:   2026-03-23
+ * @Version: V1.0
+ */
+@Service
+public class SysMailConfigServiceImpl extends ServiceImpl<SysMailConfigMapper, SysMailConfig> implements ISysMailConfigService {
+
+}

+ 194 - 23
srm-module-code/src/main/java/org/jeecg/modules/purCode/controller/PurInquiryFormController.java

@@ -34,6 +34,7 @@ import org.jeecg.modules.cuspCode.entity.CuspSupplierProfile;
 import org.jeecg.modules.cuspCode.service.ICuspSupplierProfileService;
 import org.jeecg.modules.purCode.entity.*;
 import org.jeecg.modules.purCode.service.*;
+import org.jeecg.modules.purCode.vo.PurInquiryFormAlert;
 import org.jeecg.modules.purCode.vo.SupplierQuotationDetails;
 import org.jeecg.modules.saleCode.entity.SaleInquiryForm;
 import org.jeecg.modules.saleCode.entity.SaleInquiryFormProduct;
@@ -157,13 +158,17 @@ public class PurInquiryFormController {
     @ApiOperation(value = "采购询价单-弹框分页列表查询", notes = "采购询价单-弹框分页列表查询")
     @GetMapping(value = "/alertPurInquiryList")
     @PermissionData(pageComponent = "purchase/purchaseInquiryForm/purchaseInquiryFormList")
-    public Result<IPage<SaleInquiryFormAlert>> alertPurInquiryList(SaleInquiryFormAlert saleInquiryForm,
-                                                                   @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
-                                                                   @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
-                                                                   HttpServletRequest req) {
-        QueryWrapper<SaleInquiryFormAlert> queryWrapper = QueryGenerator.initQueryWrapper(saleInquiryForm, req.getParameterMap());
-        Page<SaleInquiryFormAlert> page = new Page<SaleInquiryFormAlert>(pageNo, pageSize);
-        IPage<SaleInquiryFormAlert> pageList = purInquiryFormProductService.alertPurInquiryList(page, queryWrapper);
+    public Result<IPage<PurInquiryFormAlert>> alertPurInquiryList(PurInquiryFormAlert saleInquiryForm,
+                                                                  @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
+                                                                  @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
+                                                                  HttpServletRequest req) {
+        QueryWrapper<PurInquiryFormAlert> queryWrapper = QueryGenerator.initQueryWrapper(saleInquiryForm, req.getParameterMap());
+        Page<PurInquiryFormAlert> page = new Page<PurInquiryFormAlert>(pageNo, pageSize);
+        IPage<PurInquiryFormAlert> pageList = purInquiryFormProductService.alertPurInquiryList(page, queryWrapper);
+        for(PurInquiryFormAlert o:pageList.getRecords()){
+            o.setSuppilerName(o.getSuppilerName1());
+            o.setInquirySuppiler(o.getInquirySuppiler1());
+        }
         return Result.OK(pageList);
     }
 
@@ -181,31 +186,51 @@ public class PurInquiryFormController {
         PurInquiryForm purInquiryForm = new PurInquiryForm();
         BeanUtils.copyProperties(purInquiryFormPage, purInquiryForm);
 
-        String code = purInquiryForm.getBillCode();
-        if (StringUtils.isNotBlank(code)) {
-
-            QueryWrapper<PurInquiryForm> queryWrapper = new QueryWrapper();
-            queryWrapper.eq("bill_code", code);
-            queryWrapper.eq("del_flag", "0");
+        String InquirySuppiler = purInquiryForm.getInquirySuppiler();
 
-            List<PurInquiryForm> list = purInquiryFormService.list(queryWrapper);
-            if (list.size() != 0) {
-                return Result.error("销售询价单重复,请修改!");
-            }
-        } else {
+        for(String a :InquirySuppiler.split(",")){
 
             Result<String> result = serialPatternService.getNextSerial("pur_inquiry_form", "bill_code");
             if (!result.isSuccess()) {
                 return result;
             }
+            purInquiryForm.setId(null);
             purInquiryForm.setBillCode(result.getMessage());
+
+            purInquiryForm.setSubmit("0");
+            CuspSupplierProfile ent = cuspSupplierProfileService.getById(a);
+            purInquiryForm.setSuppilerName(ent.getName());
+            purInquiryForm.setInquirySuppiler(a);
+//            String supplierName = "";
+//            if(StringUtils.isNotBlank(purInquiryForm.getInquirySuppiler())){
+//                for(String o:purInquiryForm.getInquirySuppiler().split(",")){
+//                    CuspSupplierProfile ent = cuspSupplierProfileService.getById(o);
+//                    if(ent !=null){
+//                        if(StringUtils.isBlank(supplierName)){
+//                            supplierName = ent.getName();
+//                        }else{
+//                            supplierName = supplierName+","+ent.getName();
+//                        }
+//                    }
+//                }
+//                purInquiryForm.setSuppilerName(supplierName);
+//            }
+
+            purInquiryFormService.saveMain(purInquiryForm, purInquiryFormPage.getPurInquiryFormShipList(), purInquiryFormPage.getPurInquiryFormProductList());
+
         }
 
-        purInquiryForm.setSubmit("0");
-        purInquiryFormService.saveMain(purInquiryForm, purInquiryFormPage.getPurInquiryFormShipList(), purInquiryFormPage.getPurInquiryFormProductList());
         return Result.OK("添加成功!");
     }
 
+    public static void main(String[] args) {
+        String roleCode = "阿飞萨芬,R0032,R0032";
+        if(roleCode.contains("R0031")){
+            System.out.println(11);
+        }else{
+            System.out.println(22);
+        }
+    }
     /**
      * 编辑
      *
@@ -223,7 +248,58 @@ public class PurInquiryFormController {
         if (purInquiryFormEntity == null) {
             return Result.error("未找到对应数据");
         }
-        purInquiryFormService.updateMain(purInquiryForm, purInquiryFormPage.getPurInquiryFormShipList(), purInquiryFormPage.getPurInquiryFormProductList());
+
+        String InquirySuppiler = purInquiryForm.getInquirySuppiler();
+
+        int i = 0;
+        for(String a :InquirySuppiler.split(",")){
+
+            if(i == 0){
+
+                CuspSupplierProfile ent = cuspSupplierProfileService.getById(a);
+                purInquiryForm.setSuppilerName(ent.getName());
+                purInquiryForm.setInquirySuppiler(a);
+
+                purInquiryFormService.updateMain(purInquiryForm, purInquiryFormPage.getPurInquiryFormShipList(), purInquiryFormPage.getPurInquiryFormProductList());
+
+            }else{
+
+                Result<String> result = serialPatternService.getNextSerial("pur_inquiry_form", "bill_code");
+                if (!result.isSuccess()) {
+                    return result;
+                }
+                purInquiryForm.setId(null);
+                purInquiryForm.setBillCode(result.getMessage());
+
+                purInquiryForm.setSubmit("0");
+                CuspSupplierProfile ent = cuspSupplierProfileService.getById(a);
+                purInquiryForm.setSuppilerName(ent.getName());
+                purInquiryForm.setInquirySuppiler(a);
+
+                purInquiryFormService.saveMain(purInquiryForm, purInquiryFormPage.getPurInquiryFormShipList(), purInquiryFormPage.getPurInquiryFormProductList());
+
+            }
+
+            i++;
+
+        }
+
+//        String supplierName = "";
+//        if(StringUtils.isNotBlank(purInquiryForm.getInquirySuppiler())){
+//            for(String o:purInquiryForm.getInquirySuppiler().split(",")){
+//                CuspSupplierProfile ent = cuspSupplierProfileService.getById(o);
+//                if(ent !=null){
+//                    if(StringUtils.isBlank(supplierName)){
+//                        supplierName = ent.getName();
+//                    }else{
+//                        supplierName = supplierName+","+ent.getName();
+//                    }
+//                }
+//            }
+//            purInquiryForm.setSuppilerName(supplierName);
+//        }
+//
+//        purInquiryFormService.updateMain(purInquiryForm, purInquiryFormPage.getPurInquiryFormShipList(), purInquiryFormPage.getPurInquiryFormProductList());
         return Result.OK("编辑成功!");
     }
 
@@ -800,6 +876,102 @@ public class PurInquiryFormController {
     }
 
 
+    /**
+     * 导出供应商询价单
+     *
+     * @return
+     */
+    public String exportInquiryXlsTest(String id) {
+        BaseTemplates templates = baseTemplatesService.getByTemplateType("采购询价");
+        PurInquiryForm purInquiryForm = purInquiryFormService.getById(id);
+        LambdaQueryWrapper<PurInquiryFormProduct> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(PurInquiryFormProduct::getHeadId, id);
+        List<PurInquiryFormProduct> productList = purInquiryFormProductService.list(queryWrapper);
+        if (templates != null) {
+            try {
+                String productionClass = purInquiryForm.getProductionClass();
+                if (StringUtils.isNotBlank(productionClass)) {
+
+                    BaseProductClass classEnt = baseProductClassService.getById(productionClass);
+                    if (classEnt != null) {
+                        purInquiryForm.setProductionClass(classEnt.getName());
+                    }
+                }
+                purInquiryForm.setBillDateText(DateUtils.date2Str(purInquiryForm.getBillDate(), DateUtils.date_sdf.get()));
+                String getInquirySuppiler = purInquiryForm.getInquirySuppiler();
+                if (StringUtils.isNotBlank(getInquirySuppiler)) {
+
+                    CuspSupplierProfile classEnt = cuspSupplierProfileService.getById(getInquirySuppiler);
+                    if (classEnt != null) {
+                        purInquiryForm.setInquirySuppiler(classEnt.getName());
+                        purInquiryForm.setContacts(classEnt.getContacts());
+                        purInquiryForm.setPhone(classEnt.getPhone());
+                        purInquiryForm.setAddress(classEnt.getAddress());
+                        purInquiryForm.setEmail(classEnt.getEmail());
+                    }
+                }
+                // 制单人信息
+                SysUser sysUser = sysUserService.getUserByName(purInquiryForm.getCreateBy());
+                purInquiryForm.setPurchaseman(sysUser.getRealname());
+                purInquiryForm.setPurchasePhone(sysUser.getPhone());
+                purInquiryForm.setPurchaseEmail(sysUser.getEmail());
+                // 获取计产品档案
+                List<BaseProductArchive> productArchiveList = new ArrayList<>();
+                if (oConvertUtils.listIsNotEmpty(productList)){
+                    LambdaQueryWrapper<BaseProductArchive> productWrapper = new LambdaQueryWrapper<>();
+                    productWrapper.in(BaseProductArchive::getId, productList.stream().map(PurInquiryFormProduct::getProductId).collect(Collectors.toList()));
+                    productArchiveList = baseProductArchiveService.list(productWrapper);
+                }
+                // 查询数据字典
+                List<DictModel> unitDictList = sysDictService.queryDictItemsByCode("measurement_unit");
+
+                // 产品设置
+                int rowNum = 1;
+                for (PurInquiryFormProduct product : productList){
+                    product.setRowNumber(rowNum++);
+                    BaseProductArchive findProduct = productArchiveList.stream().filter(e->e.getId().equals(product.getProductId())).findFirst().orElse(null);
+                    if (findProduct != null){
+                        product.setUnit(findProduct.getMeasurementUnit());
+                        if (findProduct.getMeasurementUnit() != null){
+                            DictModel findDict = unitDictList.stream().filter(d->d.getValue().equals(findProduct.getMeasurementUnit())).findFirst().orElse(null);
+                            if (findDict != null){
+                                product.setUnit(findDict.getText());
+                            }
+                        }
+                    }
+                }
+                // 项目名称
+                if (purInquiryForm.getInquiryProject() != null){
+                    BaseProjectArchive projectArchive = baseProjectArchiveService.getById(purInquiryForm.getInquiryProject());
+                    if (projectArchive != null){
+                        purInquiryForm.setContactsNo(projectArchive.getName());
+                    }
+
+                }
+                String templateFilePath = uploadpath + templates.getTemplateFile();
+                String tempFilePath = uploadpath + "/"+ UUIDGenerator.generate()+".xlsx";
+
+                try (ExcelWriter excelWriter = EasyExcel.write(tempFilePath).withTemplate(templateFilePath).build()) {
+                    WriteSheet writeSheet = EasyExcel.writerSheet().build();
+                    FillConfig fillConfig = FillConfig.builder().direction(WriteDirectionEnum.VERTICAL).forceNewRow(Boolean.TRUE).build();
+                    excelWriter.fill(new FillWrapper(productList), fillConfig, writeSheet);
+                    excelWriter.fill(purInquiryForm, writeSheet);
+                }
+                List<String> noteList = new ArrayList<>();
+                productList.forEach(p->noteList.add(p.getNotes()));
+
+                ExcelExportUtils.excelInsertRowNotes(purInquiryForm.getBillCode(),uploadpath,
+                        tempFilePath, 14, noteList, 1, 4);
+
+            } catch (Exception ex) {
+                return "询价单导出异常,请手动添加附件";
+            }
+
+        }
+
+        return "true";
+
+    }
     /**
      * 导出供应商询价单
      *
@@ -885,11 +1057,10 @@ public class PurInquiryFormController {
                 }
                 List<String> noteList = new ArrayList<>();
                 productList.forEach(p->noteList.add(p.getNotes()));
-
+//
                 ExcelExportUtils.excelInsertRowNotes(getOutputStream(purInquiryForm.getBillCode()+".xlsx", response),
                         tempFilePath, 14, noteList, 1, 4);
 
-
             } catch (Exception ex) {
                 ex.printStackTrace();
             }

+ 9 - 0
srm-module-code/src/main/java/org/jeecg/modules/purCode/controller/PurOrderController.java

@@ -414,6 +414,8 @@ public class PurOrderController {
             // 1-已提交,0-未提交
             String submit = o.getSubmit();
             String code = o.getBillCode();
+            String supplier = o.getSupplier();
+            String supplierName = o.getSupplierName();
 
             //关闭(close)1是0否
             String getClose = o.getClose();
@@ -426,6 +428,13 @@ public class PurOrderController {
                 sb.append("单据编码" + code).append("已提交,请勿再次提交;");
                 continue;
             }
+
+            CuspSupplierProfile classEnt = cuspSupplierProfileService.getById(supplier);
+            if(classEnt == null || classEnt.getStatus().equals(0)){
+                sb.append("单据" + code).append("供应商:"+supplierName+",不存在或已停用,请更换供应商;");
+                continue;
+            }
+
         }
 
         if (StringUtils.isNotBlank(sb.toString())) {

+ 4 - 1
srm-module-code/src/main/java/org/jeecg/modules/purCode/entity/PurInquiryForm.java

@@ -165,6 +165,8 @@ public class PurInquiryForm implements Serializable {
     @ApiModelProperty(value = "询价备注(inquiry notes)")
     private String inquiryNotes;
 
+    //协议条款
+    private String agreementTerms;
     //销售说明 销售询价单的备注
     private String saleNotes;
     //来源单号(销售询价单)
@@ -175,7 +177,8 @@ public class PurInquiryForm implements Serializable {
     //质量等级
     private String qualityGradeHead;
 
-
+    //邮件发送次数,默认0
+    private Integer sentNumber;
     //导出字段使用
     @TableField(exist = false)
     private String purchaseman;

+ 1 - 0
srm-module-code/src/main/java/org/jeecg/modules/purCode/mapper/PurInquiryFormMapper.java

@@ -16,4 +16,5 @@ public interface PurInquiryFormMapper extends BaseMapper<PurInquiryForm> {
 
     //更新询价状态
     int changeType(@Param("code")String code,@Param("type")String type);
+    int changeSentNumber(@Param("code")String code);
 }

+ 2 - 1
srm-module-code/src/main/java/org/jeecg/modules/purCode/mapper/PurInquiryFormProductMapper.java

@@ -10,6 +10,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import org.apache.ibatis.annotations.Param;
 import org.jeecg.modules.saleCode.vo.SaleInquiryFormAlert;
 
+import org.jeecg.modules.purCode.vo.PurInquiryFormAlert;
 /**
  * @Description: 采购询价单子表 - 产品明细
  * @Author: jeecg-boot
@@ -18,7 +19,7 @@ import org.jeecg.modules.saleCode.vo.SaleInquiryFormAlert;
  */
 public interface PurInquiryFormProductMapper extends BaseMapper<PurInquiryFormProduct> {
 
-	public IPage<SaleInquiryFormAlert> alertPurInquiryList(Page<SaleInquiryFormAlert> page, @Param("ew") QueryWrapper<SaleInquiryFormAlert> queryWrapper);
+	public IPage<PurInquiryFormAlert> alertPurInquiryList(Page<PurInquiryFormAlert> page, @Param("ew") QueryWrapper<PurInquiryFormAlert> queryWrapper);
 
 	/**
 	 * 通过主表id删除子表数据

+ 5 - 0
srm-module-code/src/main/java/org/jeecg/modules/purCode/mapper/xml/PurInquiryFormMapper.xml

@@ -7,4 +7,9 @@
         update pur_inquiry_form set status =#{type} where bill_code =#{code}
 
     </update>
+
+    <update id="changeSentNumber">
+        update pur_inquiry_form set sent_number = sent_number+1 where bill_code =#{code}
+    </update>
+
 </mapper>

+ 61 - 1
srm-module-code/src/main/java/org/jeecg/modules/purCode/mapper/xml/PurInquiryFormProductMapper.xml

@@ -14,6 +14,66 @@
 		WHERE
 			 head_id = #{mainId} order by create_time asc  	</select>
 
+	<select id="alertPurInquiryList" resultType="org.jeecg.modules.purCode.vo.PurInquiryFormAlert">
+		select *
+		from (
+				 select a.id            headId
+					  , b.id            child_id
+					  , a.model         head_model
+					  , b.model         child_model
+					  , a.delivery_time head_delivery_time
+					  , b.delivery_time child_delivery_time
+					  , a.*
+					  , b.product_id
+					  , b.product_class
+					  , b.product_code
+					  , b.chinese_name
+					  , b.english_name
+					  , b.specifications
+					  , b.partno
+					  , b.drawingno
+					  , b.orderno
+					  , b.factory
+					  , b.quality_grade
+					  , b.quantity
+					  , b.unit
+					  , b.need_ship
+					  , b.ship_inspection
+					  , b.notes
+					  , b.source_id sourceId2
+
+				 from (
+							SELECT
+
+							TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX(sd.suppiler_name, ',', n.n), ',', -1)) AS suppiler_name1,
+							TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX(sd.inquiry_suppiler, ',', n.n), ',', -1)) AS inquiry_suppiler1,
+							sd.*
+							FROM
+							pur_inquiry_form sd
+							JOIN
+							(SELECT 1 AS n UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL
+							SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL
+							SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9 UNION ALL SELECT 10) n
+							ON
+							n.n &lt;= LENGTH(sd.inquiry_suppiler) - LENGTH(REPLACE(sd.inquiry_suppiler, ',', '')) + 1 WHERE sd.del_flag = 0 and sd.submit = 1
+																												  and sd.status = 0
+							ORDER BY
+							sd.id, n.n
+
+						  ) a
+						  left join pur_inquiry_form_product b on a.id = b.head_id
+						  left join base_project_archive d on a.inquiry_project = d.id
+
+				 where a.del_flag = 0
+				   and a.submit = 1
+				   and a.status = 0
+				   and b.del_flag = 0
+				   and d.status = 1 order by a.inquiry_suppiler1, b.create_time asc
+			 ) a
+			${ew.customSqlSegment}
+	</select>
+
+	<!--
 	<select id="alertPurInquiryList" resultType="org.jeecg.modules.purCode.vo.PurInquiryFormAlert">
 		select *
 		from (
@@ -53,5 +113,5 @@
 				   and d.status = 1 order by b.create_time asc
 			 ) a
 			${ew.customSqlSegment}
-	</select>
+	</select>-->
 </mapper>

+ 2 - 1
srm-module-code/src/main/java/org/jeecg/modules/purCode/service/IPurInquiryFormProductService.java

@@ -9,6 +9,7 @@ import org.jeecg.modules.saleCode.vo.SaleInquiryFormAlert;
 
 import java.util.List;
 
+import org.jeecg.modules.purCode.vo.PurInquiryFormAlert;
 /**
  * @Description: 采购询价单子表 - 产品明细
  * @Author: jeecg-boot
@@ -17,7 +18,7 @@ import java.util.List;
  */
 public interface IPurInquiryFormProductService extends IService<PurInquiryFormProduct> {
 
-	IPage<SaleInquiryFormAlert> alertPurInquiryList(Page<SaleInquiryFormAlert> page, QueryWrapper<SaleInquiryFormAlert> queryWrapper);
+	IPage<PurInquiryFormAlert> alertPurInquiryList(Page<PurInquiryFormAlert> page, QueryWrapper<PurInquiryFormAlert> queryWrapper);
 
 	/**
 	 * 通过主表id查询子表数据

+ 2 - 1
srm-module-code/src/main/java/org/jeecg/modules/purCode/service/impl/PurInquiryFormProductServiceImpl.java

@@ -12,6 +12,7 @@ import java.util.List;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
+import org.jeecg.modules.purCode.vo.PurInquiryFormAlert;
 
 /**
  * @Description: 采购询价单子表 - 产品明细
@@ -33,7 +34,7 @@ public class PurInquiryFormProductServiceImpl extends ServiceImpl<PurInquiryForm
 
 	@Override
 	@Transactional(rollbackFor = Exception.class)
-	public IPage<SaleInquiryFormAlert> alertPurInquiryList(Page<SaleInquiryFormAlert> page, QueryWrapper<SaleInquiryFormAlert> queryWrapper){
+	public IPage<PurInquiryFormAlert> alertPurInquiryList(Page<PurInquiryFormAlert> page, QueryWrapper<PurInquiryFormAlert> queryWrapper){
 		return purInquiryFormProductMapper.alertPurInquiryList(page,queryWrapper);
 	}
 

+ 4 - 0
srm-module-code/src/main/java/org/jeecg/modules/purCode/vo/PurInquiryFormAlert.java

@@ -54,10 +54,12 @@ public class PurInquiryFormAlert {
     @Excel(name = "询价供应商(inquiry supplier)", width = 15)
     @ApiModelProperty(value = "询价供应商(inquiry supplier)")
     private String inquirySuppiler;
+    private String inquirySuppiler1;
     /**供应商名称*/
     @Excel(name = "供应商名称", width = 15)
     @ApiModelProperty(value = "供应商名称")
     private String suppilerName;
+    private String suppilerName1;
     /**询价有效期(inquiry period)止*/
     @Excel(name = "询价有效期(inquiry period)止", width = 15, format = "yyyy-MM-dd")
     @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd")
@@ -130,6 +132,8 @@ public class PurInquiryFormAlert {
     @Excel(name = "询价备注(inquiry notes)", width = 15)
     @ApiModelProperty(value = "询价备注(inquiry notes)")
     private String inquiryNotes;
+    //协议条款
+    private String agreementTerms;
 
     //销售说明 销售询价单的备注
     private String saleNotes;

+ 2 - 0
srm-module-code/src/main/java/org/jeecg/modules/purCode/vo/PurInquiryFormPage.java

@@ -163,6 +163,8 @@ public class PurInquiryFormPage {
     private String sourceCode;
 	//来源销售询价单文件
     private String saleAttachs;
+	//协议条款
+	private String agreementTerms;
 
 	//质量等级
 	private String qualityGradeHead;

+ 52 - 10
srm-module-code/src/main/java/org/jeecg/modules/saleCode/controller/SaleInquiryFormController.java

@@ -138,22 +138,36 @@ public class SaleInquiryFormController {
                                                                     @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
                                                                     HttpServletRequest req) {
 
-
         LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
-        if (!sysUser.getUsername().equals("admin")) {
 
-            String orgCode = sysUser.getOrgCode();
-            if (StringUtils.isNotBlank(orgCode)) {
-                SysDepart dept = sysDepartService.queryDeptByCode(orgCode);
-                if (dept != null) {
-                    saleInquiryForm.setInquiryTeam(dept.getId());
+        QueryWrapper<SaleInquiryFormAlert> queryWrapper = QueryGenerator.initQueryWrapper(saleInquiryForm, req.getParameterMap());
+        Page<SaleInquiryFormAlert> page = new Page<SaleInquiryFormAlert>(pageNo, pageSize);
+
+        if (!sysUser.getUsername().equals("admin")) {
+            String roleCode = sysUser.getRoleCode();
+            if(roleCode.contains("R0031")){
+                queryWrapper.and(i -> i.likeRight("inquiry_team_name", "A02A03").or().eq("inquiry_Team", "SALES"));//.or().isNull("inquiry_Team"));
+            }else{
+
+                String orgCode = sysUser.getOrgCode();
+                if (StringUtils.isNotBlank(orgCode)) {
+                    SysDepart dept = sysDepartService.queryDeptByCode(orgCode);
+                    if (dept != null) {
+
+                        if(sysUser.getOrgCode().equals("A02A03A08")||
+                                sysUser.getOrgCode().equals("A02A03A09")||
+                                sysUser.getOrgCode().equals("A02A03A10")||
+                                sysUser.getOrgCode().equals("A02A03A11")){
+
+                            queryWrapper.and(i -> i.eq("inquiry_team", dept.getId()).or().eq("inquiry_Team", "SALES"));
+                        } else{
+                            queryWrapper.eq("inquiry_Team",dept.getId());
+                        }
+                    }
                 }
             }
         }
 
-        QueryWrapper<SaleInquiryFormAlert> queryWrapper = QueryGenerator.initQueryWrapper(saleInquiryForm, req.getParameterMap());
-        Page<SaleInquiryFormAlert> page = new Page<SaleInquiryFormAlert>(pageNo, pageSize);
-
         IPage<SaleInquiryFormAlert> pageList = saleInquiryFormService.alertSaleInquiryList(page, queryWrapper);
         return Result.OK(pageList);
     }
@@ -203,6 +217,20 @@ public class SaleInquiryFormController {
                 saleInquiryForm.setSaleDepartmentName(dept.getDepartName());
             }
         }
+        if (StringUtils.isNotBlank(saleInquiryForm.getInquiryTeam())) {
+            SysDepart dept = sysDepartService.getDepartById(saleInquiryForm.getInquiryTeam());
+            if (dept != null) {
+                saleInquiryForm.setInquiryTeamName(dept.getOrgCode());
+            }else{
+                List<SysDepart> dept2 = sysDepartService.queryDeptByName(saleInquiryForm.getInquiryTeam());
+                if (dept2.size() > 0) {
+                    saleInquiryForm.setInquiryTeamName(dept2.get(0).getOrgCode());
+                    saleInquiryForm.setInquiryTeam(dept2.get(0).getId());
+                }else{
+                    saleInquiryForm.setInquiryTeamName(saleInquiryForm.getInquiryTeam());
+                }
+            }
+        }
 
         saleInquiryFormService.saveMain(saleInquiryForm, saleInquiryFormPage.getSaleInquiryFormShipList(), saleInquiryFormPage.getSaleInquiryFormProductList());
         return Result.OK("添加成功!");
@@ -232,6 +260,20 @@ public class SaleInquiryFormController {
                 saleInquiryForm.setSaleDepartmentName(dept.getDepartName());
             }
         }
+        if (StringUtils.isNotBlank(saleInquiryForm.getInquiryTeam())) {
+            SysDepart dept = sysDepartService.getDepartById(saleInquiryForm.getInquiryTeam());
+            if (dept != null) {
+                saleInquiryForm.setInquiryTeamName(dept.getOrgCode());
+            }else{
+                List<SysDepart> dept2 = sysDepartService.queryDeptByName(saleInquiryForm.getInquiryTeam());
+                if (dept2.size() > 0) {
+                    saleInquiryForm.setInquiryTeamName(dept2.get(0).getDepartName());
+                    saleInquiryForm.setInquiryTeam(dept2.get(0).getId());
+                }else{
+                    saleInquiryForm.setInquiryTeamName(saleInquiryForm.getInquiryTeam());
+                }
+            }
+        }
         saleInquiryFormService.updateMain(saleInquiryForm, saleInquiryFormPage.getSaleInquiryFormShipList(), saleInquiryFormPage.getSaleInquiryFormProductList());
         return Result.OK("编辑成功!");
     }

+ 22 - 0
srm-module-code/src/main/java/org/jeecg/modules/saleCode/controller/SaleInvoiceController.java

@@ -73,6 +73,7 @@ import org.jeecg.modules.saleCode.vo.SaleInvoicePage;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.env.Environment;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.servlet.ModelAndView;
 import org.springframework.web.multipart.MultipartFile;
@@ -157,7 +158,12 @@ public class SaleInvoiceController {
 
     @Value(value = "${jeecg.path.upload}")
     private String uploadpath;
+    @Autowired
+    private Environment environment;
 
+    public String getActiveProfile() {
+        return environment.getProperty("spring.profiles.active");
+    }
     /**
      * 分页列表查询
      *
@@ -182,7 +188,19 @@ public class SaleInvoiceController {
         String dept = sysUser.getOrgCode();
         String userName =  sysUser.getUsername();
 
+
         if(!userName.equals("admin") && !userName.equals("jack") && !userName.equals("max") && !"A02A05".equals(dept)){
+
+            if(userName.equals("louisa")){
+
+                String active = getActiveProfile();
+                if(StringUtils.isNotBlank(active) && (active.equals("prod8004") || active.equals("dev"))){
+
+                    IPage<SaleInvoice> pageList = saleInvoiceService.page(page, queryWrapper);
+                    return Result.OK(pageList);
+                }
+            }
+
             queryWrapper.and(wrapper ->
                     wrapper.eq("sys_org_code_delivery", dept)
                             .or()
@@ -976,6 +994,8 @@ public class SaleInvoiceController {
             String productClass = saleDelivery.getProductionClass();
             String orderCode = saleDelivery.getSourceCode();
             String currency = saleDelivery.getCurrency();
+            String maker = saleDelivery.getMaker();
+            String model = saleDelivery.getModel();
             saleInvoice.setProductionClass(productClass);
             saleInvoice.setCurrency(currency);
 
@@ -1195,6 +1215,8 @@ public class SaleInvoiceController {
 //                    }
                     saleInvoice.setSalesmanName(saleCreateBy);
 //                }
+                    saleInvoice.setMaker(maker);
+                    saleInvoice.setModel(model);
 
                     String templateFilePath = uploadpath + templates.getTemplateFile();
                     String tempFilePath = uploadpath + "/"+ UUIDGenerator.generate()+".xlsx";

+ 48 - 0
srm-module-code/src/main/java/org/jeecg/modules/saleCode/controller/SaleQuotationController.java

@@ -164,7 +164,55 @@ public class SaleQuotationController {
                                                       @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
                                                       @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
                                                       HttpServletRequest req) {
+
+
+        String productCode = saleQuotation.getProductCode();
+        String englishName = saleQuotation.getEnglishName();
+
+        String customerInquiryNumber = saleQuotation.getCustomerInquiryNumber();
+
+        saleQuotation.setProductCode(null);
+        saleQuotation.setEnglishName(null);
+        saleQuotation.setCustomerInquiryNumber(null);
+
         QueryWrapper<SaleQuotation> queryWrapper = QueryGenerator.initQueryWrapper(saleQuotation, req.getParameterMap());
+
+        if(StringUtils.isNotBlank(customerInquiryNumber)){
+
+            QueryWrapper<SaleInquiryForm> queryWrapperSaleInquiryForm = new QueryWrapper<>();
+            queryWrapperSaleInquiryForm.eq("customer_Inquiry_Number",customerInquiryNumber);
+            queryWrapperSaleInquiryForm.eq("del_flag",0);
+            queryWrapperSaleInquiryForm.eq("submit",1);
+            List<SaleInquiryForm> saleQuotationList = saleInquiryFormService.list(queryWrapperSaleInquiryForm);
+            if(saleQuotationList.size() > 0){
+
+                List<String> codes = saleQuotationList.stream().map(SaleInquiryForm::getInquiryProject).collect(Collectors.toList());
+                queryWrapper.in("quotation_Project",codes);
+            }
+        }
+
+
+        if(StringUtils.isNotBlank(englishName) || StringUtils.isNotBlank(productCode)){
+
+            QueryWrapper<SaleQuotationProduct> childQueryWrapper = new QueryWrapper<>();
+            if(StringUtils.isNotBlank(productCode)){
+
+                childQueryWrapper.eq("product_code", productCode);
+            }
+            if(StringUtils.isNotBlank(englishName)){
+
+                childQueryWrapper.eq("english_name", englishName);
+            }
+
+            List<SaleQuotationProduct> productList = saleQuotationProductService.list(childQueryWrapper);
+            if(productList.size() > 0 ){
+
+                List<String> ids = productList.stream().map(SaleQuotationProduct::getHeadId).collect(Collectors.toList());
+                queryWrapper.in("id",ids);
+            }
+        }
+
+
         Page<SaleQuotation> page = new Page<SaleQuotation>(pageNo, pageSize);
         IPage<SaleQuotation> pageList = saleQuotationService.page(page, queryWrapper);
         List<SaleQuotation> quotationList = pageList.getRecords();

+ 4 - 0
srm-module-code/src/main/java/org/jeecg/modules/saleCode/entity/SaleInvoice.java

@@ -248,4 +248,8 @@ public class SaleInvoice implements Serializable {
     private String salesmanName;
     @TableField(exist = false)
     private String agreementTerms;
+    @TableField(exist = false)
+    private String maker;//厂家
+    @TableField(exist = false)
+    private String model;//机型
 }

+ 6 - 0
srm-module-code/src/main/java/org/jeecg/modules/saleCode/entity/SaleQuotation.java

@@ -260,4 +260,10 @@ public class SaleQuotation implements Serializable {
     // 客户询价单号
     @TableField(exist = false)
     private String customerInquiryNumber;
+
+//    子表查询使用
+    @TableField(exist = false)
+    private String productCode;
+    @TableField(exist = false)
+    private String englishName;
 }

+ 1 - 1
srm-module-code/src/main/java/org/jeecg/modules/saleCode/entity/SaleQuotationProduct.java

@@ -134,7 +134,7 @@ public class SaleQuotationProduct implements Serializable {
     @ApiModelProperty(value = "税率(tax rate)")
     private java.math.BigDecimal taxRate;
 	/**毛利率(gross margin)*/
-	@Excel(name = "毛利率(gross margin)", width = 15,type=4)
+	@Excel(name = "毛利率(NET)", width = 15,type=4)
     @ApiModelProperty(value = "毛利率(gross margin)")
     private java.math.BigDecimal grossMargin;
 	/**折扣(discount)*/

+ 346 - 6
srm-module-code/src/main/java/org/jeecg/modules/saleCode/service/impl/SaleInterfaceSyncServiceImpl.java

@@ -12,6 +12,8 @@ import com.google.gson.JsonObject;
 import io.micrometer.core.instrument.util.StringUtils;
 import io.swagger.annotations.ApiModelProperty;
 import org.apache.logging.log4j.util.Strings;
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.text.PDFTextStripper;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.apache.poi.ss.usermodel.*;
 import org.apache.shiro.SecurityUtils;
@@ -39,6 +41,7 @@ import org.jeecg.modules.saleCode.entity.SaleInterfaceItem;
 import org.jeecg.modules.saleCode.mapper.SaleInterfaceItemMapper;
 import org.jeecg.modules.saleCode.mapper.SaleInterfaceSyncMapper;
 import org.jeecg.modules.saleCode.service.ISaleInterfaceSyncService;
+import org.jeecg.modules.saleCode.util.CoordinateTextStripper;
 import org.jeecg.modules.saleCode.util.HttpUtils;
 import org.jeecg.modules.saleCode.util.MonthUtil;
 import org.jeecg.modules.saleCode.util.PDFTableReader;
@@ -53,6 +56,8 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.multipart.MultipartFile;
 
+import java.io.File;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.Serializable;
 import java.math.BigDecimal;
@@ -340,16 +345,56 @@ public class SaleInterfaceSyncServiceImpl extends ServiceImpl<SaleInterfaceSyncM
         return Result.OK("执行成功");
     }
 
-    public static void main(String[] args) {
-        String dateStr = "2025-04-11T08:33:50.963Z";
+    public static void main(String[] args) throws IOException {
+//        String dateStr = "2025-04-11T08:33:50.963Z";
+//
+//        Instant instant = Instant.parse(dateStr);
+//        Date date = Date.from(instant);
+//        BaseShipArchive baseShipArchive = new BaseShipArchive();
+//        System.out.println(baseShipArchive.getId());
+
+        // 1. 加载PDF文件
+        PDDocument document = PDDocument.load(new File("E:\\新建文件夹\\RFQ DMS_250237.pdf"));
+        PDFTextStripper stripper = new PDFTextStripper();
+        String text = stripper.getText(document);
+//        System.out.println(text);
+
+
+        System.out.println("=============================="); // 输出结果
+        String requestNo = extractField(text, "Request No\\.:", "\\n");
+        System.out.println("1. Request No.: " + requestNo);
+        String Buyer = extractField(text, "Buyer\\:", "\\n");
+        System.out.println("Buyer: " + Buyer);
+        String For = extractField(text, "For\\:", "\\n");
+        System.out.println("For: " + For);
+        String VesselIMOnumber = extractField(text, "Vessel IMO number\\:", "\\n");
+        System.out.println("Vessel IMO number: " + VesselIMOnumber);
+
+        String Equipment = extractField(text, "Equipment\\:", "\\n");
+        System.out.println("Equipment: " + Equipment);
+
+
+
+
+
+        document.close();
+
 
-        Instant instant = Instant.parse(dateStr);
-        Date date = Date.from(instant);
-        BaseShipArchive baseShipArchive = new BaseShipArchive();
-        System.out.println(baseShipArchive.getId());
     }
 
 
+    /**
+     * 提取单个字段值
+     */
+    private static String extractField(String text, String fieldName, String delimiter) {
+        Pattern pattern = Pattern.compile(fieldName + "\\s*([^" + delimiter + "]+)");
+        Matcher matcher = pattern.matcher(text);
+        if (matcher.find()) {
+            return matcher.group(1).trim();
+        }
+        return "未找到";
+    }
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public synchronized Result<String> actionSyncOrder(Collection<? extends Serializable> idList) {
@@ -672,6 +717,10 @@ public class SaleInterfaceSyncServiceImpl extends ServiceImpl<SaleInterfaceSyncM
             case "12":
                 OMAN(file);
                 break;
+            case "13":
+//                RFQ(file, txt);
+                extractItems(file);
+                break;
             default:
                 return;
         }
@@ -1495,6 +1544,105 @@ public class SaleInterfaceSyncServiceImpl extends ServiceImpl<SaleInterfaceSyncM
 
     }
 
+    public void RFQ(MultipartFile file,String text) throws Exception {
+
+        SaleInterfaceSync saleInterfaceSync = new SaleInterfaceSync();
+        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+        String id = UUIDGenerator.generate();
+        saleInterfaceSync.setId(id);
+        saleInterfaceSync.setCreateBy(sysUser.getUsername());
+
+        String requestNo = extractField(text, "Request No\\.:", "\\n");
+        String Buyer = extractField(text, "Buyer\\:", "\\n");
+        String Buyer2 = extractField(text, "Buyer contact\\:", "\\n");
+        String For = extractField(text, "For\\:", "\\n");
+        String VesselIMOnumber = extractField(text, "Vessel IMO number\\:", "\\n");
+        String Equipment = extractField(text, "Equipment\\:", "\\n");
+
+        saleInterfaceSync.setReferenceNumber(requestNo);
+        if(StringUtils.isNotBlank(Buyer2) && !Buyer2.equals("User")){
+
+            saleInterfaceSync.setBuyerName(Buyer+" "+Buyer2);
+        }else{
+
+            saleInterfaceSync.setBuyerName(Buyer);
+        }
+        saleInterfaceSync.setVesselImo(VesselIMOnumber);
+        saleInterfaceSync.setVesselCode(For);
+        saleInterfaceSync.setSubject(Equipment);
+
+        List<String> fieldList = new ArrayList<>();
+        fieldList.add("No.");
+        fieldList.add("Item name");
+        fieldList.add("Vendor");
+        fieldList.add("Buyer");
+        fieldList.add("Maker's No.");
+        fieldList.add("IMPA");
+        fieldList.add("Maker");
+        fieldList.add("Quantity");
+        fieldList.add("Unit");
+
+        List<String> ignoreList = new ArrayList<>();
+        ignoreList.add("Page");
+        ignoreList.add("Request For Quotation");
+        ignoreList.add("LIMITED as Managers");
+        ignoreList.add("behalf of Owners Abundance");
+        ignoreList.add("Shipsure Version Number");
+        ignoreList.add("Plate / Sheet No");
+        ignoreList.add("Order Line Notes");
+        ignoreList.add("Sub Total");
+        ignoreList.add("Freight Cost");
+        ignoreList.add("Packaging Cost");
+        ignoreList.add("Grand Total");
+        ignoreList.add("(%)");
+        ignoreList.add("1 of");
+        ignoreList.add("2 of");
+        ignoreList.add("3 of");
+        ignoreList.add("4 of");
+        ignoreList.add("5 of");
+        ignoreList.add("6 of");
+        ignoreList.add("7 of");
+        ignoreList.add("8 of");
+
+        String[] extra = {"/"};
+//        PdfTable pdfTable = PDFTableReader.handlePdf(file, "Request - Opened");
+        PdfTable pdfTable = PDFTableReader.handlePdf(file, "Items");
+        JSONArray jsonArray = PDFTableReader.getPdfTable(pdfTable, fieldList, ignoreList, extra, "Item name", "Unit", "left", true);
+
+        try {
+            Map<String, JSONObject> willSortedData = new HashMap<>();
+            for(Object data : jsonArray) {
+                willSortedData.put(((JSONObject)data).getString("No."), (JSONObject)data);
+            }
+            List<JSONObject> values = willSortedData.values().stream().sorted(new Comparator<JSONObject>() {
+                @Override
+                public int compare(JSONObject o1, JSONObject o2) {
+                    return (o1.getInteger("No.") - o2.getInteger("No."));
+                }}).collect(Collectors.toList());
+
+            jsonArray = JSONArray.parseArray(JSONArray.toJSONString(values));
+        } catch (Exception e) {
+            log.error("去重失败", e);
+        }
+
+        for(Object node : jsonArray) {
+            JSONObject jsonObject = JSONObject.parseObject(String.valueOf(node));
+            if(jsonObject.size() >= 0) {
+                SaleInterfaceItem saleInterfaceItem = new SaleInterfaceItem();
+                saleInterfaceItem.setNumber(Integer.valueOf(jsonObject.getString("No.")));
+                saleInterfaceItem.setDescription(jsonObject.getString("Item name"));
+                String formattedStr = jsonObject.getString("Quantity").replace(',', '.');
+                saleInterfaceItem.setQuantity(formattedStr);
+                saleInterfaceItem.setUnitOfMeasure(jsonObject.getString("Unit") == null ? "" : jsonObject.getString("Unit").toUpperCase());
+                saleInterfaceItem.setHeadId(id);
+                saleInterfaceItemMapper.insert(saleInterfaceItem);
+            }
+        }
+        saleInterfaceSyncMapper.insert(saleInterfaceSync);
+
+    }
+
+
     public void OMAN(MultipartFile file) throws Exception {
         try {
 
@@ -1730,4 +1878,196 @@ public class SaleInterfaceSyncServiceImpl extends ServiceImpl<SaleInterfaceSyncM
         }
     }
 
+    private static final float Y_TOLERANCE = 5.0f;
+    private static final List<String> UNITS = Arrays.asList("PCE", "PC", "SET", "EA", "PR", "UNIT", "NOS");
+
+    public List<Map<String, Object>> extractItems(MultipartFile file) {
+        try (PDDocument document = PDDocument.load(file.getInputStream())) {
+            CoordinateTextStripper stripper = new CoordinateTextStripper();
+            stripper.setSortByPosition(true);
+            stripper.getText(document);
+
+            List<CoordinateTextStripper.TextChunk> chunks = stripper.getTextChunks();
+
+            // 1. 按 Y 坐标分组(同一行)
+            Map<Float, List<CoordinateTextStripper.TextChunk>> rows = new TreeMap<>();
+            for (CoordinateTextStripper.TextChunk chunk : chunks) {
+                float yKey = Math.round(chunk.getY() / Y_TOLERANCE) * Y_TOLERANCE;
+                rows.computeIfAbsent(yKey, k -> new ArrayList<>()).add(chunk);
+            }
+
+            // 2. 将每行的文本块按 X 坐标排序,得到单元格列表
+            List<List<String>> table = new ArrayList<>();
+            for (List<CoordinateTextStripper.TextChunk> rowChunks : rows.values()) {
+                rowChunks.sort(Comparator.comparing(CoordinateTextStripper.TextChunk::getX));
+                List<String> rowCells = rowChunks.stream()
+                        .map(CoordinateTextStripper.TextChunk::getText)
+                        .collect(Collectors.toList());
+                table.add(rowCells);
+            }
+
+            // 3. 定位 "Items" 标题所在行
+            int itemsRowIndex = -1;
+            for (int i = 0; i < table.size(); i++) {
+                List<String> row = table.get(i);
+                String rowText = String.join("", row);
+                if (rowText.contains("Items")) {
+                    itemsRowIndex = i;
+                    break;
+                }
+            }
+
+            if (itemsRowIndex == -1) {
+                throw new RuntimeException("未找到 Items 标题");
+            }
+
+            // 4. 解析 Items 后的每一行
+            List<Map<String, Object>> items = new ArrayList<>();
+            for (int i = itemsRowIndex + 1; i < table.size(); i++) {
+                List<String> row = table.get(i);
+                if (row.isEmpty()) continue;
+
+                String fullRowText = String.join(" ", row).trim();
+                String firstCell = row.get(0).trim();
+
+                // 判断是否为数据行(首单元格以数字开头)
+                if (firstCell.isEmpty() || !Character.isDigit(firstCell.charAt(0))) {
+                    continue;
+                }
+
+                // 提取序号
+                String no = extractNumberPrefix(firstCell);
+                String description;
+                String quantity;
+                String unit;
+
+                if (row.size() == 1) {
+                    // 情形1:整行合并为一个文本块 -> 从完整字符串解析
+                    ItemInfo info = parseItemFromText(fullRowText);
+                    description = info.description;
+                    quantity = info.quantity;
+                    unit = info.unit;
+                } else {
+                    // 情形2:多列,最后一列为数量+单位
+                    String lastCell = row.get(row.size() - 1).trim();
+                    ItemInfo lastCellInfo = parseQuantityUnit(lastCell);
+                    if (lastCellInfo != null && !lastCellInfo.quantity.isEmpty()) {
+                        quantity = lastCellInfo.quantity;
+                        unit = lastCellInfo.unit;
+                        // 描述为中间列合并
+                        StringBuilder descBuilder = new StringBuilder();
+                        for (int j = 1; j < row.size() - 1; j++) {
+                            descBuilder.append(row.get(j)).append(" ");
+                        }
+                        description = descBuilder.toString().trim();
+                    } else {
+                        // 若最后一列不包含数量,则所有剩余列作为描述
+                        StringBuilder descBuilder = new StringBuilder();
+                        for (int j = 1; j < row.size(); j++) {
+                            descBuilder.append(row.get(j)).append(" ");
+                        }
+                        description = descBuilder.toString().trim();
+                        quantity = "1.0";
+                        unit = "PCE";
+                    }
+                }
+
+                // 修正数量为0的情况
+                try {
+                    double qtyVal = Double.parseDouble(quantity);
+                    if (qtyVal == 0.0) quantity = "1.0";
+                } catch (NumberFormatException e) {
+                    // 保持原样
+                }
+
+                description = description.trim().replaceAll("\\s+", " ");
+
+                Map<String, Object> item = new LinkedHashMap<>();
+                item.put("No.", no);
+                item.put("Item name", description);
+                item.put("Vendor cat. No.", "");
+                item.put("Buyer part no", "");
+                item.put("Maker's No.", "");
+                item.put("IMPA", "");
+                item.put("Maker", "");
+                item.put("Quantity", quantity);
+                item.put("Unit", unit);
+                items.add(item);
+            }
+
+            return items;
+        } catch (IOException e) {
+            throw new RuntimeException("PDF 解析失败", e);
+        }
+    }
+
+    private ItemInfo parseItemFromText(String text) {
+        String no = extractNumberPrefix(text);
+        if (no.isEmpty()) {
+            return new ItemInfo("", text, "1.0", "PCE");
+        }
+        String remaining = text.substring(no.length()).trim();
+
+        ItemInfo qtyInfo = parseQuantityUnit(remaining);
+        if (qtyInfo != null && !qtyInfo.quantity.isEmpty()) {
+            int qtyStart = remaining.lastIndexOf(qtyInfo.quantity + qtyInfo.unit);
+            if (qtyStart >= 0) {
+                String description = remaining.substring(0, qtyStart).trim();
+                return new ItemInfo(no, description, qtyInfo.quantity, qtyInfo.unit);
+            }
+        }
+        return new ItemInfo(no, remaining, "1.0", "PCE");
+    }
+
+    private ItemInfo parseQuantityUnit(String text) {
+        String upperText = text.toUpperCase();
+        for (String unit : UNITS) {
+            if (upperText.endsWith(unit)) {
+                int unitStart = text.length() - unit.length();
+                String numPart = text.substring(0, unitStart).trim();
+                String quantity = extractTrailingNumber(numPart);
+                if (!quantity.isEmpty()) {
+                    return new ItemInfo("", "", quantity, unit);
+                }
+            }
+        }
+        return null;
+    }
+
+    private String extractNumberPrefix(String s) {
+        StringBuilder num = new StringBuilder();
+        for (char c : s.toCharArray()) {
+            if (Character.isDigit(c)) {
+                num.append(c);
+            } else {
+                break;
+            }
+        }
+        return num.toString();
+    }
+
+    private String extractTrailingNumber(String s) {
+        if (s.isEmpty()) return "";
+        int i = s.length() - 1;
+        while (i >= 0 && (Character.isDigit(s.charAt(i)) || s.charAt(i) == '.' || s.charAt(i) == ',')) {
+            i--;
+        }
+        String number = s.substring(i + 1).trim();
+        number = number.replace(',', '.');
+        return number;
+    }
+
+    private static class ItemInfo {
+        String no;
+        String description;
+        String quantity;
+        String unit;
+
+        ItemInfo(String no, String description, String quantity, String unit) {
+            this.no = no;
+            this.description = description;
+            this.quantity = quantity;
+            this.unit = unit;
+        }
+    }
 }

+ 50 - 0
srm-module-code/src/main/java/org/jeecg/modules/saleCode/util/CoordinateTextStripper.java

@@ -0,0 +1,50 @@
+package org.jeecg.modules.saleCode.util;
+import org.apache.pdfbox.text.PDFTextStripper;
+import org.apache.pdfbox.text.TextPosition;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class CoordinateTextStripper extends PDFTextStripper {
+    private final List<TextChunk> textChunks = new ArrayList<>();
+
+    public CoordinateTextStripper() throws IOException {
+        super();
+    }
+
+    @Override
+    protected void writeString(String text, List<TextPosition> textPositions) {
+        // 将连续的文本合并为一个块(这里合并整个字符串,位置取第一个字符)
+        if (!textPositions.isEmpty()) {
+            TextPosition first = textPositions.get(0);
+            float x = first.getXDirAdj();
+            float y = first.getYDirAdj();
+            textChunks.add(new TextChunk(text, x, y));
+        }
+    }
+
+    public List<TextChunk> getTextChunks() {
+        return textChunks;
+    }
+
+    public static class TextChunk {
+        private final String text;
+        private final float x;
+        private final float y;
+
+        public TextChunk(String text, float x, float y) {
+            this.text = text;
+            this.x = x;
+            this.y = y;
+        }
+
+        public String getText() { return text; }
+        public float getX() { return x; }
+        public float getY() { return y; }
+
+        @Override
+        public String toString() {
+            return String.format("(%.2f, %.2f) %s", x, y, text);
+        }
+    }
+}

+ 1 - 1
srm-module-code/src/main/java/org/jeecg/modules/saleCode/vo/SaleInquiryFormAlert.java

@@ -26,7 +26,7 @@ public class SaleInquiryFormAlert {
 
 	@ApiModelProperty(value = "headId")
     private String headId;
-	@ApiModelProperty(value = "headId")
+	@ApiModelProperty(value = "childId")
     private String childId;
 	/**其他状态(other status)*/
 	@Excel(name = "其他状态(other status)", width = 15)

+ 58 - 3
srm-module-code/src/main/java/org/jeecg/modules/utils/ExcelExportUtils.java

@@ -7,9 +7,7 @@ import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 import org.jeecg.common.util.oConvertUtils;
 import org.springframework.stereotype.Component;
 
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.OutputStream;
+import java.io.*;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
@@ -76,6 +74,63 @@ public class ExcelExportUtils {
         }
     }
 
+
+    public static void excelInsertRowNotes(String code,String outputDir,String tempFilePath, int startIndex, List<String> noteList,
+                                           int mergeStartColumn, int mergeEndColumn) {
+        // 指定输出路径:D:\files\A0001.xlsx
+        String outputFile = outputDir + "\\temp\\"+code+".xlsx";
+
+        File dir = new File(outputDir);
+        if (!dir.exists()) {
+            dir.mkdirs(); // 创建目录
+        }
+
+        try (FileInputStream fis = new FileInputStream(tempFilePath);
+             FileOutputStream fos = new FileOutputStream(new File(outputFile))) {
+
+            Workbook workbook = new XSSFWorkbook(fis);
+            Sheet sheet = workbook.getSheetAt(0);
+
+            int firstRowIndex = startIndex;
+            int insertedRow = 0;
+            for (int i = 0; i < noteList.size(); i++) {
+                String notes = noteList.get(i);
+                if (oConvertUtils.isNotEmpty(notes)) {
+                    int rowIndex = firstRowIndex + i + insertedRow;
+                    insertedRow++;
+                    sheet.shiftRows(rowIndex, sheet.getLastRowNum(), 1, true, true);
+                    Row newRow = sheet.createRow(rowIndex);
+                    Cell remarkCell = newRow.createCell(mergeStartColumn);
+                    remarkCell.setCellValue(notes);
+
+                    CellRangeAddress mergedRegion = new CellRangeAddress(rowIndex, rowIndex, mergeStartColumn, mergeEndColumn);
+                    CellStyle style = workbook.createCellStyle();
+                    style.setWrapText(true);
+                    Font font = workbook.createFont();
+                    font.setFontHeightInPoints((short) 10);
+                    style.setFont(font);
+                    remarkCell.setCellStyle(style);
+
+                    sheet.addMergedRegion(mergedRegion);
+                }
+            }
+
+            // 写入输出文件(自动覆盖)
+            workbook.write(fos);
+            // fos 关闭由 try-with-resources 自动处理
+            // 删除临时模板文件
+            Path tempPath = Paths.get(tempFilePath);
+            try {
+                Files.delete(tempPath);
+            } catch (Exception e) {
+                // 可选:记录日志
+            }
+
+        } catch (Exception ex) {
+            ex.printStackTrace(); // 建议不要静默吞异常
+        }
+    }
+
     /**
      * 导出excel插入注释行
      * @param tempFilePath 临时