Просмотр исходного кода

feat(app): 优化合同签署功能

- 新增 AppContractSign表及相关 mapper
- 完善合同签署流程,支持多用户签署
- 优化企业授权信息获取逻辑
- 修复合同模板创建和编辑相关问题
- 重构部分代码结构,提高可维护性
SheepHy 2 дней назад
Родитель
Сommit
9b662e3364
15 измененных файлов с 513 добавлено и 146 удалено
  1. 8 8
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/controller/ESignApi.java
  2. 24 0
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/dto/DocTemplateDTO.java
  3. 165 0
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/dto/SignFlowDTO.java
  4. 10 9
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/esign/fileAndTemplate/TemplateDemo.java
  5. 8 74
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/esign/sign/SignDemo.java
  6. 3 3
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/IESignService.java
  7. 2 1
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/impl/AppHomeServiceImpl.java
  8. 12 8
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/impl/DetailServiceImpl.java
  9. 202 34
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/impl/ESignServiceImpl.java
  10. 53 0
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/entity/AppContractSign.java
  11. 3 4
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/mapper/AppCategoryMapper.java
  12. 2 1
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/mapper/AppContractInfoMapper.java
  13. 9 0
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/mapper/AppContractSignMapper.java
  14. 2 0
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/mapper/AppCoursesMapper.java
  15. 10 4
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/mapper/xml/AppSiteMapper.xml

+ 8 - 8
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/controller/ESignApi.java

@@ -58,8 +58,8 @@ public class ESignApi {
      **/
     @GetMapping("/getOrgIdentityInfos")
     @Operation(summary = "查询企业授权状态-PC")
-    public Result<Boolean> getOrgIdentityInfos(@RequestParam("orgName") @Schema(description="企业名称")String orgName) throws EsignDemoException{
-        return Result.OK(iESignService.getOrgIdentityInfos(orgName));
+    public Result<Boolean> getOrgIdentityInfos(@RequestParam("orgCode") @Schema(description="企业编号")String orgCode) throws EsignDemoException{
+        return Result.OK(iESignService.getOrgIdentityInfos(orgCode));
     }
 
     /**
@@ -71,9 +71,9 @@ public class ESignApi {
      **/
     @GetMapping("/getOrgAuthUrls")
     @Operation(summary = "企业获取授权链接-PC")
-    public Result<String> getOrgAuthUrls(@RequestParam("orgName") @Schema(description="企业名称")String orgName,
+    public Result<String> getOrgAuthUrls(@RequestParam("orgCode") @Schema(description="企业编号")String orgCode,
                                          @RequestParam("phoneNumber") @Schema(description="联系人手机号")String phoneNumber) throws EsignDemoException{
-        return Result.OK(iESignService.getOrgAuthUrls(orgName,phoneNumber));
+        return Result.OK(iESignService.getOrgAuthUrls(orgCode,phoneNumber));
     }
 
     /**
@@ -136,9 +136,9 @@ public class ESignApi {
      * @return
      **/
     @GetMapping("/createSign")
-    @Operation(summary = "发起签署-PC")
-    public Result<String> createSign(@RequestParam("fileId") @Schema(description="文件标识")String fileId) throws EsignDemoException{
-        return Result.OK(iESignService.createSign(fileId));
+    @Operation(summary = "发起签署-APP")
+    public Result<List<String>> createSign(@RequestParam("orderCode") @Schema(description="订单编号")String orderCode) throws EsignDemoException{
+        return Result.OK(iESignService.createSign(orderCode));
     }
 
     /**
@@ -163,7 +163,7 @@ public class ESignApi {
      **/
     @GetMapping("/queryContractInfo")
     @Operation(summary = "合同列表查询-PC")
-    public Result<List<AppContractInfo>> queryContractInfo(@RequestParam("contractName") @Schema(description="合同名称")String contractName){
+    public Result<List<AppContractInfo>> queryContractInfo(@RequestParam(name = "contractName", required = false) @Schema(description="合同名称")String contractName){
         return Result.OK(iESignService.queryContractInfo(contractName));
     }
 }

+ 24 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/dto/DocTemplateDTO.java

@@ -0,0 +1,24 @@
+package org.jeecg.modules.app.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@Schema(description = "文档模板配置DTO")
+public class DocTemplateDTO {
+    @Schema(description = "文档模板名称")
+    private String docTemplateName;
+
+    @Schema(description = "文档模板类型")
+    private Integer docTemplateType;
+
+    @Schema(description = "文件ID")
+    private String fileId;
+
+    @Schema(description = "重定向URL")
+    private String redirectUrl;
+}

+ 165 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/dto/SignFlowDTO.java

@@ -0,0 +1,165 @@
+package org.jeecg.modules.app.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.util.List;
+
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@Schema(description = "电子签流程配置DTO")
+public class SignFlowDTO {
+    @Schema(description = "文档列表")
+    private List<Doc> docs;
+
+    @Schema(description = "签署流程配置")
+    private SignFlowConfig signFlowConfig;
+
+    @Schema(description = "签署方列表")
+    private List<Signer> signers;
+
+    // 内部类 - 文档信息
+    @Data
+    @Accessors(chain = true)
+    @Schema(description = "文档信息")
+    public static class Doc {
+        @Schema(description = "文件ID")
+        private String fileId;
+
+        @Schema(description = "文件名称")
+        private String fileName;
+    }
+
+    // 内部类 - 签署流程配置
+    @Data
+    @Accessors(chain = true)
+    @Schema(description = "签署流程配置")
+    public static class SignFlowConfig {
+        @Schema(description = "流程标题")
+        private String signFlowTitle;
+
+        @Schema(description = "流程过期时间")
+        private Long signFlowExpireTime;
+
+        @Schema(description = "是否自动完成")
+        private Boolean autoFinish;
+
+        @Schema(description = "回调通知地址")
+        private String notifyUrl;
+
+        @Schema(description = "重定向配置")
+        private RedirectConfig redirectConfig;
+    }
+
+    // 内部类 - 重定向配置
+    @Data
+    @Accessors(chain = true)
+    @Schema(description = "重定向配置")
+    public static class RedirectConfig {
+        @Schema(description = "重定向URL")
+        private String redirectUrl;
+    }
+
+    // 内部类 - 签署方信息
+    @Data
+    @Accessors(chain = true)
+    @Schema(description = "签署方信息")
+    public static class Signer {
+
+        @Schema(description = "签署方类型 0-个人 1-企业")
+        private Integer signerType;
+
+        @Schema(description = "个人签署方信息")
+        private PsnSignerInfo psnSignerInfo;
+
+        @Schema(description = "签署字段列表")
+        private List<SignField> signFields;
+    }
+
+    // 内部类 - 签署配置
+    @Data
+    @Accessors(chain = true)
+    @Schema(description = "签署配置")
+    public static class SignConfig {
+        @Schema(description = "签署顺序")
+        private Integer signOrder;
+    }
+
+    // 内部类 - 通知配置
+    @Data
+    @Accessors(chain = true)
+    @Schema(description = "通知配置")
+    public static class NoticeConfig {
+        @Schema(description = "通知类型集合")
+        private String noticeTypes;
+    }
+
+    // 内部类 - 个人签署方信息
+    @Data
+    @Accessors(chain = true)
+    @Schema(description = "个人签署方信息")
+    public static class PsnSignerInfo {
+        @Schema(description = "签署方账号")
+        private String psnAccount;
+
+        @Schema(description = "签署方信息")
+        private PsnInfo psnInfo;
+    }
+
+    // 内部类 - 签署方信息
+    @Data
+    @Accessors(chain = true)
+    @Schema(description = "签署方信息")
+    public static class PsnInfo {
+        @Schema(description = "签署方姓名")
+        private String psnName;
+    }
+
+    // 内部类 - 签署字段
+    @Data
+    @Accessors(chain = true)
+    @Schema(description = "签署字段配置")
+    public static class SignField {
+        @Schema(description = "自定义业务编号")
+        private String customBizNum;
+
+        @Schema(description = "文件ID")
+        private String fileId;
+
+        @Schema(description = "普通签署字段配置")
+        private NormalSignFieldConfig normalSignFieldConfig;
+    }
+
+    // 内部类 - 普通签署字段配置
+    @Data
+    @Accessors(chain = true)
+    @Schema(description = "普通签署字段配置")
+    public static class NormalSignFieldConfig {
+        @Schema(description = "是否自动签署")
+        private Boolean autoSign = true;
+
+        @Schema(description = "签署字段样式")
+        private Integer signFieldStyle;
+
+        @Schema(description = "签署位置信息")
+        private List<SignFieldPosition> signFieldPosition;
+    }
+
+    // 内部类 - 签署位置信息
+    @Data
+    @Accessors(chain = true)
+    @Schema(description = "签署位置信息")
+    public static class SignFieldPosition {
+        @Schema(description = "页码位置")
+        private String positionPage;
+
+        @Schema(description = "X坐标位置")
+        private Integer positionX;
+
+        @Schema(description = "Y坐标位置")
+        private Integer positionY;
+    }
+}

+ 10 - 9
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/esign/fileAndTemplate/TemplateDemo.java

@@ -2,6 +2,7 @@ package org.jeecg.modules.app.esign.fileAndTemplate;
 
 import com.google.gson.Gson;
 import com.google.gson.JsonObject;
+import org.jeecg.modules.app.dto.DocTemplateDTO;
 import org.jeecg.modules.app.esign.comm.EsignHttpHelper;
 import org.jeecg.modules.app.esign.comm.EsignHttpResponse;
 import org.jeecg.modules.app.esign.constant.EsignDemoConfig;
@@ -32,10 +33,10 @@ public class TemplateDemo extends Exception {
 //		System.err.println("合同模板id:"+docTemplateId);
 
 		/* 获取编辑合同模板页面*/
-		EsignHttpResponse getTemplateEditUrl = getTemplateEditUrl();
-		JsonObject getTemplateEditUrlObject = gson.fromJson(getTemplateEditUrl.getBody(), JsonObject.class);
-		String docTemplateEditUrl = getTemplateEditUrlObject.getAsJsonObject("data").get("docTemplateEditUrl").getAsString();
-		System.err.println("编辑合同模板的页面链接:"+docTemplateEditUrl);
+//		EsignHttpResponse getTemplateEditUrl = getTemplateEditUrl();
+//		JsonObject getTemplateEditUrlObject = gson.fromJson(getTemplateEditUrl.getBody(), JsonObject.class);
+//		String docTemplateEditUrl = getTemplateEditUrlObject.getAsJsonObject("data").get("docTemplateEditUrl").getAsString();
+//		System.err.println("编辑合同模板的页面链接:"+docTemplateEditUrl);
 
 		/* 查询合同模板中控件详情*/
 		EsignHttpResponse getComponentsInfo = getComponentsInfo();
@@ -61,10 +62,11 @@ public class TemplateDemo extends Exception {
 	 * @return
 	 * @throws EsignDemoException
 	 */
-	public static EsignHttpResponse getTemplateCreateUrl(String fileId) throws EsignDemoException {
+	public static EsignHttpResponse getTemplateCreateUrl(DocTemplateDTO docTemplateDTO) throws EsignDemoException {
 		String apiaddr="/v3/doc-templates/doc-template-create-url";
 		//请求参数body体,json格式。get或者delete请求时jsonString传空json:"{}"或者null
-		String jsonParm="{\"docTemplateName\":\"测试模板\",\"docTemplateType\":0,\"fileId\":\"b3f01axxxxxx05d320da35\",\"redirectUrl\":\"https://www.esign.cn\"}";
+		Gson gson = new Gson();
+		String jsonParm = gson.toJson(docTemplateDTO);
 
 		//请求方法
 		EsignRequestType requestType= EsignRequestType.POST;
@@ -78,11 +80,10 @@ public class TemplateDemo extends Exception {
 	 * @return
 	 * @throws EsignDemoException
 	 */
-	public static EsignHttpResponse getTemplateEditUrl() throws EsignDemoException {
-		String docTemplateId="a6f7e3b4e7xxxxxxxedc6fc89";
+	public static EsignHttpResponse getTemplateEditUrl(String docTemplateId,String redirectUrl) throws EsignDemoException {
 		String apiaddr="/v3/doc-templates/"+docTemplateId+"/doc-template-edit-url";
 		//请求参数body体,json格式。get或者delete请求时jsonString传空json:"{}"或者null
-		String jsonParm="{\"redirectUrl\":\"https://www.esign.cn\"}";
+		String jsonParm="{\"redirectUrl\":"+redirectUrl+"}";
 
 		//请求方法
 		EsignRequestType requestType= EsignRequestType.POST;

+ 8 - 74
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/esign/sign/SignDemo.java

@@ -2,6 +2,7 @@ package org.jeecg.modules.app.esign.sign;
 
 import com.google.gson.Gson;
 import com.google.gson.JsonObject;
+import org.jeecg.modules.app.dto.SignFlowDTO;
 import org.jeecg.modules.app.esign.comm.EsignHttpHelper;
 import org.jeecg.modules.app.esign.comm.EsignHttpResponse;
 import org.jeecg.modules.app.esign.constant.EsignDemoConfig;
@@ -21,12 +22,12 @@ public class SignDemo {
     public static void main(String[] args) throws EsignDemoException {
         Gson gson = new Gson();
         /* 发起签署*/
-        EsignHttpResponse createByFile = createByFile();
+//        EsignHttpResponse createByFile = createByFile();
         //JSONObject getPsnAuthUrlObject = JSONObject.parseObject(getPsnAuthUrl.getBody());
-        JsonObject createByFileJsonObject = gson.fromJson(createByFile.getBody(), JsonObject.class);
-        JsonObject createByFileData = createByFileJsonObject.getAsJsonObject("data");
-        String authUrl = createByFileData.get("signFlowId").getAsString();
-        System.err.println("流程id:"+signFlowId);
+//        JsonObject createByFileJsonObject = gson.fromJson(createByFile.getBody(), JsonObject.class);
+//        JsonObject createByFileData = createByFileJsonObject.getAsJsonObject("data");
+//        String authUrl = createByFileData.get("signFlowId").getAsString();
+//        System.err.println("流程id:"+signFlowId);
 
         //获取合同文件签署链接
         EsignHttpResponse signUrl = signUrl(signFlowId);
@@ -641,77 +642,10 @@ public class SignDemo {
      * @return
      * @throws EsignDemoException
      */
-    public static EsignHttpResponse createByFile() throws EsignDemoException {
+    public static EsignHttpResponse createByFile(SignFlowDTO dto) throws EsignDemoException {
         String apiaddr = "/v3/sign-flow/create-by-file";
         //请求参数body体,json格式。get或者delete请求时jsonString传空json:"{}"或者null
-        String jsonParm = "{\n" +
-                "    \"docs\": [\n" +
-                "        {\n" +
-                "            \"fileId\": \"c3c22a9***********fa9c482\",\n" +
-                "            \"fileName\": \"1234.pdf\"\n" +
-                "        }\n" +
-                "    ],\n" +
-                "    \"signFlowConfig\": {\n" +
-                "        \"signFlowTitle\": \"测试合同\",\n" +
-                "        \"chargeConfig\": {\n" +
-                "            \"chargeMode\": 0\n" +
-                "        }\n" +
-                "    },\n" +
-                "    \"signers\": [\n" +
-                "        {\n" +
-                "            \"noticeConfig\": {\n" +
-                "                \"noticeTypes\": \"1\"\n" +
-                "            },\n" +
-                "            \"orgSignerInfo\": {\n" +
-                "                \"orgId\": \"\",\n" +
-                "                \"orgInfo\": {\n" +
-                "                    \"legalRepIDCardNum\": \"\",\n" +
-                "                    \"legalRepIDCardType\": \"\",\n" +
-                "                    \"legalRepName\": \"孙xx\",\n" +
-                "                    \"orgIDCardNum\": \"915******52355\",\n" +
-                "                    \"orgIDCardType\": \"CRED_ORG_USCC\"\n" +
-                "                },\n" +
-                "                \"orgName\": \"**科技信息有限公司\",\n" +
-                "                \"transactorInfo\": {\n" +
-                "                    \"psnAccount\": \"18********79\",\n" +
-                "                    \"psnId\": \"\",\n" +
-                "                    \"psnInfo\": {\n" +
-                "                        \"bankCardNum\": \"\",\n" +
-                "                        \"psnIDCardNum\": \"\",\n" +
-                "                        \"psnIDCardType\": \"\",\n" +
-                "                        \"psnName\": \"\"\n" +
-                "                    }\n" +
-                "                }\n" +
-                "            },\n" +
-                "            \"signConfig\": {\n" +
-                "                \"signOrder\": 1\n" +
-                "            },\n" +
-                "            \"signFields\": [\n" +
-                "                {\n" +
-                "                    \"customBizNum\": \"62453252523\",\n" +
-                "                    \"fileId\": \"c3c22a9***********87cfa9c482\",\n" +
-                "                    \"normalSignFieldConfig\": {\n" +
-                "                        \"assignedSealId\": \"\",\n" +
-                "                        \"autoSign\": false,\n" +
-                "                        \"freeMode\": true,\n" +
-                "                        \"movableSignField\": true,\n" +
-                "                        \"orgSealBizTypes\": \"\",\n" +
-                "                        \"psnSealStyles\": \"\",\n" +
-                "                        \"signFieldPosition\": {\n" +
-                "                            \"positionPage\": \"1\",\n" +
-                "                            \"positionX\": 120,\n" +
-                "                            \"positionY\": 460\n" +
-                "                        },\n" +
-                "                        \"signFieldStyle\": 1\n" +
-                "                    },\n" +
-                "                    \"signFieldType\": 0\n" +
-                "                }\n" +
-                "            ],\n" +
-                "            \"signerType\": 1\n" +
-                "        }\n" +
-                "    ]\n" +
-                "}";
-
+        String jsonParm = dto.toString();
         //请求方法
         EsignRequestType requestType = EsignRequestType.POST;
         //生成请求签名鉴权方式的Header

+ 3 - 3
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/IESignService.java

@@ -34,7 +34,7 @@ public interface IESignService {
      * @Param
      * @return
      **/
-    boolean getOrgIdentityInfos(String orgName) throws EsignDemoException;
+    boolean getOrgIdentityInfos(String orgCode) throws EsignDemoException;
 
     /**
      * @Author SheepHy
@@ -43,7 +43,7 @@ public interface IESignService {
      * @Param
      * @return
      **/
-    String getOrgAuthUrls(String orgName,String phoneNumber) throws EsignDemoException;
+    String getOrgAuthUrls(String orgCode,String phoneNumber) throws EsignDemoException;
 
     /**
      * @Author SheepHy
@@ -62,7 +62,7 @@ public interface IESignService {
      * @Param
      * @return
      **/
-    String createSign(String fileId) throws EsignDemoException;
+    List<String> createSign(String fileId) throws EsignDemoException;
 
     /**
      * @Author SheepHy

+ 2 - 1
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/impl/AppHomeServiceImpl.java

@@ -249,7 +249,8 @@ public class AppHomeServiceImpl implements IAppHomeService {
         searchPlaceVOPage.getRecords().forEach(placeVO -> {
             AppSite appSite = appSiteMapper.selectById(placeVO.getId());
             placeVO.setKm(PositionUtil.calculateDistance(searchDTO.getLatitude(), searchDTO.getLongitude(), appSite.getLatitude().doubleValue(), appSite.getLongitude().doubleValue()))
-                    .setCategory(getCategoryName(placeVO.getCategoryId()));
+                    .setCategory(getCategoryName(placeVO.getCategoryId())).setCover(placeVO.getCover().split(",")[0]);
+
         });
         if(searchDTO.getVenueType().equals("0-2")
                 || searchDTO.getVenueType().equals("1-1")

+ 12 - 8
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/impl/DetailServiceImpl.java

@@ -32,10 +32,7 @@ import javax.annotation.Resource;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.ZoneId;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.List;
+import java.util.*;
 
 import static org.jeecg.modules.system.constant.DefIndexConst.FACILITY_INFO;
 
@@ -181,12 +178,19 @@ public class DetailServiceImpl implements IDetailService {
                 .eq(AppSitePlace::getStatus, 0)
                 .eq(AppSitePlace::getDelFlag, 0)
                 .last("LIMIT 1"));
-        List<PlaceInfoVO.theGymnasiumIsCharteredInfoVO> collect = appSitePriceRulesMapper.theGymnasiumIsCharteredInfo(appSitePlace.getOrgCode(), categoryId);
-        return new PlaceInfoVO.theGymnasiumIsCharteredVO()
+        List<PlaceInfoVO.theGymnasiumIsCharteredInfoVO> collect = new ArrayList<>();
+        PlaceInfoVO.theGymnasiumIsCharteredVO theGymnasiumIsCharteredVO = new PlaceInfoVO.theGymnasiumIsCharteredVO()
                 .setCategory(getCategoryName(categoryId))
-                .setEarlyRefundTime(appSitePlace.getEarlyRefundTime())
-                .setVr(appSiteMapper.selectById(id).getVr())
                 .setTimeSlot(collect);
+        if(appSitePlace != null){
+            collect = appSitePriceRulesMapper.theGymnasiumIsCharteredInfo(appSitePlace.getOrgCode(), categoryId);
+            theGymnasiumIsCharteredVO.setEarlyRefundTime(Optional.ofNullable(appSitePlace.getEarlyRefundTime()).orElse(0));
+
+        }
+        if(!collect.isEmpty()){
+            theGymnasiumIsCharteredVO.setVr(appSiteMapper.selectById(id).getVr());
+        }
+        return theGymnasiumIsCharteredVO;
     }
 
     @Override

+ 202 - 34
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/impl/ESignServiceImpl.java

@@ -10,7 +10,9 @@ import lombok.extern.log4j.Log4j2;
 import org.apache.shiro.SecurityUtils;
 import org.jeecg.common.exception.JeecgBootException;
 import org.jeecg.common.system.vo.LoginUser;
+import org.jeecg.modules.app.dto.DocTemplateDTO;
 import org.jeecg.modules.app.dto.GetPsnAuthUrlDTO;
+import org.jeecg.modules.app.dto.SignFlowDTO;
 import org.jeecg.modules.app.esign.comm.EsignHttpResponse;
 import org.jeecg.modules.app.esign.exception.EsignDemoException;
 import org.jeecg.modules.app.esign.fileAndTemplate.FileDemo;
@@ -18,16 +20,28 @@ import org.jeecg.modules.app.esign.sign.SignDemo;
 import org.jeecg.modules.app.service.IESignService;
 import org.jeecg.modules.system.app.dto.AppContractInfoDTO;
 import org.jeecg.modules.system.app.entity.AppContractInfo;
+import org.jeecg.modules.system.app.entity.AppContractSign;
+import org.jeecg.modules.system.app.entity.AppOrder;
+import org.jeecg.modules.system.app.entity.FamilyMembers;
 import org.jeecg.modules.system.app.mapper.AppContractInfoMapper;
+import org.jeecg.modules.system.app.mapper.AppContractSignMapper;
+import org.jeecg.modules.system.app.mapper.AppOrderMapper;
+import org.jeecg.modules.system.app.mapper.FamilyMembersMapper;
+import org.jeecg.modules.system.entity.SysDepart;
 import org.jeecg.modules.system.entity.SysUser;
+import org.jeecg.modules.system.mapper.SysDepartMapper;
 import org.jeecg.modules.system.mapper.SysUserMapper;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
+import java.util.*;
 
 import static com.alibaba.dashscope.utils.JsonUtils.gson;
 import static org.jeecg.modules.app.esign.auth.ESignAuth.*;
@@ -42,6 +56,14 @@ public class ESignServiceImpl implements IESignService {
     private SysUserMapper sysUserMapper;
     @Resource
     private AppContractInfoMapper appAccountMapper;
+    @Resource
+    private SysDepartMapper sysDepartMapper;
+    @Resource
+    private AppOrderMapper orderMapper;
+    @Resource
+    private AppContractSignMapper appContractSignMapper;
+    @Resource
+    private FamilyMembersMapper familyMembersMapper;
     @Override
     public boolean getUserIdentityInfo(String phoneNumber) throws EsignDemoException {
         EsignHttpResponse getPsnIdentityInfo = getPsnIdentityInfo(phoneNumber);
@@ -65,16 +87,25 @@ public class ESignServiceImpl implements IESignService {
     }
 
     @Override
-    public boolean getOrgIdentityInfos(String orgName) throws EsignDemoException {
-        EsignHttpResponse getOrgIdentityInfo = getOrgIdentityInfo(orgName);
+    public boolean getOrgIdentityInfos(String orgCode) throws EsignDemoException {
+        SysDepart sysDepart = sysDepartMapper.selectOne(Wrappers.<SysDepart>lambdaQuery().eq(SysDepart::getOrgCode, orgCode));
+        EsignHttpResponse getOrgIdentityInfo = getOrgIdentityInfo(sysDepart.getDepartName());
         JsonObject getOrgIdentityInfoObject = gson.fromJson(getOrgIdentityInfo.getBody(), JsonObject.class);
-        String orgRealnameStatus =	getOrgIdentityInfoObject.getAsJsonObject("data").get("realnameStatus").getAsString();//授权状态authorizeUserInfo
+        JsonElement dataElement = getOrgIdentityInfoObject.get("data");
+        if (dataElement == null || !dataElement.isJsonObject()) {
+            // 记录原始响应内容便于排查
+            log.error("data字段解析失败,原始响应:{}", getOrgIdentityInfo.getBody());
+            throw new JeecgBootException("未查询到授权信息");
+        }
+        JsonObject dataObj = dataElement.getAsJsonObject();
+        String orgRealnameStatus = dataObj.get("realnameStatus").getAsString();
         return orgRealnameStatus.equals("1");
     }
 
     @Override
-    public String getOrgAuthUrls(String orgName,String phoneNumber) throws EsignDemoException {
-        EsignHttpResponse getOrgAuthUrl = getOrgAuthUrl(orgName,phoneNumber);
+    public String getOrgAuthUrls(String orgCode,String phoneNumber) throws EsignDemoException {
+        SysDepart sysDepart = sysDepartMapper.selectOne(Wrappers.<SysDepart>lambdaQuery().eq(SysDepart::getOrgCode, orgCode));
+        EsignHttpResponse getOrgAuthUrl = getOrgAuthUrl(sysDepart.getDepartName(),phoneNumber);
         JsonObject getOrgAuthUrlObject = gson.fromJson(getOrgAuthUrl.getBody(), JsonObject.class);
         return getOrgAuthUrlObject.getAsJsonObject("data").get("authUrl").getAsString();
     }
@@ -82,35 +113,122 @@ public class ESignServiceImpl implements IESignService {
     @Override
     public boolean uploadContractTemplate(AppContractInfoDTO appContractInfoDTO) throws EsignDemoException {
         LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
-        EsignHttpResponse getUploadUrl = FileDemo.getUploadUrl(appContractInfoDTO.getFilePath());
+        String remoteUrl = "http://127.0.0.1:8080/jeecg-boot/sys/common/static/" + appContractInfoDTO.getFilePath();
+        String fileType = getFileExtension(appContractInfoDTO.getFilePath());
+        if (fileType.isEmpty()) {
+            throw new JeecgBootException("未指定文件类型");
+        }
+        EsignHttpResponse getUploadUrl = FileDemo.getUploadUrl(remoteUrl);
         JsonObject getUploadUrlJsonObject = gson.fromJson(getUploadUrl.getBody(), JsonObject.class);
         JsonObject data = getUploadUrlJsonObject.getAsJsonObject("data");
+        //文件id后续发起签署使用
+        String fileId =data.get("fileId").getAsString();
         String fileUploadUrl =data.get("fileUploadUrl").getAsString();
-        EsignHttpResponse uploadFileResponse = FileDemo.uploadFile(fileUploadUrl,appContractInfoDTO.getFilePath());
+        System.out.println("获取文件id以及文件上传地址成功,文件id:"+fileId);
+        System.out.println("上传链接:"+fileUploadUrl);
+        EsignHttpResponse uploadFileResponse = FileDemo.uploadFile(fileUploadUrl,remoteUrl);
         JsonObject uploadFileResponseJsonObject = gson.fromJson(uploadFileResponse.getBody(), JsonObject.class);
         int errCode = uploadFileResponseJsonObject.get("errCode").getAsInt();
-        String fileId =data.get("fileId").getAsString();
-        appAccountMapper.insert(new AppContractInfo()
-                .setOrgCode(user.getOrgCode())
-                .setFileId(fileId)
-                .setContractName(appContractInfoDTO.getContractName())
-                .setRemark(appContractInfoDTO.getRemark())
-                .setCreateBy(user.getId())
-                .setCreateTime(new java.util.Date())
-                .setUpdateTime(new java.util.Date())
-                .setUpdateBy(user.getId()));
-        return errCode == 0;
+        System.out.println("文件上传成功,状态码:"+errCode);
+        if (errCode == 0) {
+            appAccountMapper.delete(Wrappers.<AppContractInfo>lambdaQuery()
+                    .eq(AppContractInfo::getOrgCode, user.getOrgCode()));
+            appAccountMapper.insert(new AppContractInfo()
+                    .setOrgCode(user.getOrgCode())
+                    .setFileId(fileId)
+                    .setContractName(appContractInfoDTO.getContractName())
+                    .setRemark(appContractInfoDTO.getRemark())
+                    .setCreateBy(user.getId())
+                    .setCreateTime(new Date())
+                    .setUpdateTime(new Date())
+                    .setUpdateBy(user.getId())
+                    .setContractType(fileType)); // 新增文件类型字段
+            return true;
+        }
+        return false;
     }
 
     @Override
-    public String createSign(String fileId) throws EsignDemoException {
-        EsignHttpResponse createByFile = createByFile();
-        JSONObject createByFileJsonObject = JSONObject.parseObject(createByFile.getBody());
-        String signFlowId = createByFileJsonObject.getJSONObject("data").getString("signFlowId");
-        System.out.println("signFlowId:" + signFlowId);
-        return signFlowId;
+    @Transactional
+    public List<String> createSign(String orderCode) throws EsignDemoException {
+        List<String> signFlowIds = new ArrayList<>();
+        //todo
+        AppOrder appOrder = orderMapper.selectOne(Wrappers.<AppOrder>lambdaQuery().eq(AppOrder::getOrderCode, orderCode));
+        List<String> familyIds = List.of(appOrder.getFamilyIds().split(","));
+        AppContractInfo appContractInfo = appAccountMapper.selectById(appOrder.getContractNo());
+        familyIds.forEach(familyId -> {
+            String generate32BitUUID = generate32BitUUID();
+            FamilyMembers familyMembers = familyMembersMapper.selectById(familyId);
+            EsignHttpResponse createByFile = null;
+            try {
+                SignFlowDTO dto = new SignFlowDTO();
+                dto.setDocs(Arrays.asList(
+                        new SignFlowDTO.Doc().setFileId(appContractInfo.getFileId()).setFileName(appContractInfo.getContractName())
+                ));
+                dto.setSignFlowConfig(new SignFlowDTO.SignFlowConfig()
+                        .setSignFlowTitle(appContractInfo.getContractName())
+                        .setSignFlowExpireTime(System.currentTimeMillis() + 86400000L)
+                        .setAutoFinish(true)
+                        .setNotifyUrl("http://example.com/notify")
+                        .setRedirectConfig(new SignFlowDTO.RedirectConfig().setRedirectUrl(appContractInfo.getRedirectUrl())));
+                List<SignFlowDTO.Signer> signers = new  ArrayList<>();
+                //个人用户
+                SignFlowDTO.Signer signer1 = new SignFlowDTO.Signer()
+                        .setSignerType(0)
+                        .setPsnSignerInfo(new SignFlowDTO.PsnSignerInfo()
+                                .setPsnAccount(familyMembers.getPhone())
+                                .setPsnInfo(new SignFlowDTO.PsnInfo().setPsnName(familyMembers.getFullName())))
+                        .setSignFields(Collections.singletonList(
+                                new SignFlowDTO.SignField()
+                                        .setCustomBizNum(generate32BitUUID)
+                                        .setFileId(appContractInfo.getFileId())
+                                        .setNormalSignFieldConfig(new SignFlowDTO.NormalSignFieldConfig()
+                                                .setAutoSign(false)
+                                                .setSignFieldStyle(1)
+                                                .setSignFieldPosition(Collections.singletonList(new SignFlowDTO.SignFieldPosition()
+                                                        .setPositionPage("1")
+                                                        .setPositionX(100)
+                                                        .setPositionY(200))))));
+//                //企业用户
+//                SignFlowDTO.Signer signer2 = new SignFlowDTO.Signer()
+//                        .setSignerType(1)
+//                        .setSignFields(Collections.singletonList(
+//                                new SignFlowDTO.SignField()
+//                                        .setCustomBizNum(generate32BitUUID)
+//                                        .setFileId(appContractInfo.getFileId())
+//                                        .setNormalSignFieldConfig(new SignFlowDTO.NormalSignFieldConfig()
+//                                                .setAutoSign(false)
+//                                                .setSignFieldStyle(1)
+//                                                .setSignFieldPosition(Collections.singletonList(new SignFlowDTO.SignFieldPosition()
+//                                                        .setPositionPage("1")
+//                                                        .setPositionX(100)
+//                                                        .setPositionY(200))))));
+                signers.add(signer1);
+//                signers.add(signer2);
+                dto.setSigners(signers);
+                createByFile = createByFile(dto);
+            } catch (EsignDemoException e) {
+                throw new RuntimeException(e);
+            }
+            JSONObject createByFileJsonObject = JSONObject.parseObject(createByFile.getBody());
+            String signFlowId = createByFileJsonObject.getJSONObject("data").getString("signFlowId");
+            System.out.println("signFlowId:" + signFlowId);
+            signFlowIds.add(signFlowId);
+            appContractSignMapper.insert(new AppContractSign().setId(generate32BitUUID)
+                    .setSignFlowId(signFlowId)
+                    .setOrderId(appOrder.getId())
+                    .setOrgCode(appOrder.getOrgCode())
+                    .setCreateTime(new Date())
+                    .setUpdateTime(new Date()));
+        });
+        return signFlowIds;
+    }
+    public static String generate32BitUUID() {
+        // 生成标准 UUID(128 位)
+        UUID uuid = UUID.randomUUID();
+        // 去除连字符,得到 32 位字符串
+        return uuid.toString().replace("-", "");
     }
-
     @Override
     public String getSignUrl(String signFlowId) throws EsignDemoException {
         JSONObject signUrl = JSONObject.parseObject(SignDemo.signUrl(signFlowId).getBody());
@@ -119,16 +237,20 @@ public class ESignServiceImpl implements IESignService {
 
     @Override
     public String createTemplate(String fileId) throws EsignDemoException {
+        AppContractInfo appContractInfo = appAccountMapper.selectOne(Wrappers.<AppContractInfo>lambdaQuery().eq(AppContractInfo::getFileId, fileId));
+        DocTemplateDTO docTemplateDTO = new DocTemplateDTO()
+                .setDocTemplateName(appContractInfo.getContractName())
+                .setDocTemplateType(0)
+                .setFileId(fileId)
+                .setRedirectUrl(appContractInfo.getRedirectUrl());
         /* 获取制作合同模板页面*/
-        EsignHttpResponse getTemplateCreateUrl = getTemplateCreateUrl(fileId);
+        EsignHttpResponse getTemplateCreateUrl = getTemplateCreateUrl(docTemplateDTO);
         Gson gson = new Gson();
         JsonObject getTemplateCreateUrlObject = gson.fromJson(getTemplateCreateUrl.getBody(), JsonObject.class);
-
         String docTemplateCreateUrl = getTemplateCreateUrlObject.getAsJsonObject("data").get("docTemplateCreateUrl").getAsString();
         String docTemplateId = getTemplateCreateUrlObject.getAsJsonObject("data").get("docTemplateId").getAsString();
         System.err.println("制作合同模板的页面链接:"+docTemplateCreateUrl);
         System.err.println("合同模板id:"+docTemplateId);
-        AppContractInfo appContractInfo = appAccountMapper.selectOne(Wrappers.<AppContractInfo>lambdaQuery().eq(AppContractInfo::getFileId, fileId));
         appContractInfo.setDocTemplateId(docTemplateId);
         appAccountMapper.updateById(appContractInfo);
         return docTemplateCreateUrl;
@@ -136,8 +258,9 @@ public class ESignServiceImpl implements IESignService {
 
     @Override
     public String editContract(String docTemplateId) throws EsignDemoException {
+        AppContractInfo appContractInfo = appAccountMapper.selectOne(Wrappers.<AppContractInfo>lambdaQuery().eq(AppContractInfo::getDocTemplateId, docTemplateId));
         /* 获取编辑合同模板页面*/
-        EsignHttpResponse getTemplateEditUrl = getTemplateEditUrl();
+        EsignHttpResponse getTemplateEditUrl = getTemplateEditUrl(docTemplateId,appContractInfo.getRedirectUrl());
         JsonObject getTemplateEditUrlObject = gson.fromJson(getTemplateEditUrl.getBody(), JsonObject.class);
         String docTemplateEditUrl = getTemplateEditUrlObject.getAsJsonObject("data").get("docTemplateEditUrl").getAsString();
         System.err.println("编辑合同模板的页面链接:"+docTemplateEditUrl);
@@ -163,7 +286,52 @@ public class ESignServiceImpl implements IESignService {
 
     @Override
     public List<AppContractInfo> queryContractInfo(String contractName) {
-        return appAccountMapper.selectList(Wrappers.<AppContractInfo>lambdaQuery().like(AppContractInfo::getContractName,contractName));
+        LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+        if(null != contractName){
+            return appAccountMapper.selectList(Wrappers.<AppContractInfo>lambdaQuery()
+                    .like(AppContractInfo::getContractName,contractName).like(AppContractInfo::getOrgCode,user.getOrgCode()));
+        }else {
+            return appAccountMapper.selectList(Wrappers.<AppContractInfo>lambdaQuery().like(AppContractInfo::getOrgCode,user.getOrgCode()));
+        }
+    }
+
+    /**
+     * 获取文件扩展名
+     */
+    private String getFileExtension(String filename) {
+        if (filename == null || !filename.contains(".")) {
+            return "";
+        }
+        return filename.substring(filename.lastIndexOf(".") + 1).toLowerCase();
+    }
+
+    /**
+     * 下载远程文件
+     */
+    private File downloadRemoteFile(String fileUrl) throws IOException {
+        URL url = new URL(fileUrl);
+        File tempFile = File.createTempFile("esign-", ".tmp");
+        tempFile.deleteOnExit();
+
+        try (InputStream in = url.openStream()) {
+            Files.copy(in, tempFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
+        }
+
+        return tempFile;
+    }
+
+    /**
+     * 获取MIME类型映射
+     */
+    private String getMimeType(String ext) {
+        Map<String, String> mimeMap = new HashMap<>();
+        mimeMap.put("pdf", "application/pdf");
+        mimeMap.put("doc", "application/msword");
+        mimeMap.put("docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
+        mimeMap.put("xls", "application/vnd.ms-excel");
+        mimeMap.put("xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
+
+        return mimeMap.getOrDefault(ext, "application/octet-stream");
     }
 }
 

+ 53 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/entity/AppContractSign.java

@@ -0,0 +1,53 @@
+package org.jeecg.modules.system.app.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.jeecgframework.poi.excel.annotation.Excel;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.Date;
+
+@Data
+@TableName("nm_contract_sign")
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@Schema(description="合同签署表")
+public class AppContractSign {
+    /**id*/
+    @TableId(type = IdType.ASSIGN_ID)
+    @Schema(description = "id")
+    private String id;
+    @Schema(description = "订单ID")
+    private String orderId;
+    @Schema(description = "E签宝signFlowId")
+    private String signFlowId;
+    @Schema(description = "orgCode")
+    private String orgCode;
+    @Schema(description = "是否签署 0、未签 1、已签")
+    private int isSign;
+    @Schema(description = "使用人ID")
+    private String familyId;
+    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    @Schema(description = "签字时间;签字时间")
+    private Date signTime;
+    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    @Schema(description = "创建时间;创建时间")
+    private Date createTime;
+    @Excel(name = "删除标志;删除状态(0-正常,1-已删除)", width = 15)
+    @Schema(description = "删除标志;删除状态(0-正常,1-已删除)")
+    @TableLogic
+    private Integer delFlag;
+    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    @Schema(description = "更新时间;更新时间")
+    private Date updateTime;
+}

+ 3 - 4
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/mapper/AppCategoryMapper.java

@@ -1,10 +1,8 @@
 package org.jeecg.modules.system.app.mapper;
 
-import java.util.List;
-
-import org.apache.ibatis.annotations.Param;
-import org.jeecg.modules.system.app.entity.AppCategory;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.jeecg.modules.system.app.entity.AppCategory;
 
 /**
  * @Description: 运动类型表
@@ -12,6 +10,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  * @Date:   2025-07-03
  * @Version: V1.0
  */
+@Mapper
 public interface AppCategoryMapper extends BaseMapper<AppCategory> {
 
 }

+ 2 - 1
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/mapper/AppContractInfoMapper.java

@@ -1,7 +1,8 @@
 package org.jeecg.modules.system.app.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
 import org.jeecg.modules.system.app.entity.AppContractInfo;
-
+@Mapper
 public interface AppContractInfoMapper extends BaseMapper<AppContractInfo> {
 }

+ 9 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/mapper/AppContractSignMapper.java

@@ -0,0 +1,9 @@
+package org.jeecg.modules.system.app.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.jeecg.modules.system.app.entity.AppContractSign;
+
+@Mapper
+public interface AppContractSignMapper extends BaseMapper<AppContractSign> {
+}

+ 2 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/mapper/AppCoursesMapper.java

@@ -3,6 +3,7 @@ package org.jeecg.modules.system.app.mapper;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 import org.jeecg.modules.app.dto.SearchDTO;
 import org.jeecg.modules.app.vo.CourseInfoVO;
@@ -19,6 +20,7 @@ import org.jeecg.modules.system.app.entity.AppCourses;
  * @Date:   2025-07-03
  * @Version: V1.0
  */
+@Mapper
 public interface AppCoursesMapper extends BaseMapper<AppCourses> {
     /**
      * @Author SheepHy

+ 10 - 4
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/mapper/xml/AppSiteMapper.xml

@@ -16,7 +16,7 @@
         nm_site_place a
         LEFT JOIN nm_site b ON a.site_id = b.id
         LEFT JOIN sys_depart c ON b.tenant_id = c.id
-        WHERE 1 = 1
+        WHERE 1 = 1 AND a.del_flag = 0
         <if test="venueType != null and venueType == '0-1'">
             ORDER BY b.good_rate DESC
         </if>
@@ -45,13 +45,19 @@
         a.type,
         CASE
         WHEN EXISTS (
-        SELECT SUM(inventory)
+        SELECT 1
         FROM nm_site_price_rules e
-        WHERE e.site_place_id = a.id
+        WHERE e.org_code = a.org_code AND e.inventory > 0
         ) THEN 1
         ELSE 0
         END AS ticketWhether
-        FROM nm_site a LEFT JOIN sys_depart b ON a.tenant_id = b.id WHERE 1=1
+        FROM nm_site a
+        LEFT JOIN sys_depart b ON a.tenant_id = b.id
+        WHERE EXISTS (
+        SELECT 1
+        FROM nm_site_price_rules e
+        WHERE e.org_code = a.org_code
+        ) AND 1=1
         <if test="searchDTO.keyword != null and searchDTO.keyword != ''">
             AND (a.name LIKE CONCAT('%',#{searchDTO.keyword},'%') OR a.address LIKE CONCAT('%',#{searchDTO.keyword},'%'))
         </if>