wangxy 2 dní pred
rodič
commit
4727c0bf0a
23 zmenil súbory, kde vykonal 1160 pridanie a 8 odobranie
  1. 93 0
      fs-admin/src/main/java/com/fs/task/CompanyMsgTask.java
  2. 13 0
      fs-company-app/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java
  3. 77 0
      fs-company/src/main/java/com/fs/company/controller/crm/ProxyOrderMsgController.java
  4. 22 0
      fs-company/src/main/java/com/fs/company/controller/store/FsInquiryOrderController.java
  5. 20 0
      fs-company/src/main/java/com/fs/company/controller/store/FsPackageOrderController.java
  6. 1 1
      fs-service/src/main/java/com/fs/course/domain/FsUserCourseVideo.java
  7. 8 0
      fs-service/src/main/java/com/fs/course/service/IFsCourseLinkService.java
  8. 150 4
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseLinkServiceImpl.java
  9. 26 0
      fs-service/src/main/java/com/fs/crm/service/IProxyOrderMsgService.java
  10. 111 0
      fs-service/src/main/java/com/fs/crm/service/impl/ProxyOrderMsgServiceImpl.java
  11. 1 1
      fs-service/src/main/java/com/fs/his/domain/FsInquiryOrder.java
  12. 1 0
      fs-service/src/main/java/com/fs/his/domain/FsPackageOrder.java
  13. 117 0
      fs-service/src/main/java/com/fs/his/domain/FsPreOrder.java
  14. 14 0
      fs-service/src/main/java/com/fs/his/mapper/FsPreOrderMapper.java
  15. 3 1
      fs-service/src/main/java/com/fs/his/param/FsInquiryOrderCreateParam.java
  16. 14 0
      fs-service/src/main/java/com/fs/his/param/FsPackageOrderAddParam.java
  17. 1 1
      fs-service/src/main/java/com/fs/his/param/FsPackageOrderCreateParam.java
  18. 16 0
      fs-service/src/main/java/com/fs/his/service/IFsPreOrderService.java
  19. 321 0
      fs-service/src/main/java/com/fs/his/service/impl/FsPreOrderServiceImpl.java
  20. 1 0
      fs-service/src/main/resources/mapper/his/FsInquiryOrderMapper.xml
  21. 1 0
      fs-service/src/main/resources/mapper/his/FsPackageOrderMapper.xml
  22. 141 0
      fs-service/src/main/resources/mapper/his/FsPreOrderMapper.xml
  23. 8 0
      fs-user-app/src/main/java/com/fs/app/controller/StoreOrderController.java

+ 93 - 0
fs-admin/src/main/java/com/fs/task/CompanyMsgTask.java

@@ -7,8 +7,13 @@ import com.fs.company.util.CompanyRedPacketBalanceUtil;
 import com.fs.crm.domain.CrmMsg;
 import com.fs.crm.mapper.CrmMsgMapper;
 import com.fs.crm.service.IOrderAuditMsgService;
+import com.fs.crm.service.IProxyOrderMsgService;
 import com.fs.crm.service.IRedPacketBalanceMsgService;
+import com.fs.his.domain.FsInquiryOrder;
+import com.fs.his.domain.FsPackageOrder;
 import com.fs.his.domain.FsStoreOrderFinanceAudit;
+import com.fs.his.mapper.FsInquiryOrderMapper;
+import com.fs.his.mapper.FsPackageOrderMapper;
 import com.fs.his.mapper.FsStoreOrderFinanceAuditMapper;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -31,10 +36,17 @@ public class CompanyMsgTask {
     private final CrmMsgMapper crmMsgMapper;
     private final IRedPacketBalanceMsgService redPacketBalanceMsgService;
     private final IOrderAuditMsgService orderAuditMsgService;
+    private final IProxyOrderMsgService proxyOrderMsgService;
+    private final FsPackageOrderMapper packageOrderMapper;
+    private final FsInquiryOrderMapper inquiryOrderMapper;
 
     private static final BigDecimal BALANCE_THRESHOLD = new BigDecimal("100");
     private static final int MSG_TYPE_RED_PACKET_BALANCE = 7;
     private static final int MSG_TYPE_ORDER_AUDIT = 8;
+    private static final int MSG_TYPE_PROXY_ORDER = 9;
+    private static final int ORDER_SOURCE_PROXY = 4;
+    private static final int ORDER_CATEGORY_PACKAGE = 1;
+    private static final int ORDER_CATEGORY_INQUIRY = 2;
 
     public void checkRedPacketBalance() {
         log.info("开始检查公司红包余额...");
@@ -100,4 +112,85 @@ public class CompanyMsgTask {
             return null;
         }
     }
+
+    public void checkProxyOrders() {
+        log.info("开始检查代制单订单...");
+        try {
+            checkProxyPackageOrders();
+//            checkProxyInquiryOrders();
+            log.info("检查代制单订单完成");
+        } catch (Exception e) {
+            log.error("检查代制单订单任务执行失败", e);
+        }
+    }
+
+    private void checkProxyPackageOrders() {
+        log.info("开始检查代制单套餐包订单...");
+        try {
+            FsPackageOrder queryParam = new FsPackageOrder();
+            queryParam.setSource(ORDER_SOURCE_PROXY);
+            queryParam.setIsPay(1);
+            List<FsPackageOrder> proxyPackageOrders = packageOrderMapper.selectFsPackageOrderList(queryParam);
+
+            for (FsPackageOrder order : proxyPackageOrders) {
+                try {
+                    CrmMsg existMsg = crmMsgMapper.selectMsgByObjIdAndType(order.getOrderId(), MSG_TYPE_PROXY_ORDER);
+                    if (existMsg == null) {
+                        Long companyId = order.getCompanyId();
+                        Long companyUserId=order.getCompanyUserId();
+                        if (companyId != null) {
+                            proxyOrderMsgService.sendProxyOrderReminderToAdmins(
+                                companyId,
+                                order.getOrderId(),
+                                order.getOrderSn(),
+                                ORDER_CATEGORY_PACKAGE,
+                                    companyUserId
+                            );
+                            log.info("代制单套餐包订单提醒已发送,订单ID: {}, 订单编号: {}", order.getOrderId(), order.getOrderSn());
+                        }
+                    }
+                } catch (Exception e) {
+                    log.error("发送代制单套餐包订单提醒失败,订单ID: {}", order.getOrderId(), e);
+                }
+            }
+            log.info("检查代制单套餐包订单完成");
+        } catch (Exception e) {
+            log.error("检查代制单套餐包订单失败", e);
+        }
+    }
+
+    private void checkProxyInquiryOrders() {
+        log.info("开始检查代制单问诊订单...");
+        try {
+            FsInquiryOrder queryParam = new FsInquiryOrder();
+            queryParam.setSource(ORDER_SOURCE_PROXY);
+            queryParam.setIsPay(1);
+            List<FsInquiryOrder> proxyInquiryOrders = inquiryOrderMapper.selectFsInquiryOrderList(queryParam);
+
+            for (FsInquiryOrder order : proxyInquiryOrders) {
+                try {
+                    CrmMsg existMsg = crmMsgMapper.selectMsgByObjIdAndType(order.getOrderId(), MSG_TYPE_PROXY_ORDER);
+                    if (existMsg == null) {
+                        Long companyId = order.getCompanyId();
+                        Long companyUserId=order.getCompanyUserId();
+                        if (companyId != null) {
+                            proxyOrderMsgService.sendProxyOrderReminderToAdmins(
+                                companyId,
+                                order.getOrderId(),
+                                order.getOrderSn(),
+                                ORDER_CATEGORY_INQUIRY,
+                                    companyUserId
+                            );
+                            log.info("代制单问诊订单提醒已发送,订单ID: {}, 订单编号: {}", order.getOrderId(), order.getOrderSn());
+                        }
+                    }
+                } catch (Exception e) {
+                    log.error("发送代制单问诊订单提醒失败,订单ID: {}", order.getOrderId(), e);
+                }
+            }
+            log.info("检查代制单问诊订单完成");
+        } catch (Exception e) {
+            log.error("检查代制单问诊订单失败", e);
+        }
+    }
 }

+ 13 - 0
fs-company-app/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java

@@ -33,6 +33,7 @@ import com.fs.course.vo.FsCourseWatchLogListVO;
 import com.fs.course.vo.FsUserCourseParticipationRecordVO;
 import com.fs.course.vo.newfs.*;
 import com.fs.im.domain.FsImMsgSendLog;
+import com.fs.im.dto.BatchSmsLinkDTO;
 import com.fs.im.dto.OpenImResponseDTO;
 import com.fs.im.service.IFsImMsgSendLogService;
 import com.fs.im.service.OpenIMService;
@@ -362,6 +363,18 @@ public class FsUserCourseVideoController extends AppBaseController {
         return ResponseResult.ok(courseLinkService.getGotoH5Link(linkStr));
     }
 
+    @ApiOperation("批量短信发送课程/获客短链")
+    @PostMapping("/batchSendSmsLink")
+    public OpenImResponseDTO batchSendSmsLink(@RequestBody BatchSmsLinkDTO batchSmsLinkDTO) {
+        return openIMService.batchSendSmsLink(batchSmsLinkDTO);
+    }
+
+    @ApiOperation("短信短链详情")
+    @GetMapping("/smsShortLink/detail")
+    public R getSmsShortLinkDetail(@RequestParam String code) {
+        return openIMService.getSmsShortLinkDetail(code);
+    }
+
     @ApiOperation("会员批量发送课程消息")
     @PostMapping("/batchSendCourse")
     public OpenImResponseDTO batchSendCourse(@RequestBody BatchSendCourseDTO batchSendCourseDTO) throws JsonProcessingException {

+ 77 - 0
fs-company/src/main/java/com/fs/company/controller/crm/ProxyOrderMsgController.java

@@ -0,0 +1,77 @@
+package com.fs.company.controller.crm;
+
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.R;
+import com.fs.common.utils.ServletUtils;
+import com.fs.crm.domain.CrmMsg;
+import com.fs.crm.mapper.CrmMsgMapper;
+import com.fs.crm.service.IProxyOrderMsgService;
+import com.fs.framework.security.LoginUser;
+import com.fs.framework.service.TokenService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Api(tags = "代制单下单提醒消息")
+@RestController
+@RequestMapping("/crm/proxyOrderMsg")
+public class ProxyOrderMsgController extends BaseController
+{
+    @Autowired
+    private TokenService tokenService;
+
+    @Autowired
+    private CrmMsgMapper crmMsgMapper;
+
+    @Autowired
+    private IProxyOrderMsgService proxyOrderMsgService;
+
+    private static final String PLATFORM_COMPANY = "company";
+
+    @ApiOperation("获取最新未读代制单下单提醒消息")
+    @GetMapping("/getLatestUnread")
+    public R getLatestUnreadMsg()
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        Long userId = loginUser.getUser().getUserId();
+        CrmMsg msg = proxyOrderMsgService.getLatestUnreadMsg(userId, PLATFORM_COMPANY);
+        Long unreadCount = proxyOrderMsgService.getUnreadCount(userId, PLATFORM_COMPANY);
+        Long totalCount = crmMsgMapper.selectTotalCountByPlatformAndType(userId, PLATFORM_COMPANY, IProxyOrderMsgService.MSG_TYPE_PROXY_ORDER);
+
+        Map<String, Object> result = new HashMap<>();
+        result.put("msg", msg);
+        result.put("unreadCount", unreadCount);
+        result.put("totalCount", totalCount);
+        return R.ok().put("data", result);
+    }
+
+    @ApiOperation("获取未读代制单下单提醒消息数量")
+    @GetMapping("/getUnreadCount")
+    public R getUnreadCount()
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        Long count = proxyOrderMsgService.getUnreadCount(loginUser.getUser().getUserId(), PLATFORM_COMPANY);
+        return R.ok().put("data", count);
+    }
+
+    @ApiOperation("标记代制单下单提醒消息为已读")
+    @PostMapping("/markAsRead/{msgId}")
+    public R markAsRead(@PathVariable Long msgId)
+    {
+        crmMsgMapper.markMsgAsRead(msgId);
+        return R.ok();
+    }
+
+    @ApiOperation("标记所有代制单下单提醒消息为已读")
+    @PostMapping("/markAllAsRead")
+    public R markAllAsRead()
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        proxyOrderMsgService.markAllAsRead(loginUser.getUser().getUserId(), PLATFORM_COMPANY);
+        return R.ok();
+    }
+}

+ 22 - 0
fs-company/src/main/java/com/fs/company/controller/store/FsInquiryOrderController.java

@@ -27,6 +27,7 @@ import com.fs.his.service.IFsDoctorService;
 import com.fs.his.service.IFsExportTaskService;
 import com.fs.his.service.IFsInquiryOrderLogsService;
 import com.fs.his.service.IFsInquiryOrderService;
+import com.fs.his.service.IFsPreOrderService;
 import com.fs.his.utils.PhoneUtil;
 import com.fs.his.vo.FsInquiryOrderListVO;
 import com.fs.his.vo.FsInquiryOrderVO;
@@ -37,6 +38,7 @@ import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
+import java.io.UnsupportedEncodingException;
 import java.util.Base64;
 import java.util.Date;
 import java.util.List;
@@ -56,6 +58,8 @@ public class FsInquiryOrderController extends BaseController
     @Autowired
     private IFsInquiryOrderService fsInquiryOrderService;
     @Autowired
+    private IFsPreOrderService fsPreOrderService;
+    @Autowired
     private IFsInquiryOrderLogsService fsInquiryOrderLogsService;
 
     @Autowired
@@ -275,6 +279,24 @@ public class FsInquiryOrderController extends BaseController
         return fsInquiryOrderService.createOrder(param);
     }
 
+    @PreAuthorize("@ss.hasPermi('store:inquiryOrder:add')")
+    @Log(title = "问诊订单预制分享链接", businessType = BusinessType.INSERT)
+    @PostMapping("/shareLink")
+    public R createShareLink(@RequestBody FsInquiryOrderCreateParam param){
+        String uuid = IdUtil.randomUUID();
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        param.setOrderKey(uuid);
+        param.setCompanyId(loginUser.getCompany().getCompanyId());
+        param.setCompanyUserId(loginUser.getUser().getUserId());
+        return fsPreOrderService.createInquiryPreOrderLink(param, param.getCompanyId(), param.getCompanyUserId());
+    }
+
+    @GetMapping("/preOrder/{preOrderId}")
+    public R getPreOrder(@PathVariable("preOrderId") Long preOrderId)
+    {
+        return fsPreOrderService.getPreOrder(preOrderId);
+    }
+
     /**
      * 手动代下问诊订单
      */

+ 20 - 0
fs-company/src/main/java/com/fs/company/controller/store/FsPackageOrderController.java

@@ -18,6 +18,7 @@ import com.fs.his.param.FsPackageOrderManuallyParam;
 import com.fs.his.param.FsPackageOrderParam;
 import com.fs.his.service.IFsExportTaskService;
 import com.fs.his.service.IFsPackageOrderService;
+import com.fs.his.service.IFsPreOrderService;
 import com.fs.his.utils.PhoneUtil;
 import com.fs.his.vo.FsPackageOrderListVO;
 import com.fs.his.vo.FsPackageOrderVO;
@@ -26,6 +27,7 @@ import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
+import java.io.UnsupportedEncodingException;
 import java.util.Base64;
 import java.util.Date;
 import java.util.List;
@@ -43,6 +45,8 @@ public class FsPackageOrderController extends BaseController
     @Autowired
     private IFsPackageOrderService fsPackageOrderService;
     @Autowired
+    private IFsPreOrderService fsPreOrderService;
+    @Autowired
     private IFsExportTaskService exportTaskService;
     /**
      * 查询套餐订单列表
@@ -199,6 +203,22 @@ public class FsPackageOrderController extends BaseController
         return fsPackageOrderService.addPackageOrder(fsPackageOrder);
     }
 
+    @PreAuthorize("@ss.hasPermi('store:packageOrder:add')")
+    @Log(title = "套餐订单预制分享链接", businessType = BusinessType.INSERT)
+    @PostMapping("/shareLink")
+    public R createShareLink(@RequestBody FsPackageOrderAddParam fsPackageOrder) {
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        fsPackageOrder.setCompanyId(loginUser.getCompany().getCompanyId());
+        fsPackageOrder.setCompanyUserId(loginUser.getUser().getUserId());
+        return fsPreOrderService.createPackagePreOrderLink(fsPackageOrder, fsPackageOrder.getCompanyId(), fsPackageOrder.getCompanyUserId());
+    }
+
+    @GetMapping("/preOrder/{preOrderId}")
+    public R getPreOrder(@PathVariable("preOrderId") Long preOrderId)
+    {
+        return fsPreOrderService.getPreOrder(preOrderId);
+    }
+
     /**
      * 手动代下套餐订单
      */

+ 1 - 1
fs-service/src/main/java/com/fs/course/domain/FsUserCourseVideo.java

@@ -109,7 +109,7 @@ public class FsUserCourseVideo extends BaseEntity
 
     private Long productId;//拍商品id
 
-    private Integer isVip;//是否VIP课程 0:否 1:是
+    private Integer isVip;//是否VIP课程 0:是 1:否
 
     private Long listingStartTime;//商品售卖时间
 

+ 8 - 0
fs-service/src/main/java/com/fs/course/service/IFsCourseLinkService.java

@@ -96,6 +96,14 @@ public interface IFsCourseLinkService
      */
     String getGotoWxAppLink(String linkStr, String appId);
 
+    /**
+     * 获取跳转微信小程序的链接地址(预制单专用,不影响旧逻辑)
+     * @param linkStr 链接字符串
+     * @param appId 小程序appId(必传或可通过companyId解析)
+     * @return 小程序链接
+     */
+    String getGotoWxAppLinkForPreOrder(String linkStr, String appId);
+
     R getWxaCodeGenerateScheme(String linkStr,String appId);
 
     R getProjectCode();

+ 150 - 4
fs-service/src/main/java/com/fs/course/service/impl/FsCourseLinkServiceImpl.java

@@ -822,21 +822,46 @@ public class FsCourseLinkServiceImpl implements IFsCourseLinkService
     @Override
     public String getGotoWxAppLink(String linkStr, String appId) {
         Long companyId = parseCompanyIdFromLink(linkStr);
-        
+
         List<String> appIdList = getAppIdListByCompanyId(companyId);
-        
+
         if (appIdList == null || appIdList.isEmpty()) {
             return "未配置小程序,获取失败";
         }
-        
+
         int currentIndex = 0;
         if (StringUtils.isNotBlank(appId) && appIdList.contains(appId)) {
             currentIndex = appIdList.indexOf(appId);
         }
-        
+
         return generateWxAppLinkWithRetry(linkStr, appIdList, currentIndex);
     }
 
+    @Override
+    public String getGotoWxAppLinkForPreOrder(String linkStr, String appId) {
+        Long companyId = parseCompanyIdFromLink(linkStr);
+
+        List<String> appIdList;
+        if (companyId != null) {
+            appIdList = getAppIdListByCompanyId(companyId);
+        } else if (StringUtils.isNotBlank(appId)) {
+            appIdList = Collections.singletonList(appId);
+        } else {
+            appIdList = Collections.emptyList();
+        }
+
+        if (appIdList == null || appIdList.isEmpty()) {
+            return "未配置小程序,获取失败";
+        }
+
+        int currentIndex = 0;
+        if (StringUtils.isNotBlank(appId) && appIdList.contains(appId)) {
+            currentIndex = appIdList.indexOf(appId);
+        }
+
+        return generateWxAppLinkWithRetryForPreOrder(linkStr, appIdList, currentIndex);
+    }
+
     /**
      * 从链接字符串中解析companyId
      * @param linkStr 链接字符串,格式如:/pages_course/videovip?course={"companyId":123,...}
@@ -1052,6 +1077,127 @@ public class FsCourseLinkServiceImpl implements IFsCourseLinkService
         }
     }
 
+    private String generateWxAppLinkWithRetryForPreOrder(String linkStr, List<String> appIdList, int currentIndex) {
+        if (currentIndex >= appIdList.size()) {
+            log.error("所有appId都已尝试失败");
+            return "所有小程序均调用失败,获取失败";
+        }
+
+        String currentAppId = appIdList.get(currentIndex);
+        log.info("尝试使用appId[{}]:{}", currentIndex, currentAppId);
+
+        CloseableHttpClient client = null;
+        try {
+            client = HttpClients.createDefault();
+            String decodedLinkStr = URLDecoder.decode(linkStr, StandardCharsets.UTF_8.toString());
+            int queryIndex = decodedLinkStr.indexOf("?");
+            if (queryIndex == -1 || queryIndex == decodedLinkStr.length() - 1) {
+                return "页面链接错误,获取失败";
+            }
+
+            String pageUrl = decodedLinkStr.substring(0, queryIndex);
+            String queryString = decodedLinkStr.substring(queryIndex + 1);
+            if (pageUrl.startsWith("/")) {
+                pageUrl = pageUrl.substring(1);
+            }
+            if (pageUrl.contains(".html")) {
+                pageUrl = pageUrl.replace(".html", "");
+            }
+            String[] paramPairs = queryString.split("&");
+            StringBuilder encodedQuery = new StringBuilder();
+            for (int i = 0; i < paramPairs.length; i++) {
+                String pair = paramPairs[i];
+                int equalIndex = pair.indexOf("=");
+                if (equalIndex > 0 && equalIndex < pair.length() - 1) {
+                    String key = pair.substring(0, equalIndex);
+                    String value = pair.substring(equalIndex + 1);
+                    if (encodedQuery.length() > 0) {
+                        encodedQuery.append("&");
+                    }
+                    encodedQuery.append(key).append("=").append(URLEncoder.encode(value, StandardCharsets.UTF_8.toString()));
+                } else if (equalIndex == -1) {
+                    if (encodedQuery.length() > 0) {
+                        encodedQuery.append("&");
+                    }
+                    encodedQuery.append(pair);
+                }
+            }
+            String query = encodedQuery.toString();
+
+            final WxMaService wxService = WxMaConfiguration.getMaService(currentAppId);
+            String token = wxService.getAccessToken();
+            log.info("小程序TOKEN值-------->刷新前TOKEN:{}", token);
+            HttpPost httpPost = new HttpPost("https://api.weixin.qq.com/wxa/generate_urllink?access_token=" + token);
+            JSONObject bodyObj = new JSONObject();
+            bodyObj.put("path", pageUrl);
+            bodyObj.put("query", query);
+            log.info("微信小程序请求参数打印:{}", bodyObj.toJSONString());
+            StringEntity entity = new StringEntity(bodyObj.toJSONString(),"UTF-8");
+            httpPost.setEntity(entity);
+            httpPost.setHeader("Content-type", "application/json");
+            httpPost.setHeader("cache-control","max-age=0");
+            HttpEntity response = client.execute(httpPost).getEntity();
+            String responseString = EntityUtils.toString(response);
+            log.info("微信小程序接口响应数据:{}", responseString);
+            JSONObject jsonObject = JSONObject.parseObject(responseString);
+
+            if(TOKEN_VALID_CODE.equals(jsonObject.getString("errcode"))){
+                Integer curVersion = Integer.valueOf(version);
+                synchronized (TOKEN_VALID_CODE){
+                    if(curVersion.equals(version)){
+                        log.info("小程序TOKEN:40001进入强制刷新-------->刷新前TOKEN:{}", token);
+                        wxService.getAccessToken(true);
+                        version = version.equals(Integer.MAX_VALUE) ? 0 : curVersion + 1;
+                        log.info("小程序TOKEN:40001进入强制刷新-------->刷新后TOKEN:{}", wxService.getAccessToken());
+                    }
+                    return generateWxAppLinkWithRetryForPreOrder(linkStr, appIdList, currentIndex);
+                }
+            }
+
+            if(null != jsonObject && !jsonObject.isEmpty() && jsonObject.containsKey("url_link")){
+                return jsonObject.getString("url_link");
+            }
+
+            if(jsonObject != null && jsonObject.containsKey("errcode")) {
+                Integer errcode = jsonObject.getInteger("errcode");
+                String errmsg = jsonObject.getString("errmsg");
+                log.error("微信小程序生成链接失败,appId:{},错误码:{},错误信息:{}", currentAppId, errcode, errmsg);
+
+                if (currentIndex + 1 < appIdList.size()) {
+                    log.info("切换到下一个appId重试,下一个索引:{}", currentIndex + 1);
+                    return generateWxAppLinkWithRetryForPreOrder(linkStr, appIdList, currentIndex + 1);
+                }
+
+                return "微信错误:" + errcode + "|" + errmsg;
+            }
+
+            log.error("微信小程序响应格式异常");
+            return "微信小程序响应格式异常";
+
+        } catch (WxErrorException e) {
+            log.error("微信API调用异常,appId:{}", currentAppId, e);
+            if (currentIndex + 1 < appIdList.size()) {
+                log.info("异常切换到下一个appId重试,下一个索引:{}", currentIndex + 1);
+                return generateWxAppLinkWithRetryForPreOrder(linkStr, appIdList, currentIndex + 1);
+            }
+            return "微信API异常";
+        } catch (ClientProtocolException e) {
+            log.error("HTTP协议错误", e);
+            return "网络请求失败";
+        } catch (IOException e) {
+            log.error("IO异常", e);
+            return "网络连接失败";
+        } finally {
+            if (client != null) {
+                try {
+                    client.close();
+                } catch (IOException e) {
+                    log.error("关闭HttpClient失败", e);
+                }
+            }
+        }
+    }
+
     @Override
     public R getWxaCodeGenerateScheme(String linkStr,String appId) {
         CloseableHttpClient client = null;

+ 26 - 0
fs-service/src/main/java/com/fs/crm/service/IProxyOrderMsgService.java

@@ -0,0 +1,26 @@
+package com.fs.crm.service;
+
+import com.fs.crm.domain.CrmMsg;
+
+/**
+ * 代制单下单提醒消息服务接口
+ *
+ * @author fs
+ * @date 2026-05-12
+ */
+public interface IProxyOrderMsgService
+{
+    int MSG_TYPE_PROXY_ORDER = 10;
+
+    void sendProxyOrderReminder(Long companyId, Long companyUserId, Long orderId, String orderCode, Integer orderCategory);
+
+    void sendProxyOrderReminderToAdmins(Long companyId, Long orderId, String orderCode, Integer orderCategory,Long companyUserId);
+
+    CrmMsg getLatestUnreadMsg(Long userId, String platform);
+
+    Long getUnreadCount(Long userId, String platform);
+
+    void markAsRead(Long msgId);
+
+    void markAllAsRead(Long userId, String platform);
+}

+ 111 - 0
fs-service/src/main/java/com/fs/crm/service/impl/ProxyOrderMsgServiceImpl.java

@@ -0,0 +1,111 @@
+package com.fs.crm.service.impl;
+
+import com.fs.common.utils.DateUtils;
+import com.fs.company.mapper.CompanyUserMapper;
+import com.fs.crm.domain.CrmMsg;
+import com.fs.crm.mapper.CrmMsgMapper;
+import com.fs.crm.service.IProxyOrderMsgService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 代制单下单提醒消息服务实现
+ *
+ * @author fs
+ * @date 2026-05-12
+ */
+@Service
+public class ProxyOrderMsgServiceImpl implements IProxyOrderMsgService
+{
+    private static final Logger log = LoggerFactory.getLogger(ProxyOrderMsgServiceImpl.class);
+
+    private static final String PLATFORM_COMPANY = "company";
+
+    private static final int ORDER_CATEGORY_PACKAGE = 1;
+    private static final int ORDER_CATEGORY_INQUIRY = 2;
+
+    @Autowired
+    private CrmMsgMapper crmMsgMapper;
+
+    @Autowired
+    private CompanyUserMapper companyUserMapper;
+
+    @Override
+    public void sendProxyOrderReminder(Long companyId, Long companyUserId, Long orderId, String orderCode, Integer orderCategory)
+    {
+        try {
+            String orderCategoryName = orderCategory != null && orderCategory == ORDER_CATEGORY_INQUIRY ? "问诊订单" : "套餐包订单";
+            String actionUrl = orderCategory != null && orderCategory == ORDER_CATEGORY_INQUIRY ? "order/inquiryOrder" : "order/order";
+
+            CrmMsg existMsg = crmMsgMapper.selectMsgByObjIdAndType(orderId, MSG_TYPE_PROXY_ORDER);
+            if (existMsg != null) {
+                log.info("代制单下单提醒消息已存在,跳过发送,订单ID: {}", orderId);
+                return;
+            }
+
+            CrmMsg msg = new CrmMsg();
+            msg.setMsgType(MSG_TYPE_PROXY_ORDER);
+            msg.setTitle("代制单下单提醒");
+            msg.setContent(String.format("有一笔新的代制单%s已支付,订单编号: %s,请及时处理", orderCategoryName, orderCode));
+            msg.setCompanyUserId(companyUserId);
+            msg.setCompanyId(companyId);
+            msg.setObjId(orderId);
+            msg.setActionUrl(actionUrl);
+            msg.setPlatform(PLATFORM_COMPANY);
+            msg.setPriority(1);
+            msg.setIsRead(0);
+            msg.setCreateTime(DateUtils.getNowDate());
+            msg.setExpireTime(getExpireTime(7));
+
+            crmMsgMapper.insertCrmMsg(msg);
+            log.info("发送代制单下单提醒消息成功, 公司ID: {}, 用户ID: {}, 订单编号: {}", companyId, companyUserId, orderCode);
+        } catch (Exception e) {
+            log.error("发送代制单下单提醒消息失败, 订单ID: {}", orderId, e);
+        }
+    }
+
+    @Override
+    public void sendProxyOrderReminderToAdmins(Long companyId, Long orderId, String orderCode, Integer orderCategory,Long companyUserId)
+    {
+        sendProxyOrderReminder(companyId, companyUserId, orderId, orderCode, orderCategory);
+    }
+
+    @Override
+    public CrmMsg getLatestUnreadMsg(Long userId, String platform)
+    {
+        return crmMsgMapper.selectLatestUnreadMsg(userId, platform, MSG_TYPE_PROXY_ORDER);
+    }
+
+    @Override
+    public Long getUnreadCount(Long userId, String platform)
+    {
+        return crmMsgMapper.selectUnreadCountByPlatformAndType(userId, platform, MSG_TYPE_PROXY_ORDER);
+    }
+
+    @Override
+    public void markAsRead(Long msgId)
+    {
+        CrmMsg msg = new CrmMsg();
+        msg.setMsgId(msgId);
+        msg.setIsRead(1);
+        crmMsgMapper.updateCrmMsg(msg);
+    }
+
+    @Override
+    public void markAllAsRead(Long userId, String platform)
+    {
+        crmMsgMapper.markAllAsReadByPlatform(userId, platform);
+    }
+
+    private Date getExpireTime(int days) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.add(Calendar.DAY_OF_MONTH, days);
+        return calendar.getTime();
+    }
+}

+ 1 - 1
fs-service/src/main/java/com/fs/his/domain/FsInquiryOrder.java

@@ -141,7 +141,7 @@ public class FsInquiryOrder extends BaseEntity
     private String companyUserRemark; //销售备注
 
     private Integer isSendSms; //是否发送短信
-    private Integer source;//订单来源
+    private Integer source;//订单来源 1:小程序 2:app  3:H5 4:代制单
 
     private Long triageUserId;
 

+ 1 - 0
fs-service/src/main/java/com/fs/his/domain/FsPackageOrder.java

@@ -157,5 +157,6 @@ public class FsPackageOrder extends BaseEntity
 
     private Long userCouponId;
     private String icdCode;
+    //订单来源 1:小程序 2:app  3:H5 4:代制单
     private Integer source;
 }

+ 117 - 0
fs-service/src/main/java/com/fs/his/domain/FsPreOrder.java

@@ -0,0 +1,117 @@
+package com.fs.his.domain;
+
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 预制单对象 fs_pre_order
+ */
+@Data
+public class FsPreOrder extends BaseEntity {
+    /** 预制单ID */
+    private Long preOrderId;
+
+    /** 预制单类型:1套餐包,2问诊订单 */
+    private Integer preOrderType;
+
+    /** 公司ID */
+    private Long companyId;
+
+    /** 销售ID */
+    private Long companyUserId;
+
+    /** 用户ID */
+    private Long userId;
+
+    /** 患者ID */
+    private Long patientId;
+
+    /** 套餐ID */
+    private Long packageId;
+
+    /** 优惠券ID */
+    private Long couponId;
+
+    /** 支付类型 */
+    private Integer payType;
+
+    /** 支付金额 */
+    private BigDecimal payMoney;
+
+    /** 应付金额 */
+    private BigDecimal payableAmount;
+
+    /** 地址ID */
+    private Long addressId;
+
+    /** 产品ID列表JSON */
+    private String productIds;
+
+    /** 问诊订单key */
+    private String orderKey;
+
+    /** 病情描述 */
+    private String title;
+
+    /** 销售备注 */
+    private String companyUserRemark;
+
+    /** 患病时长 */
+    private String duration;
+
+    /** 是否就诊 */
+    private String isVisit;
+
+    /** 问诊类型 */
+    private Integer inquiryType;
+
+    /** 问诊子类型 */
+    private Integer inquirySubType;
+
+    /** 问诊订单类型 */
+    private Integer inquiryOrderType;
+
+    /** 医生ID */
+    private Long doctorId;
+
+    /** 检测报告 */
+    private String reportImages;
+
+    /** 舌苔图片 */
+    private String tongueImages;
+
+    /** 面部图片 */
+    private String faceImages;
+
+    /** 手部图片 */
+    private String handImages;
+
+    /** 身高 */
+    private String height;
+
+    /** 体重 */
+    private String weight;
+
+    /** 联系电话 */
+    private String mobile;
+
+    /** 用药情况 */
+    private String medication;
+
+    /** 期望会诊方式 */
+    private String usage;
+
+    /** 订单来源 */
+    private Integer source;
+
+    /** 小程序页面参数 */
+    private String linkStr;
+
+    /** 生成后的分享链接 */
+    private String shareLink;
+
+    /** 状态:0待下单,1已下单,2已失效 */
+    private Integer status;
+}

+ 14 - 0
fs-service/src/main/java/com/fs/his/mapper/FsPreOrderMapper.java

@@ -0,0 +1,14 @@
+package com.fs.his.mapper;
+
+import com.fs.his.domain.FsPreOrder;
+
+/**
+ * 预制单Mapper接口
+ */
+public interface FsPreOrderMapper {
+    FsPreOrder selectFsPreOrderById(Long preOrderId);
+
+    int insertFsPreOrder(FsPreOrder fsPreOrder);
+
+    int updateFsPreOrder(FsPreOrder fsPreOrder);
+}

+ 3 - 1
fs-service/src/main/java/com/fs/his/param/FsInquiryOrderCreateParam.java

@@ -47,6 +47,8 @@ public class FsInquiryOrderCreateParam implements Serializable {
     private String usage;//期望会诊方式
     private Long companyId;
     private Long companyUserId;
-    private Integer source;//订单来源 1:小程序 2:app  3:H5
+    private Integer source;//订单来源 1:小程序 2:app  3:H5 4:代制单
 
+    /** 优惠券id */
+    private Long couponId;
 }

+ 14 - 0
fs-service/src/main/java/com/fs/his/param/FsPackageOrderAddParam.java

@@ -22,6 +22,20 @@ public class FsPackageOrderAddParam {
     /** 支付金额 */
     private BigDecimal payMoney;
 
+    /**
+     * 应付金额
+     */
+
+    private  BigDecimal payableAmount;
+
     /** 产品id */
     private List<Long> productIds;
+
+    /** 套餐优惠券ID */
+    private Long couponId;
+
+    /**
+     * 订单备注
+     */
+    private  String orderRemark;
 }

+ 1 - 1
fs-service/src/main/java/com/fs/his/param/FsPackageOrderCreateParam.java

@@ -18,7 +18,7 @@ public class FsPackageOrderCreateParam implements Serializable {
     private Long companyUserId;
     private String formJson;
     private String patientJson;
-    private Integer source;//订单来源 1:小程序 2:app  3:H5
+    private Integer source;//订单来源 1:小程序 2:app  3:H5 4:代制单
     private String createPackageOrderKey;
     private Integer payType;
     private Integer isUserInformation = 0;

+ 16 - 0
fs-service/src/main/java/com/fs/his/service/IFsPreOrderService.java

@@ -0,0 +1,16 @@
+package com.fs.his.service;
+
+import com.fs.common.core.domain.R;
+import com.fs.his.param.FsInquiryOrderCreateParam;
+import com.fs.his.param.FsPackageOrderAddParam;
+
+/**
+ * 预制单Service接口
+ */
+public interface IFsPreOrderService {
+    R createPackagePreOrderLink(FsPackageOrderAddParam param, Long companyId, Long companyUserId);
+
+    R createInquiryPreOrderLink(FsInquiryOrderCreateParam param, Long companyId, Long companyUserId);
+
+    R getPreOrder(Long preOrderId);
+}

+ 321 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsPreOrderServiceImpl.java

@@ -0,0 +1,321 @@
+package com.fs.his.service.impl;
+
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.json.JSONUtil;
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.fs.common.core.domain.R;
+import com.fs.company.domain.CompanyMiniapp;
+import com.fs.company.service.ICompanyMiniappService;
+import com.fs.course.service.IFsCourseLinkService;
+import com.fs.his.domain.*;
+import com.fs.his.dto.FsPriceDTO;
+import com.fs.his.dto.InquiryConfigDTO;
+import com.fs.his.mapper.*;
+import com.fs.his.param.FsInquiryOrderCreateParam;
+import com.fs.his.param.FsPackageOrderAddParam;
+import com.fs.his.service.IFsPreOrderService;
+import com.fs.system.service.ISysConfigService;
+import lombok.AllArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.io.UnsupportedEncodingException;
+import java.math.BigDecimal;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 预制单Service业务层处理
+ */
+@Service
+@AllArgsConstructor
+public class FsPreOrderServiceImpl implements IFsPreOrderService {
+    private static final int TYPE_PACKAGE = 1;
+    private static final int TYPE_INQUIRY = 2;
+
+    private final FsPreOrderMapper fsPreOrderMapper;
+    private final IFsCourseLinkService fsCourseLinkService;
+    private final FsPatientMapper fsPatientMapper;
+    private final FsPackageMapper fsPackageMapper;
+    private final FsUserAddressMapper fsUserAddressMapper;
+    private final FsCouponMapper fsCouponMapper;
+    private final FsUserCouponMapper fsUserCouponMapper;
+    private final FsDoctorMapper fsDoctorMapper;
+    private final ISysConfigService configService;
+    private final ICompanyMiniappService companyMiniappService;
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public R createPackagePreOrderLink(FsPackageOrderAddParam param, Long companyId, Long companyUserId) {
+        if (param == null) {
+            return R.error("参数不能为空");
+        }
+        FsPatient patient = fsPatientMapper.selectFsPatientByPatientId(param.getPatientId());
+        if (patient == null) {
+            return R.error("请提交患者信息");
+        }
+        FsPackage fsPackage = fsPackageMapper.selectFsPackageByPackageId(param.getPackageId());
+        if (fsPackage == null || Integer.valueOf(0).equals(fsPackage.getStatus())) {
+            return R.error("套餐已下架");
+        }
+        Integer num = fsPackage.getNum();
+        if (num != null && num != 0) {
+            int count = fsPackageMapper.selectFsPackageListByUser(param.getUserId(), fsPackage.getPackageId());
+            if (count >= num) {
+                return R.error("超过限购次数");
+            }
+        }
+        FsUserAddress address = fsUserAddressMapper.selectFsUserAddressByAddressId(param.getAddressId());
+        if (address == null) {
+            return R.error("地址错误");
+        }
+        //支付金额
+        BigDecimal totalPrice =param.getPayMoney();
+        BigDecimal payableAmount = param.getPayableAmount() != null ? param.getPayableAmount(): fsPackage.getTotalPrice();
+        if (param.getCouponId() != null) {
+            R couponCheck = checkPackageCoupon(param.getCouponId(), param.getUserId(), fsPackage);
+            if (couponCheck != null) {
+                return couponCheck;
+            }
+            FsCoupon coupon = fsCouponMapper.selectFsCouponByCouponId(param.getCouponId());
+            payableAmount = payableAmount.subtract(coupon.getPrice() == null ? BigDecimal.ZERO : coupon.getPrice());
+            if (payableAmount.compareTo(BigDecimal.ZERO) < 0) {
+                payableAmount = BigDecimal.ZERO;
+            }
+        }
+        FsPreOrder preOrder = buildPackagePreOrder(param, companyId, companyUserId, totalPrice, payableAmount);
+        return createPreOrderLink(preOrder, "/pages_index/packageDetails.html");
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public R createInquiryPreOrderLink(FsInquiryOrderCreateParam param, Long companyId, Long companyUserId) {
+        if (param == null) {
+            return R.error("参数不能为空");
+        }
+        FsPatient patient = fsPatientMapper.selectFsPatientByPatientId(param.getPatientId());
+        if (patient == null) {
+            return R.error("请提交患者信息");
+        }
+        BigDecimal payableAmount = BigDecimal.ZERO;
+        if (param.getDoctorId() != null) {
+            FsDoctor doctor = fsDoctorMapper.selectFsDoctorByDoctorId(param.getDoctorId());
+            if (doctor == null) {
+                return R.error("医生不存在");
+            }
+            payableAmount = getInquiryPrice(param.getDoctorId(), param.getOrderType());
+        }
+        if (param.getCouponId() != null) {
+            R couponCheck = checkInquiryCoupon(param.getCouponId(), param.getUserId(), payableAmount, companyId);
+            if (couponCheck != null) {
+                return couponCheck;
+            }
+            FsUserCoupon userCoupon = fsUserCouponMapper.selectFsUserCouponById(param.getCouponId());
+            if (userCoupon != null) {
+                FsCoupon coupon = fsCouponMapper.selectFsCouponByCouponId(userCoupon.getCouponId());
+                if (coupon != null) {
+                    BigDecimal couponPrice = coupon.getPrice() == null ? BigDecimal.ZERO : coupon.getPrice();
+                    payableAmount = payableAmount.subtract(couponPrice);
+                    if (payableAmount.compareTo(BigDecimal.ZERO) < 0) {
+                        payableAmount = BigDecimal.ZERO;
+                    }
+                }
+            }
+        }
+        FsPreOrder preOrder = buildInquiryPreOrder(param, companyId, companyUserId, payableAmount);
+        return createPreOrderLink(preOrder, "/pages_order/inquiryForm1.html");
+    }
+
+    @Override
+    public R getPreOrder(Long preOrderId) {
+        if (preOrderId == null) {
+            return R.error("预制单ID不能为空");
+        }
+        FsPreOrder preOrder = fsPreOrderMapper.selectFsPreOrderById(preOrderId);
+        if (preOrder == null) {
+            return R.error("预制单不存在");
+        }
+        return R.ok().put("data", preOrder);
+    }
+
+    private R createPreOrderLink(FsPreOrder preOrder, String pagePath){
+        if (preOrder.getCompanyId() == null || preOrder.getCompanyUserId() == null) {
+            return R.error("公司或销售不能为空");
+        }
+        preOrder.setStatus(0);
+        preOrder.setCreateTime(new Date());
+        fsPreOrderMapper.insertFsPreOrder(preOrder);
+
+        String rawLinkStr;
+        String appId = null;
+        if (Integer.valueOf(TYPE_INQUIRY).equals(preOrder.getPreOrderType())) {
+            rawLinkStr = pagePath + "?preOrderId=" + preOrder.getPreOrderId() + "&isNew=true";
+            appId = getCompanyFirstAppId(preOrder.getCompanyId());
+        } else {
+            rawLinkStr = pagePath + "?companyId=" + preOrder.getCompanyId()
+                    + "&companyUserId=" + preOrder.getCompanyUserId()
+                    + "&preOrderId=" + preOrder.getPreOrderId()
+                    + "&choose=0"
+                    + "&isNew=true";
+        }
+        String linkStr;
+        try {
+            linkStr = URLEncoder.encode(rawLinkStr, StandardCharsets.UTF_8.toString());
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException("链接编码失败", e);
+        }
+        String shareLink = fsCourseLinkService.getGotoWxAppLinkForPreOrder(linkStr, appId);
+
+        FsPreOrder update = new FsPreOrder();
+        update.setPreOrderId(preOrder.getPreOrderId());
+        update.setLinkStr(rawLinkStr);
+        update.setShareLink(shareLink);
+        update.setUpdateTime(new Date());
+        fsPreOrderMapper.updateFsPreOrder(update);
+
+        return R.ok()
+                .put("preOrderId", preOrder.getPreOrderId())
+                .put("linkStr", linkStr)
+                .put("shareLink", shareLink);
+    }
+
+    private String getCompanyFirstAppId(Long companyId) {
+        if (companyId == null) {
+            return null;
+        }
+        List<CompanyMiniapp> miniappList = companyMiniappService.list(new QueryWrapper<CompanyMiniapp>().eq("company_id", companyId));
+        if (miniappList == null || miniappList.isEmpty() || miniappList.get(0) == null || miniappList.get(0).getAppId() == null) {
+            return null;
+        }
+        String[] appIds = miniappList.get(0).getAppId().split(",");
+        return appIds.length > 0 ? appIds[0].trim() : null;
+    }
+
+    private FsPreOrder buildPackagePreOrder(FsPackageOrderAddParam param, Long companyId, Long companyUserId, BigDecimal totalPrice, BigDecimal payableAmount) {
+        FsPreOrder preOrder = new FsPreOrder();
+        preOrder.setPreOrderType(TYPE_PACKAGE);
+        preOrder.setCompanyId(companyId);
+        preOrder.setCompanyUserId(companyUserId);
+        preOrder.setUserId(param.getUserId());
+        preOrder.setPatientId(param.getPatientId());
+        preOrder.setPackageId(param.getPackageId());
+        preOrder.setCouponId(param.getCouponId());
+        preOrder.setCompanyUserRemark(param.getOrderRemark());
+        preOrder.setPayType(param.getPayType());
+        preOrder.setPayMoney(totalPrice);
+        preOrder.setPayableAmount(payableAmount);
+        preOrder.setAddressId(param.getAddressId());
+        preOrder.setProductIds(param.getProductIds() == null ? null : JSON.toJSONString(param.getProductIds()));
+        return preOrder;
+    }
+
+    private FsPreOrder buildInquiryPreOrder(FsInquiryOrderCreateParam param, Long companyId, Long companyUserId, BigDecimal payableAmount) {
+        FsPreOrder preOrder = new FsPreOrder();
+        preOrder.setPreOrderType(TYPE_INQUIRY);
+        preOrder.setCompanyId(companyId);
+        preOrder.setCompanyUserId(companyUserId);
+        preOrder.setUserId(param.getUserId());
+        preOrder.setOrderKey(param.getOrderKey() == null ? IdUtil.randomUUID() : param.getOrderKey());
+        preOrder.setPatientId(param.getPatientId());
+        preOrder.setCouponId(param.getCouponId());
+        preOrder.setTitle(param.getTitle());
+        preOrder.setCompanyUserRemark(param.getCompanyUserRemark());
+        preOrder.setDuration(param.getDuration());
+        preOrder.setIsVisit(param.getIsVisit());
+        preOrder.setInquiryType(param.getInquiryType());
+        preOrder.setInquirySubType(param.getInquirySubType());
+        preOrder.setInquiryOrderType(param.getOrderType());
+        preOrder.setDoctorId(param.getDoctorId());
+        preOrder.setReportImages(param.getReportImages());
+        preOrder.setTongueImages(param.getTongueImages());
+        preOrder.setFaceImages(param.getFaceImages());
+        preOrder.setHandImages(param.getHandImages());
+        preOrder.setHeight(param.getHeight());
+        preOrder.setWeight(param.getWeight());
+        preOrder.setMobile(param.getMobile());
+        preOrder.setMedication(param.getMedication());
+        preOrder.setUsage(param.getUsage());
+        preOrder.setSource(param.getSource());
+        preOrder.setPayableAmount(payableAmount);
+        return preOrder;
+    }
+
+    private R checkPackageCoupon(Long couponId, Long userId, FsPackage fsPackage) {
+        FsCoupon coupon = fsCouponMapper.selectFsCouponByCouponId(couponId);
+        if (coupon == null) {
+            return R.error("优惠券配置不存在");
+        }
+        if (!Integer.valueOf(5).equals(coupon.getCouponType())) {
+            return R.error("优惠券类型不正确,仅支持套餐优惠券");
+        }
+        if (coupon.getLimitTime() != null && coupon.getLimitTime().before(new Date())) {
+            return R.error("优惠券已过期");
+        }
+        FsUserCoupon userCoupon = fsUserCouponMapper.selectByCouponIdAndUserId(couponId, userId);
+        if (userCoupon == null) {
+            return R.error("该用户的优惠券不存在");
+        }
+        if (!Integer.valueOf(0).equals(userCoupon.getStatus())) {
+            return R.error("优惠券已使用或已过期");
+        }
+        return null;
+    }
+
+    private R checkInquiryCoupon(Long userCouponId, Long userId, BigDecimal money, Long companyId) {
+        if (companyId != null && companyId > 0) {
+            return R.error("此订单不能使用优惠券");
+        }
+        FsUserCoupon userCoupon = fsUserCouponMapper.selectFsUserCouponById(userCouponId);
+        if (userCoupon == null) {
+            return R.error("优惠券不存在");
+        }
+        if (!Integer.valueOf(0).equals(userCoupon.getStatus())) {
+            return R.error("优惠券已过期或已使用");
+        }
+        if (userId != null && userCoupon.getUserId() != null && !userId.equals(userCoupon.getUserId())) {
+            return R.error("该用户的优惠券不存在");
+        }
+        FsCoupon coupon = fsCouponMapper.selectFsCouponByCouponId(userCoupon.getCouponId());
+        if (coupon == null) {
+            return R.error("优惠券不存在");
+        }
+        if (Integer.valueOf(2).equals(coupon.getCouponType()) || Integer.valueOf(5).equals(coupon.getCouponType())) {
+            return R.error("此优惠券不可用于问诊订单");
+        }
+        if (Integer.valueOf(1).equals(coupon.getCouponType()) && coupon.getMinPrice() != null && coupon.getMinPrice().compareTo(money) == 1) {
+            return R.error("此优惠券不可用");
+        }
+        return null;
+    }
+
+    private BigDecimal getInquiryPrice(Long doctorId, Integer orderType) {
+        String json = configService.selectConfigByKey("his.inquiryConfig");
+        InquiryConfigDTO configDTO = JSONUtil.toBean(json, InquiryConfigDTO.class);
+
+        if (doctorId != null) {
+            FsDoctor doctor = fsDoctorMapper.selectFsDoctorByDoctorId(doctorId);
+            if (doctor == null || Integer.valueOf(0).equals(doctor.getStatus()) || !Integer.valueOf(1).equals(doctor.getWorkStatus())) {
+                return BigDecimal.ZERO;
+            }
+            if (doctor.getPriceJson() != null) {
+                List<FsPriceDTO> priceDTOList = JSONUtil.parseArray(doctor.getPriceJson()).toList(FsPriceDTO.class);
+                List<FsPriceDTO> doctorPrice = priceDTOList.stream().filter(x -> x.getType().equals(orderType)).collect(Collectors.toList());
+                if (doctorPrice.size() == 1 && doctorPrice.get(0).getPrice() != null) {
+                    return doctorPrice.get(0).getPrice();
+                }
+            }
+        }
+
+        if (configDTO != null && configDTO.getPrices() != null) {
+            List<FsPriceDTO> price = configDTO.getPrices().stream().filter(x -> x.getType().equals(orderType)).collect(Collectors.toList());
+            if (price.size() == 1 && price.get(0).getPrice() != null) {
+                return price.get(0).getPrice();
+            }
+        }
+        return BigDecimal.ZERO;
+    }
+}

+ 1 - 0
fs-service/src/main/resources/mapper/his/FsInquiryOrderMapper.xml

@@ -80,6 +80,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="auditUserId != null "> and audit_user_id = #{auditUserId}</if>
             <if test="auditTime != null "> and audit_time = #{auditTime}</if>
             <if test="isSendSms != null "> and is_send_sms = #{isSendSms}</if>
+            <if test="source != null "> and source = #{source}</if>
         </where>
     </select>
 

+ 1 - 0
fs-service/src/main/resources/mapper/his/FsPackageOrderMapper.xml

@@ -82,6 +82,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="finishTime != null "> and finish_time = #{finishTime}</if>
             <if test="companyUserId != null "> and company_user_id = #{companyUserId}</if>
             <if test="companyId != null "> and company_id = #{companyId}</if>
+            <if test="source != null "> and source = #{source}</if>
         </where>
     </select>
 

+ 141 - 0
fs-service/src/main/resources/mapper/his/FsPreOrderMapper.xml

@@ -0,0 +1,141 @@
+<?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="com.fs.his.mapper.FsPreOrderMapper">
+
+    <resultMap type="FsPreOrder" id="FsPreOrderResult">
+        <result property="preOrderId" column="pre_order_id" />
+        <result property="preOrderType" column="pre_order_type" />
+        <result property="companyId" column="company_id" />
+        <result property="companyUserId" column="company_user_id" />
+        <result property="userId" column="user_id" />
+        <result property="patientId" column="patient_id" />
+        <result property="packageId" column="package_id" />
+        <result property="couponId" column="coupon_id" />
+        <result property="payType" column="pay_type" />
+        <result property="payMoney" column="pay_money" />
+        <result property="payableAmount" column="payable_amount" />
+        <result property="addressId" column="address_id" />
+        <result property="productIds" column="product_ids" />
+        <result property="orderKey" column="order_key" />
+        <result property="title" column="title" />
+        <result property="companyUserRemark" column="company_user_remark" />
+        <result property="duration" column="duration" />
+        <result property="isVisit" column="is_visit" />
+        <result property="inquiryType" column="inquiry_type" />
+        <result property="inquirySubType" column="inquiry_sub_type" />
+        <result property="inquiryOrderType" column="inquiry_order_type" />
+        <result property="doctorId" column="doctor_id" />
+        <result property="reportImages" column="report_images" />
+        <result property="tongueImages" column="tongue_images" />
+        <result property="faceImages" column="face_images" />
+        <result property="handImages" column="hand_images" />
+        <result property="height" column="height" />
+        <result property="weight" column="weight" />
+        <result property="mobile" column="mobile" />
+        <result property="medication" column="medication" />
+        <result property="usage" column="usage" />
+        <result property="source" column="source" />
+        <result property="linkStr" column="link_str" />
+        <result property="shareLink" column="share_link" />
+        <result property="status" column="status" />
+        <result property="createTime" column="create_time" />
+        <result property="updateTime" column="update_time" />
+    </resultMap>
+
+    <select id="selectFsPreOrderById" parameterType="Long" resultMap="FsPreOrderResult">
+        select * from fs_pre_order where pre_order_id = #{preOrderId}
+    </select>
+
+    <insert id="insertFsPreOrder" parameterType="FsPreOrder" useGeneratedKeys="true" keyProperty="preOrderId">
+        insert into fs_pre_order
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="preOrderType != null">pre_order_type,</if>
+            <if test="companyId != null">company_id,</if>
+            <if test="companyUserId != null">company_user_id,</if>
+            <if test="userId != null">user_id,</if>
+            <if test="patientId != null">patient_id,</if>
+            <if test="packageId != null">package_id,</if>
+            <if test="couponId != null">coupon_id,</if>
+            <if test="payType != null">pay_type,</if>
+            <if test="payMoney != null">pay_money,</if>
+            <if test="payableAmount != null">payable_amount,</if>
+            <if test="addressId != null">address_id,</if>
+            <if test="productIds != null">product_ids,</if>
+            <if test="orderKey != null">order_key,</if>
+            <if test="title != null">title,</if>
+            <if test="companyUserRemark != null">company_user_remark,</if>
+            <if test="duration != null">duration,</if>
+            <if test="isVisit != null">is_visit,</if>
+            <if test="inquiryType != null">inquiry_type,</if>
+            <if test="inquirySubType != null">inquiry_sub_type,</if>
+            <if test="inquiryOrderType != null">inquiry_order_type,</if>
+            <if test="doctorId != null">doctor_id,</if>
+            <if test="reportImages != null">report_images,</if>
+            <if test="tongueImages != null">tongue_images,</if>
+            <if test="faceImages != null">face_images,</if>
+            <if test="handImages != null">hand_images,</if>
+            <if test="height != null">height,</if>
+            <if test="weight != null">weight,</if>
+            <if test="mobile != null">mobile,</if>
+            <if test="medication != null">medication,</if>
+            <if test="usage != null">usage,</if>
+            <if test="source != null">source,</if>
+            <if test="linkStr != null">link_str,</if>
+            <if test="shareLink != null">share_link,</if>
+            <if test="status != null">status,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="updateTime != null">update_time,</if>
+        </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="preOrderType != null">#{preOrderType},</if>
+            <if test="companyId != null">#{companyId},</if>
+            <if test="companyUserId != null">#{companyUserId},</if>
+            <if test="userId != null">#{userId},</if>
+            <if test="patientId != null">#{patientId},</if>
+            <if test="packageId != null">#{packageId},</if>
+            <if test="couponId != null">#{couponId},</if>
+            <if test="payType != null">#{payType},</if>
+            <if test="payMoney != null">#{payMoney},</if>
+            <if test="payableAmount != null">#{payableAmount},</if>
+            <if test="addressId != null">#{addressId},</if>
+            <if test="productIds != null">#{productIds},</if>
+            <if test="orderKey != null">#{orderKey},</if>
+            <if test="title != null">#{title},</if>
+            <if test="companyUserRemark != null">#{companyUserRemark},</if>
+            <if test="duration != null">#{duration},</if>
+            <if test="isVisit != null">#{isVisit},</if>
+            <if test="inquiryType != null">#{inquiryType},</if>
+            <if test="inquirySubType != null">#{inquirySubType},</if>
+            <if test="inquiryOrderType != null">#{inquiryOrderType},</if>
+            <if test="doctorId != null">#{doctorId},</if>
+            <if test="reportImages != null">#{reportImages},</if>
+            <if test="tongueImages != null">#{tongueImages},</if>
+            <if test="faceImages != null">#{faceImages},</if>
+            <if test="handImages != null">#{handImages},</if>
+            <if test="height != null">#{height},</if>
+            <if test="weight != null">#{weight},</if>
+            <if test="mobile != null">#{mobile},</if>
+            <if test="medication != null">#{medication},</if>
+            <if test="usage != null">#{usage},</if>
+            <if test="source != null">#{source},</if>
+            <if test="linkStr != null">#{linkStr},</if>
+            <if test="shareLink != null">#{shareLink},</if>
+            <if test="status != null">#{status},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+        </trim>
+    </insert>
+
+    <update id="updateFsPreOrder" parameterType="FsPreOrder">
+        update fs_pre_order
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="linkStr != null">link_str = #{linkStr},</if>
+            <if test="shareLink != null">share_link = #{shareLink},</if>
+            <if test="status != null">status = #{status},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+        </trim>
+        where pre_order_id = #{preOrderId}
+    </update>
+</mapper>

+ 8 - 0
fs-user-app/src/main/java/com/fs/app/controller/StoreOrderController.java

@@ -60,6 +60,8 @@ public class StoreOrderController extends  AppBaseController {
     private IFsCouponService couponService;
     @Autowired
     private IFsStoreOrderBillLogService orderBillLogService;
+    @Autowired
+    private  IFsPreOrderService fsPreOrderService;
     @Login
     @ApiOperation("获取我的订单列表")
     @GetMapping("/getMyStoreOrderList")
@@ -277,5 +279,11 @@ public class StoreOrderController extends  AppBaseController {
         return orderBillLogService.billBack(id);
     }
 
+    @ApiOperation("预制单信息查询")
+    @GetMapping("/preOrder/{preOrderId}")
+    public R getPreOrder(@PathVariable("preOrderId") Long preOrderId)
+    {
+        return fsPreOrderService.getPreOrder(preOrderId);
+    }
 
 }