yys 2 settimane fa
parent
commit
cc51a3b1f8
100 ha cambiato i file con 8636 aggiunte e 201 eliminazioni
  1. 15 0
      fs-admin/src/main/java/com/fs/FSApplication.java
  2. 80 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsAdvScrmBridgeController.java
  3. 80 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsMenuScrmBridgeController.java
  4. 80 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsPrescribeDrugScrmBridgeController.java
  5. 80 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsPrescribeScrmBridgeController.java
  6. 80 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsShippingTemplatesFreeScrmBridgeController.java
  7. 80 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsShippingTemplatesRegionScrmBridgeController.java
  8. 91 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsShippingTemplatesScrmBridgeController.java
  9. 91 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreActivityScrmBridgeController.java
  10. 80 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreAfterSalesItemScrmBridgeController.java
  11. 231 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreAfterSalesScrmBridgeController.java
  12. 80 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreAfterSalesStatusScrmBridgeController.java
  13. 80 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreCartScrmBridgeController.java
  14. 81 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreCouponIssueScrmBridgeController.java
  15. 80 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreCouponIssueUserScrmBridgeController.java
  16. 129 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreCouponScrmBridgeController.java
  17. 80 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreCouponUserScrmBridgeController.java
  18. 94 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreOrderAuditScrmBridgeController.java
  19. 88 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreOrderItemScrmBridgeController.java
  20. 80 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreOrderNoticeScrmBridgeController.java
  21. 132 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreOrderOfflineScrmBridgeController.java
  22. 139 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreOrderPromotionScrmBridgeController.java
  23. 1060 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreOrderScrmBridgeController.java
  24. 80 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreOrderStatusScrmBridgeController.java
  25. 80 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreProductAttrScrmBridgeController.java
  26. 80 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreProductAttrValueScrmBridgeController.java
  27. 80 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreProductCategoryScrmBridgeController.java
  28. 80 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreProductDetailsScrmBridgeController.java
  29. 115 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreProductGroupScrmBridgeController.java
  30. 59 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreProductRelationScrmBridgeController.java
  31. 93 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreProductReplyScrmBridgeController.java
  32. 101 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreProductRuleScrmBridgeController.java
  33. 80 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreProductTemplateScrmBridgeController.java
  34. 88 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreRecommendScrmBridgeController.java
  35. 80 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreShopStaffScrmBridgeController.java
  36. 80 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreVisitScrmBridgeController.java
  37. 82 0
      fs-admin/src/main/java/com/fs/admin/controller/store/FsUserPromoterApplyScrmBridgeController.java
  38. 61 0
      fs-admin/src/main/java/com/fs/admin/controller/store/SysOperlogScrmBridgeController.java
  39. 19 0
      fs-admin/src/main/java/com/fs/config/FullQualifiedBeanNameGenerator.java
  40. 30 0
      fs-admin/src/main/java/com/fs/config/OverridingBeanNameGenerator.java
  41. 3 1
      fs-admin/src/main/resources/application.yml
  42. 6 6
      fs-admin/src/main/resources/pay/wxpay.properties
  43. 2 7
      fs-ai-call-task/src/main/java/com/fs/app/task/TenantTaskRunner.java
  44. 2 7
      fs-cid-workflow/src/main/java/com/fs/app/task/TenantTaskRunner.java
  45. 6 0
      fs-company-app/src/main/java/com/fs/app/controller/AppBaseController.java
  46. 9 0
      fs-company-app/src/main/java/com/fs/app/controller/CompanyUserController.java
  47. 12 0
      fs-company-app/src/main/java/com/fs/app/controller/CrmController.java
  48. 15 0
      fs-company-app/src/main/java/com/fs/app/controller/CrmCustomerController.java
  49. 3 0
      fs-company-app/src/main/java/com/fs/app/controller/StorePaymentController.java
  50. 1 6
      fs-company-app/src/main/java/com/fs/app/controller/UserController.java
  51. 11 0
      fs-company-app/src/main/java/com/fs/app/websocket/service/WebSocketServer.java
  52. 3 13
      fs-company-app/src/main/java/com/fs/core/filter/CompanySaasContextFilter.java
  53. 33 1
      fs-company/src/main/java/com/fs/FsCompanyApplication.java
  54. 22 0
      fs-company/src/main/java/com/fs/framework/config/OverridingBeanNameGenerator.java
  55. 5 0
      fs-company/src/main/resources/application-dev.yml
  56. 6 1
      fs-company/src/main/resources/application.yml
  57. 75 8
      fs-company/src/main/resources/static/chat-aggregate.html
  58. 1 1
      fs-framework/src/main/java/com/fs/framework/config/ResourcesConfig.java
  59. 1 7
      fs-framework/src/main/java/com/fs/framework/security/filter/JwtAuthenticationTokenFilter.java
  60. 2 7
      fs-framework/src/main/java/com/fs/framework/task/TenantTaskRunner.java
  61. 89 4
      fs-framework/src/main/java/com/fs/framework/web/service/TokenService.java
  62. 1 6
      fs-live-app/src/main/java/com/fs/live/task/TenantTaskRunner.java
  63. 4 19
      fs-live-app/src/main/java/com/fs/live/websocket/auth/TenantChannelContext.java
  64. 2 7
      fs-qw-api/src/main/java/com/fs/app/qwTask/TenantTaskRunner.java
  65. 2 7
      fs-qw-task/src/main/java/com/fs/app/task/TenantTaskRunner.java
  66. 2 12
      fs-qwhook/src/main/java/com/fs/framework/filter/AppTenantSwitchFilter.java
  67. 65 0
      fs-service/pom.xml
  68. 7 81
      fs-service/src/main/java/com/fs/ad/controller/AdAccountController.java
  69. 106 0
      fs-service/src/main/java/com/fs/ad/controller/AdDomainController.java
  70. 103 0
      fs-service/src/main/java/com/fs/ad/controller/AdDyAccountController.java
  71. 114 0
      fs-service/src/main/java/com/fs/ad/controller/AdDyApiController.java
  72. 97 0
      fs-service/src/main/java/com/fs/ad/controller/AdHtmlClickLogController.java
  73. 103 0
      fs-service/src/main/java/com/fs/ad/controller/AdHtmlTemplateController.java
  74. 106 0
      fs-service/src/main/java/com/fs/ad/controller/AdIqiyiAccountController.java
  75. 109 0
      fs-service/src/main/java/com/fs/ad/controller/AdSiteController.java
  76. 97 0
      fs-service/src/main/java/com/fs/ad/controller/AdUploadLogController.java
  77. 106 0
      fs-service/src/main/java/com/fs/ad/controller/AdYoukuAccountController.java
  78. 141 0
      fs-service/src/main/java/com/fs/ad/controller/BdAccountController.java
  79. 216 0
      fs-service/src/main/java/com/fs/ad/controller/MockAppController.java
  80. 84 0
      fs-service/src/main/java/com/fs/ad/controller/StatisticsController.java
  81. 26 0
      fs-service/src/main/java/com/fs/ad/controller/task/BaiduTask.java
  82. 43 0
      fs-service/src/main/java/com/fs/admin/controller/AdminAdController.java
  83. 73 0
      fs-service/src/main/java/com/fs/admin/controller/AdminCommissionRecordController.java
  84. 299 0
      fs-service/src/main/java/com/fs/admin/controller/AdminCompanyBridgeController.java
  85. 130 0
      fs-service/src/main/java/com/fs/admin/controller/AdminConsumeRecordController.java
  86. 104 0
      fs-service/src/main/java/com/fs/admin/controller/AdminCourseBridgeController.java
  87. 43 0
      fs-service/src/main/java/com/fs/admin/controller/AdminCrmController.java
  88. 134 0
      fs-service/src/main/java/com/fs/admin/controller/AdminHisBridgeController.java
  89. 72 0
      fs-service/src/main/java/com/fs/admin/controller/AdminLiveBridgeController.java
  90. 43 0
      fs-service/src/main/java/com/fs/admin/controller/AdminLiveVideoController.java
  91. 136 0
      fs-service/src/main/java/com/fs/admin/controller/AdminLobsterBridgeController.java
  92. 114 0
      fs-service/src/main/java/com/fs/admin/controller/AdminMiscBridge2Controller.java
  93. 99 0
      fs-service/src/main/java/com/fs/admin/controller/AdminMissingStubsController.java
  94. 84 0
      fs-service/src/main/java/com/fs/admin/controller/AdminModuleUsageController.java
  95. 103 0
      fs-service/src/main/java/com/fs/admin/controller/AdminProxyController.java
  96. 123 0
      fs-service/src/main/java/com/fs/admin/controller/AdminRechargeRecordController.java
  97. 70 0
      fs-service/src/main/java/com/fs/admin/controller/AdminServiceCostController.java
  98. 64 0
      fs-service/src/main/java/com/fs/admin/controller/AdminSopController.java
  99. 397 0
      fs-service/src/main/java/com/fs/admin/controller/AdminStatisticsController.java
  100. 308 0
      fs-service/src/main/java/com/fs/admin/controller/AdminStoreMiscController.java

+ 15 - 0
fs-admin/src/main/java/com/fs/FSApplication.java

@@ -1,8 +1,11 @@
 package com.fs;
 package com.fs;
 
 
+import com.fs.config.OverridingBeanNameGenerator;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.FilterType;
 import org.springframework.scheduling.annotation.EnableAsync;
 import org.springframework.scheduling.annotation.EnableAsync;
 import org.springframework.scheduling.annotation.EnableScheduling;
 import org.springframework.scheduling.annotation.EnableScheduling;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.transaction.annotation.Transactional;
@@ -11,6 +14,18 @@ import org.springframework.transaction.annotation.Transactional;
  * 启动程序
  * 启动程序
  */
  */
 @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
 @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
+@ComponentScan(
+    basePackages = "com.fs",
+    nameGenerator = OverridingBeanNameGenerator.class,
+    excludeFilters = {
+        @ComponentScan.Filter(type = FilterType.REGEX, pattern = {
+            "com\\.fs\\.framework\\.service\\.PermissionService",
+            "com\\.fs\\.framework\\.service\\.UserDetailsServiceImpl",
+            "com\\.fs\\.company\\.controller\\..*",
+            "com\\.fs\\.hisStore\\.controller\\..*"
+        })
+    }
+)
 @Transactional
 @Transactional
 @EnableAsync
 @EnableAsync
 @EnableScheduling
 @EnableScheduling

+ 80 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsAdvScrmBridgeController.java

@@ -0,0 +1,80 @@
+package com.fs.admin.controller.store;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.FsAdvScrm;
+import com.fs.hisStore.service.IFsAdvScrmService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 广告 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsAdvController,供平台总后台跨租户管理
+ *
+ * @author fs
+ * @date 2023-06-08
+ */
+@RestController
+@RequestMapping("/store/store/adv")
+public class FsAdvScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsAdvScrmService fsAdvService;
+
+    @PreAuthorize("@ss.hasPermi('store:adv:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsAdvScrm fsAdv)
+    {
+        startPage();
+        List<FsAdvScrm> list = fsAdvService.selectFsAdvList(fsAdv);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:adv:export')")
+    @Log(title = "广告", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsAdvScrm fsAdv)
+    {
+        List<FsAdvScrm> list = fsAdvService.selectFsAdvList(fsAdv);
+        ExcelUtil<FsAdvScrm> util = new ExcelUtil<FsAdvScrm>(FsAdvScrm.class);
+        return util.exportExcel(list, "广告数据");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:adv:query')")
+    @GetMapping(value = "/{advId}")
+    public AjaxResult getInfo(@PathVariable("advId") Long advId)
+    {
+        return AjaxResult.success(fsAdvService.selectFsAdvById(advId));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:adv:add')")
+    @Log(title = "广告", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsAdvScrm fsAdv)
+    {
+        return toAjax(fsAdvService.insertFsAdv(fsAdv));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:adv:edit')")
+    @Log(title = "广告", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsAdvScrm fsAdv)
+    {
+        return toAjax(fsAdvService.updateFsAdv(fsAdv));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:adv:remove')")
+    @Log(title = "广告", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{advIds}")
+    public AjaxResult remove(@PathVariable Long[] advIds)
+    {
+        return toAjax(fsAdvService.deleteFsAdvByIds(advIds));
+    }
+}

+ 80 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsMenuScrmBridgeController.java

@@ -0,0 +1,80 @@
+package com.fs.admin.controller.store;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.FsMenuScrm;
+import com.fs.hisStore.service.IFsMenuScrmService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 用户端菜单管理 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsMenuScrmController,供平台总后台跨租户管理
+ *
+ * @author fs
+ * @date 2022-03-15
+ */
+@RestController
+@RequestMapping("/store/store/menu")
+public class FsMenuScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsMenuScrmService fsMenuService;
+
+    @PreAuthorize("@ss.hasPermi('store:menu:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsMenuScrm fsMenu)
+    {
+        startPage();
+        List<FsMenuScrm> list = fsMenuService.selectFsMenuList(fsMenu);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:menu:export')")
+    @Log(title = "用户端菜单管理", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsMenuScrm fsMenu)
+    {
+        List<FsMenuScrm> list = fsMenuService.selectFsMenuList(fsMenu);
+        ExcelUtil<FsMenuScrm> util = new ExcelUtil<FsMenuScrm>(FsMenuScrm.class);
+        return util.exportExcel(list, "menu");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:menu:query')")
+    @GetMapping(value = "/{menuId}")
+    public AjaxResult getInfo(@PathVariable("menuId") Long menuId)
+    {
+        return AjaxResult.success(fsMenuService.selectFsMenuById(menuId));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:menu:add')")
+    @Log(title = "用户端菜单管理", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsMenuScrm fsMenu)
+    {
+        return toAjax(fsMenuService.insertFsMenu(fsMenu));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:menu:edit')")
+    @Log(title = "用户端菜单管理", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsMenuScrm fsMenu)
+    {
+        return toAjax(fsMenuService.updateFsMenu(fsMenu));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:menu:remove')")
+    @Log(title = "用户端菜单管理", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{menuIds}")
+    public AjaxResult remove(@PathVariable Long[] menuIds)
+    {
+        return toAjax(fsMenuService.deleteFsMenuByIds(menuIds));
+    }
+}

+ 80 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsPrescribeDrugScrmBridgeController.java

@@ -0,0 +1,80 @@
+package com.fs.admin.controller.store;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.FsPrescribeDrugScrm;
+import com.fs.hisStore.service.IFsPrescribeDrugScrmService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 处方药品 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsPrescribeDrugScrmController,供平台总后台跨租户管理
+ *
+ * @author fs
+ * @date 2022-03-15
+ */
+@RestController
+@RequestMapping("/store/store/prescribeDrug")
+public class FsPrescribeDrugScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsPrescribeDrugScrmService fsPrescribeDrugService;
+
+    @PreAuthorize("@ss.hasPermi('store:prescribeDrug:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsPrescribeDrugScrm fsPrescribeDrug)
+    {
+        startPage();
+        List<FsPrescribeDrugScrm> list = fsPrescribeDrugService.selectFsPrescribeDrugList(fsPrescribeDrug);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:prescribeDrug:export')")
+    @Log(title = "处方药品", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsPrescribeDrugScrm fsPrescribeDrug)
+    {
+        List<FsPrescribeDrugScrm> list = fsPrescribeDrugService.selectFsPrescribeDrugList(fsPrescribeDrug);
+        ExcelUtil<FsPrescribeDrugScrm> util = new ExcelUtil<FsPrescribeDrugScrm>(FsPrescribeDrugScrm.class);
+        return util.exportExcel(list, "prescribeDrug");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:prescribeDrug:query')")
+    @GetMapping(value = "/{drugId}")
+    public AjaxResult getInfo(@PathVariable("drugId") Long drugId)
+    {
+        return AjaxResult.success(fsPrescribeDrugService.selectFsPrescribeDrugById(drugId));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:prescribeDrug:add')")
+    @Log(title = "处方药品", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsPrescribeDrugScrm fsPrescribeDrug)
+    {
+        return toAjax(fsPrescribeDrugService.insertFsPrescribeDrug(fsPrescribeDrug));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:prescribeDrug:edit')")
+    @Log(title = "处方药品", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsPrescribeDrugScrm fsPrescribeDrug)
+    {
+        return toAjax(fsPrescribeDrugService.updateFsPrescribeDrug(fsPrescribeDrug));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:prescribeDrug:remove')")
+    @Log(title = "处方药品", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{drugIds}")
+    public AjaxResult remove(@PathVariable Long[] drugIds)
+    {
+        return toAjax(fsPrescribeDrugService.deleteFsPrescribeDrugByIds(drugIds));
+    }
+}

+ 80 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsPrescribeScrmBridgeController.java

@@ -0,0 +1,80 @@
+package com.fs.admin.controller.store;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.FsPrescribeScrm;
+import com.fs.hisStore.service.IFsPrescribeScrmService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 处方 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsPrescribeScrmController,供平台总后台跨租户管理
+ *
+ * @author fs
+ * @date 2022-03-15
+ */
+@RestController
+@RequestMapping("/store/store/prescribe")
+public class FsPrescribeScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsPrescribeScrmService fsPrescribeService;
+
+    @PreAuthorize("@ss.hasPermi('store:prescribe:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsPrescribeScrm fsPrescribe)
+    {
+        startPage();
+        List<FsPrescribeScrm> list = fsPrescribeService.selectFsPrescribeList(fsPrescribe);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:prescribe:export')")
+    @Log(title = "处方", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsPrescribeScrm fsPrescribe)
+    {
+        List<FsPrescribeScrm> list = fsPrescribeService.selectFsPrescribeList(fsPrescribe);
+        ExcelUtil<FsPrescribeScrm> util = new ExcelUtil<FsPrescribeScrm>(FsPrescribeScrm.class);
+        return util.exportExcel(list, "处方数据");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:prescribe:query')")
+    @GetMapping(value = "/{prescribeId}")
+    public AjaxResult getInfo(@PathVariable("prescribeId") Long prescribeId)
+    {
+        return AjaxResult.success(fsPrescribeService.selectFsPrescribeById(prescribeId));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:prescribe:add')")
+    @Log(title = "处方", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsPrescribeScrm fsPrescribe)
+    {
+        return toAjax(fsPrescribeService.insertFsPrescribe(fsPrescribe));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:prescribe:edit')")
+    @Log(title = "处方", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsPrescribeScrm fsPrescribe)
+    {
+        return toAjax(fsPrescribeService.updateFsPrescribe(fsPrescribe));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:prescribe:remove')")
+    @Log(title = "处方", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{prescribeIds}")
+    public AjaxResult remove(@PathVariable Long[] prescribeIds)
+    {
+        return toAjax(fsPrescribeService.deleteFsPrescribeByIds(prescribeIds));
+    }
+}

+ 80 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsShippingTemplatesFreeScrmBridgeController.java

@@ -0,0 +1,80 @@
+package com.fs.admin.controller.store;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.FsShippingTemplatesFreeScrm;
+import com.fs.hisStore.service.IFsShippingTemplatesFreeScrmService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 免邮费 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsShippingTemplatesFreeScrmController,供平台总后台跨租户管理
+ *
+ * @author fs
+ * @date 2022-03-15
+ */
+@RestController
+@RequestMapping("/store/store/shippingTemplatesFree")
+public class FsShippingTemplatesFreeScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsShippingTemplatesFreeScrmService fsShippingTemplatesFreeService;
+
+    @PreAuthorize("@ss.hasPermi('store:shippingTemplatesFree:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsShippingTemplatesFreeScrm fsShippingTemplatesFree)
+    {
+        startPage();
+        List<FsShippingTemplatesFreeScrm> list = fsShippingTemplatesFreeService.selectFsShippingTemplatesFreeList(fsShippingTemplatesFree);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:shippingTemplatesFree:export')")
+    @Log(title = "免邮费", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsShippingTemplatesFreeScrm fsShippingTemplatesFree)
+    {
+        List<FsShippingTemplatesFreeScrm> list = fsShippingTemplatesFreeService.selectFsShippingTemplatesFreeList(fsShippingTemplatesFree);
+        ExcelUtil<FsShippingTemplatesFreeScrm> util = new ExcelUtil<FsShippingTemplatesFreeScrm>(FsShippingTemplatesFreeScrm.class);
+        return util.exportExcel(list, "shippingTemplatesFree");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:shippingTemplatesFree:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsShippingTemplatesFreeService.selectFsShippingTemplatesFreeById(id));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:shippingTemplatesFree:add')")
+    @Log(title = "免邮费", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsShippingTemplatesFreeScrm fsShippingTemplatesFree)
+    {
+        return toAjax(fsShippingTemplatesFreeService.insertFsShippingTemplatesFree(fsShippingTemplatesFree));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:shippingTemplatesFree:edit')")
+    @Log(title = "免邮费", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsShippingTemplatesFreeScrm fsShippingTemplatesFree)
+    {
+        return toAjax(fsShippingTemplatesFreeService.updateFsShippingTemplatesFree(fsShippingTemplatesFree));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:shippingTemplatesFree:remove')")
+    @Log(title = "免邮费", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsShippingTemplatesFreeService.deleteFsShippingTemplatesFreeByIds(ids));
+    }
+}

+ 80 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsShippingTemplatesRegionScrmBridgeController.java

@@ -0,0 +1,80 @@
+package com.fs.admin.controller.store;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.FsShippingTemplatesRegionScrm;
+import com.fs.hisStore.service.IFsShippingTemplatesRegionScrmService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 邮费区域 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsShippingTemplatesRegionScrmController,供平台总后台跨租户管理
+ *
+ * @author fs
+ * @date 2022-03-15
+ */
+@RestController
+@RequestMapping("/store/store/shippingTemplatesRegion")
+public class FsShippingTemplatesRegionScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsShippingTemplatesRegionScrmService fsShippingTemplatesRegionService;
+
+    @PreAuthorize("@ss.hasPermi('store:shippingTemplatesRegion:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsShippingTemplatesRegionScrm fsShippingTemplatesRegion)
+    {
+        startPage();
+        List<FsShippingTemplatesRegionScrm> list = fsShippingTemplatesRegionService.selectFsShippingTemplatesRegionList(fsShippingTemplatesRegion);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:shippingTemplatesRegion:export')")
+    @Log(title = "邮费区域", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsShippingTemplatesRegionScrm fsShippingTemplatesRegion)
+    {
+        List<FsShippingTemplatesRegionScrm> list = fsShippingTemplatesRegionService.selectFsShippingTemplatesRegionList(fsShippingTemplatesRegion);
+        ExcelUtil<FsShippingTemplatesRegionScrm> util = new ExcelUtil<FsShippingTemplatesRegionScrm>(FsShippingTemplatesRegionScrm.class);
+        return util.exportExcel(list, "shippingTemplatesRegion");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:shippingTemplatesRegion:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsShippingTemplatesRegionService.selectFsShippingTemplatesRegionById(id));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:shippingTemplatesRegion:add')")
+    @Log(title = "邮费区域", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsShippingTemplatesRegionScrm fsShippingTemplatesRegion)
+    {
+        return toAjax(fsShippingTemplatesRegionService.insertFsShippingTemplatesRegion(fsShippingTemplatesRegion));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:shippingTemplatesRegion:edit')")
+    @Log(title = "邮费区域", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsShippingTemplatesRegionScrm fsShippingTemplatesRegion)
+    {
+        return toAjax(fsShippingTemplatesRegionService.updateFsShippingTemplatesRegion(fsShippingTemplatesRegion));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:shippingTemplatesRegion:remove')")
+    @Log(title = "邮费区域", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsShippingTemplatesRegionService.deleteFsShippingTemplatesRegionByIds(ids));
+    }
+}

+ 91 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsShippingTemplatesScrmBridgeController.java

@@ -0,0 +1,91 @@
+package com.fs.admin.controller.store;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.FsShippingTemplatesScrm;
+import com.fs.hisStore.param.FsShippingTemplatesAddEditParam;
+import com.fs.hisStore.service.IFsShippingTemplatesScrmService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 运费模板 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsShippingTemplatesScrmController,供平台总后台跨租户管理
+ *
+ * @author fs
+ * @date 2022-03-15
+ */
+@RestController
+@RequestMapping("/store/store/shippingTemplates")
+public class FsShippingTemplatesScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsShippingTemplatesScrmService fsShippingTemplatesService;
+
+    @PreAuthorize("@ss.hasPermi('store:shippingTemplates:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsShippingTemplatesScrm fsShippingTemplates)
+    {
+        startPage();
+        fsShippingTemplates.setIsDel(0);
+        List<FsShippingTemplatesScrm> list = fsShippingTemplatesService.selectFsShippingTemplatesList(fsShippingTemplates);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:shippingTemplates:export')")
+    @Log(title = "运费模板", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsShippingTemplatesScrm fsShippingTemplates)
+    {
+        List<FsShippingTemplatesScrm> list = fsShippingTemplatesService.selectFsShippingTemplatesList(fsShippingTemplates);
+        ExcelUtil<FsShippingTemplatesScrm> util = new ExcelUtil<FsShippingTemplatesScrm>(FsShippingTemplatesScrm.class);
+        return util.exportExcel(list, "shippingTemplates");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:shippingTemplates:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsShippingTemplatesService.selectFsShippingTemplatesById(id));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:shippingTemplates:add')")
+    @Log(title = "运费模板", businessType = BusinessType.INSERT)
+    @PostMapping
+    public R add(@RequestBody FsShippingTemplatesAddEditParam param)
+    {
+        return fsShippingTemplatesService.addOrEdit(param);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:shippingTemplates:edit')")
+    @Log(title = "运费模板", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public R edit(@RequestBody FsShippingTemplatesAddEditParam param)
+    {
+        return fsShippingTemplatesService.addOrEdit(param);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:shippingTemplates:remove')")
+    @Log(title = "运费模板", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsShippingTemplatesService.deleteFsShippingTemplatesByIds(ids));
+    }
+
+    @GetMapping("/getAllList")
+    public R getAllList(FsShippingTemplatesScrm fsShippingTemplates)
+    {
+        fsShippingTemplates.setIsDel(0);
+        List<FsShippingTemplatesScrm> list = fsShippingTemplatesService.selectFsShippingTemplatesList(fsShippingTemplates);
+        return R.ok().put("data", list);
+    }
+}

+ 91 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreActivityScrmBridgeController.java

@@ -0,0 +1,91 @@
+package com.fs.admin.controller.store;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.FsStoreActivityScrm;
+import com.fs.hisStore.service.IFsStoreActivityScrmService;
+import com.fs.hisStore.service.IFsStoreProductScrmService;
+import com.fs.hisStore.vo.FsStoreProductActivityListVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 活动 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsStoreActivityScrmController,供平台总后台跨租户管理
+ *
+ * @author fs
+ * @date 2022-11-18
+ */
+@RestController
+@RequestMapping("/store/storeActivity")
+public class FsStoreActivityScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsStoreActivityScrmService fsStoreActivityService;
+    @Autowired
+    private IFsStoreProductScrmService productService;
+
+    @PreAuthorize("@ss.hasPermi('store:storeActivity:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsStoreActivityScrm fsStoreActivity)
+    {
+        startPage();
+        List<FsStoreActivityScrm> list = fsStoreActivityService.selectFsStoreActivityList(fsStoreActivity);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeActivity:export')")
+    @Log(title = "活动", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsStoreActivityScrm fsStoreActivity)
+    {
+        List<FsStoreActivityScrm> list = fsStoreActivityService.selectFsStoreActivityList(fsStoreActivity);
+        ExcelUtil<FsStoreActivityScrm> util = new ExcelUtil<FsStoreActivityScrm>(FsStoreActivityScrm.class);
+        return util.exportExcel(list, "storeActivity");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeActivity:query')")
+    @GetMapping(value = "/{activityId}")
+    public R getInfo(@PathVariable("activityId") Long activityId)
+    {
+        FsStoreActivityScrm activity = fsStoreActivityService.selectFsStoreActivityById(activityId);
+        List<FsStoreProductActivityListVO> products = new ArrayList<>();
+        if (activity.getProductIds() != null) {
+            products = productService.selectFsStoreProductByIds(activity.getProductIds());
+        }
+        return R.ok().put("activity", activity).put("products", products);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeActivity:add')")
+    @Log(title = "活动", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsStoreActivityScrm fsStoreActivity)
+    {
+        return toAjax(fsStoreActivityService.insertFsStoreActivity(fsStoreActivity));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeActivity:edit')")
+    @Log(title = "活动", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsStoreActivityScrm fsStoreActivity)
+    {
+        return toAjax(fsStoreActivityService.updateFsStoreActivity(fsStoreActivity));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeActivity:remove')")
+    @Log(title = "活动", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{activityIds}")
+    public AjaxResult remove(@PathVariable Long[] activityIds)
+    {
+        return toAjax(fsStoreActivityService.deleteFsStoreActivityByIds(activityIds));
+    }
+}

+ 80 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreAfterSalesItemScrmBridgeController.java

@@ -0,0 +1,80 @@
+package com.fs.admin.controller.store;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.FsStoreAfterSalesItemScrm;
+import com.fs.hisStore.service.IFsStoreAfterSalesItemScrmService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 售后子 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsStoreAfterSalesItemScrmController,供平台总后台跨租户管理
+ *
+ * @author fs
+ * @date 2022-03-15
+ */
+@RestController
+@RequestMapping("/store/store/storeAfterSalesItem")
+public class FsStoreAfterSalesItemScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsStoreAfterSalesItemScrmService fsStoreAfterSalesItemService;
+
+    @PreAuthorize("@ss.hasPermi('store:storeAfterSalesItem:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsStoreAfterSalesItemScrm fsStoreAfterSalesItem)
+    {
+        startPage();
+        List<FsStoreAfterSalesItemScrm> list = fsStoreAfterSalesItemService.selectFsStoreAfterSalesItemList(fsStoreAfterSalesItem);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeAfterSalesItem:export')")
+    @Log(title = "售后子", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsStoreAfterSalesItemScrm fsStoreAfterSalesItem)
+    {
+        List<FsStoreAfterSalesItemScrm> list = fsStoreAfterSalesItemService.selectFsStoreAfterSalesItemList(fsStoreAfterSalesItem);
+        ExcelUtil<FsStoreAfterSalesItemScrm> util = new ExcelUtil<FsStoreAfterSalesItemScrm>(FsStoreAfterSalesItemScrm.class);
+        return util.exportExcel(list, "storeAfterSalesItem");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeAfterSalesItem:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsStoreAfterSalesItemService.selectFsStoreAfterSalesItemById(id));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeAfterSalesItem:add')")
+    @Log(title = "售后子", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsStoreAfterSalesItemScrm fsStoreAfterSalesItem)
+    {
+        return toAjax(fsStoreAfterSalesItemService.insertFsStoreAfterSalesItem(fsStoreAfterSalesItem));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeAfterSalesItem:edit')")
+    @Log(title = "售后子", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsStoreAfterSalesItemScrm fsStoreAfterSalesItem)
+    {
+        return toAjax(fsStoreAfterSalesItemService.updateFsStoreAfterSalesItem(fsStoreAfterSalesItem));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeAfterSalesItem:remove')")
+    @Log(title = "售后子", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsStoreAfterSalesItemService.deleteFsStoreAfterSalesItemByIds(ids));
+    }
+}

+ 231 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreAfterSalesScrmBridgeController.java

@@ -0,0 +1,231 @@
+package com.fs.admin.controller.store;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ParseUtils;
+import com.fs.common.utils.StringUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.config.saas.ProjectConfig;
+import com.fs.framework.security.LoginUser;
+import com.fs.framework.security.SecurityUtils;
+import com.fs.his.domain.FsUser;
+import com.fs.his.service.IFsUserService;
+import com.fs.hisStore.domain.FsStoreAfterSalesItemScrm;
+import com.fs.hisStore.domain.FsStoreAfterSalesScrm;
+import com.fs.hisStore.domain.FsStoreAfterSalesStatusScrm;
+import com.fs.hisStore.domain.FsStoreOrderScrm;
+import com.fs.hisStore.param.FsStoreAfterSalesAudit1Param;
+import com.fs.hisStore.param.FsStoreAfterSalesAudit2Param;
+import com.fs.hisStore.param.FsStoreAfterSalesCancelParam;
+import com.fs.hisStore.param.FsStoreAfterSalesRefundParam;
+import com.fs.hisStore.service.IFsStoreAfterSalesItemScrmService;
+import com.fs.hisStore.service.IFsStoreAfterSalesScrmService;
+import com.fs.hisStore.service.IFsStoreAfterSalesStatusScrmService;
+import com.fs.hisStore.service.IFsStoreOrderScrmService;
+import com.fs.hisStore.vo.FsStoreAfterSalesVO;
+import com.fs.hisStore.vo.FsStoreOrderItemExportRefundZMVO;
+import com.fs.system.mapper.SysConfigMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.math.BigDecimal;
+import java.text.ParseException;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * 售后记录 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsStoreAfterSalesScrmController,供平台总后台跨租户管理
+ *
+ * @author fs
+ * @date 2022-03-15
+ */
+@RestController
+@RequestMapping("/store/store/storeAfterSales")
+public class FsStoreAfterSalesScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsStoreOrderScrmService fsStoreOrderService;
+    @Autowired
+    private IFsUserService userService;
+    @Autowired
+    private IFsStoreAfterSalesScrmService fsStoreAfterSalesService;
+    @Autowired
+    private IFsStoreAfterSalesItemScrmService fsStoreAfterSalesItemService;
+    @Autowired
+    private IFsStoreAfterSalesStatusScrmService storeAfterSalesStatusService;
+    @Autowired
+    private SysConfigMapper sysConfigMapper;
+
+    @PreAuthorize("@ss.hasPermi('store:storeAfterSales:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsStoreAfterSalesScrm fsStoreAfterSales)
+    {
+        startPage();
+        List<FsStoreAfterSalesVO> list = fsStoreAfterSalesService.selectFsStoreAfterSalesListVO(fsStoreAfterSales);
+        for (FsStoreAfterSalesVO vo : list) {
+            vo.setUserPhone(ParseUtils.parsePhone(vo.getUserPhone()));
+        }
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeAfterSales:export')")
+    @Log(title = "售后记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsStoreAfterSalesScrm fsStoreAfterSales)
+    {
+        if (StringUtils.isNotEmpty(fsStoreAfterSales.getBeginTime()) && StringUtils.isNotEmpty(fsStoreAfterSales.getEndTime())) {
+            fsStoreAfterSales.setBeginTime(null);
+            fsStoreAfterSales.setEndTime(null);
+        }
+        if (fsStoreAfterSalesService.isEntityNull(fsStoreAfterSales) && Objects.isNull(fsStoreAfterSales.getParams())) {
+            return AjaxResult.error("请筛选数据导出");
+        }
+
+        List<FsStoreAfterSalesVO> list = fsStoreAfterSalesService.selectFsStoreAfterSalesListVOExport(fsStoreAfterSales);
+        if ("北京卓美".equals(ProjectConfig.getFromDB(sysConfigMapper).getCloudHost().getCompanyName())) {
+            List<FsStoreOrderItemExportRefundZMVO> zmvoList = list.stream()
+                    .map(vo -> {
+                        FsStoreOrderItemExportRefundZMVO zmvo = new FsStoreOrderItemExportRefundZMVO();
+                        try {
+                            zmvo.setPayCode(vo.getPayCode());
+                            zmvo.setOrderCode(vo.getOrderCode());
+                            zmvo.setStatus(vo.getOrderStatus().toString());
+                            zmvo.setUserId(vo.getUserId());
+                            zmvo.setProductName(vo.getProductName());
+                            zmvo.setBarCode(vo.getProductBarCode());
+                            zmvo.setSku(vo.getSku());
+                            zmvo.setNum(vo.getNum());
+                            zmvo.setPrice(vo.getPrice());
+                            zmvo.setCost(vo.getCost());
+                            zmvo.setPayMoney(vo.getPayMoney());
+                            zmvo.setPayPostage(vo.getTotalPostage());
+                            zmvo.setCateName(vo.getCateName());
+                            zmvo.setRealName(vo.getUserName());
+                            zmvo.setUserPhone(vo.getUserPhone());
+                            zmvo.setUserAddress(vo.getUserAddress());
+                            zmvo.setCreateTime(vo.getOrderCreateTime());
+                            zmvo.setPayTime(vo.getOrderPayTime());
+                            zmvo.setDeliverySn(vo.getOrderDeliverySn());
+                            zmvo.setDeliveryName(vo.getOrderDeliveryName());
+                            zmvo.setDeliveryId(vo.getOrderDeliveryId());
+                            zmvo.setCompanyName(vo.getCompanyName());
+                            zmvo.setCompanyUserNickName(vo.getCompanyUserNickName());
+                            zmvo.setRefundTime(vo.getCreateTime());
+                            zmvo.setRefundMoney(vo.getRefundAmount());
+                            zmvo.setBankTransactionId(vo.getBankTransactionId());
+                            zmvo.setReasons(vo.getReasons());
+                            zmvo.setExplains(vo.getExplains());
+                        } catch (Exception e) {
+                            e.printStackTrace();
+                        }
+                        return zmvo;
+                    })
+                    .collect(Collectors.toList());
+            for (FsStoreOrderItemExportRefundZMVO vo : zmvoList) {
+                vo.setUserPhone(ParseUtils.parsePhone(vo.getUserPhone()));
+            }
+            ExcelUtil<FsStoreOrderItemExportRefundZMVO> util = new ExcelUtil<FsStoreOrderItemExportRefundZMVO>(FsStoreOrderItemExportRefundZMVO.class);
+            return util.exportExcel(zmvoList, "退款订单导出");
+        }
+        for (FsStoreAfterSalesVO vo : list) {
+            vo.setUserPhone(ParseUtils.parsePhone(vo.getUserPhone()));
+        }
+        ExcelUtil<FsStoreAfterSalesVO> util = new ExcelUtil<FsStoreAfterSalesVO>(FsStoreAfterSalesVO.class);
+        return util.exportExcel(list, "退款订单导出");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeAfterSales:query')")
+    @GetMapping(value = "/{id}")
+    public R getInfo(@PathVariable("id") Long id)
+    {
+        FsStoreAfterSalesScrm afterSales = fsStoreAfterSalesService.selectFsStoreAfterSalesById(id);
+        FsStoreAfterSalesItemScrm map = new FsStoreAfterSalesItemScrm();
+        map.setStoreAfterSalesId(id);
+        List<FsStoreAfterSalesItemScrm> items = fsStoreAfterSalesItemService.selectFsStoreAfterSalesItemList(map);
+        FsStoreAfterSalesStatusScrm statusMap = new FsStoreAfterSalesStatusScrm();
+        statusMap.setStoreAfterSalesId(id);
+        List<FsStoreAfterSalesStatusScrm> logs = storeAfterSalesStatusService.selectFsStoreAfterSalesStatusList(statusMap);
+        FsUser user = userService.selectFsUserById(afterSales.getUserId());
+        user.setPhone(ParseUtils.parsePhone(user.getPhone()));
+        FsStoreOrderScrm order = fsStoreOrderService.selectFsStoreOrderByOrderCode(afterSales.getOrderCode());
+        return R.ok().put("afterSales", afterSales).put("items", items).put("logs", logs).put("user", user).put("order", order);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeAfterSales:add')")
+    @Log(title = "售后记录", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsStoreAfterSalesScrm fsStoreAfterSales)
+    {
+        return toAjax(fsStoreAfterSalesService.insertFsStoreAfterSales(fsStoreAfterSales));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeAfterSales:edit')")
+    @Log(title = "售后记录", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsStoreAfterSalesScrm fsStoreAfterSales)
+    {
+        if ((!"".equals(fsStoreAfterSales.getDeliveryName()) && !"".equals(fsStoreAfterSales.getDeliverySn())) || (fsStoreAfterSales.getDeliveryName() == null && fsStoreAfterSales.getDeliverySn() == null)) {
+            fsStoreAfterSales.setStatus(2);
+        }
+        return toAjax(fsStoreAfterSalesService.updateDelivery(fsStoreAfterSales));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeAfterSales:remove')")
+    @Log(title = "售后记录", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsStoreAfterSalesService.deleteFsStoreAfterSalesByIds(ids));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeAfterSales:audit1')")
+    @PostMapping("/audit1")
+    public R audit1(@RequestBody FsStoreAfterSalesAudit1Param param)
+    {
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        param.setOperator(loginUser.getCompanyUser().getNickName());
+        return fsStoreAfterSalesService.audit1(param);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeAfterSales:audit2')")
+    @PostMapping("/audit2")
+    public R audit2(@RequestBody FsStoreAfterSalesAudit2Param param)
+    {
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        param.setOperator(loginUser.getCompanyUser().getNickName());
+        return fsStoreAfterSalesService.audit2(param);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeAfterSales:refund')")
+    @PostMapping("/refund")
+    public R refund(@RequestBody FsStoreAfterSalesRefundParam param)
+    {
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        param.setOperator(loginUser.getCompanyUser().getNickName());
+        return fsStoreAfterSalesService.refundMoney(param);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeAfterSales:cancel')")
+    @PostMapping("/cancel")
+    public R cancel(@RequestBody FsStoreAfterSalesCancelParam param) throws ParseException
+    {
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        param.setOperator(loginUser.getCompanyUser().getNickName());
+        return fsStoreAfterSalesService.cancel(param);
+    }
+
+    @GetMapping("/getStoreAfterSales")
+    public R getStoreAfterSales(@RequestParam("orderCode") String orderCode)
+    {
+        List<FsStoreAfterSalesVO> vo = fsStoreAfterSalesService.selectFsStoreAfterSalesVOByOrderCode(orderCode);
+        return R.ok().put("data", vo);
+    }
+}

+ 80 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreAfterSalesStatusScrmBridgeController.java

@@ -0,0 +1,80 @@
+package com.fs.admin.controller.store;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.FsStoreAfterSalesStatusScrm;
+import com.fs.hisStore.service.IFsStoreAfterSalesStatusScrmService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 售后订单操作 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsStoreAfterSalesStatusScrmController,供平台总后台跨租户管理
+ *
+ * @author fs
+ * @date 2022-03-15
+ */
+@RestController
+@RequestMapping("/store/store/storeAfterSalesStatus")
+public class FsStoreAfterSalesStatusScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsStoreAfterSalesStatusScrmService fsStoreAfterSalesStatusService;
+
+    @PreAuthorize("@ss.hasPermi('store:storeAfterSalesStatus:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsStoreAfterSalesStatusScrm fsStoreAfterSalesStatus)
+    {
+        startPage();
+        List<FsStoreAfterSalesStatusScrm> list = fsStoreAfterSalesStatusService.selectFsStoreAfterSalesStatusList(fsStoreAfterSalesStatus);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeAfterSalesStatus:export')")
+    @Log(title = "售后订单操作", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsStoreAfterSalesStatusScrm fsStoreAfterSalesStatus)
+    {
+        List<FsStoreAfterSalesStatusScrm> list = fsStoreAfterSalesStatusService.selectFsStoreAfterSalesStatusList(fsStoreAfterSalesStatus);
+        ExcelUtil<FsStoreAfterSalesStatusScrm> util = new ExcelUtil<FsStoreAfterSalesStatusScrm>(FsStoreAfterSalesStatusScrm.class);
+        return util.exportExcel(list, "storeAfterSalesStatus");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeAfterSalesStatus:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsStoreAfterSalesStatusService.selectFsStoreAfterSalesStatusById(id));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeAfterSalesStatus:add')")
+    @Log(title = "售后订单操作", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsStoreAfterSalesStatusScrm fsStoreAfterSalesStatus)
+    {
+        return toAjax(fsStoreAfterSalesStatusService.insertFsStoreAfterSalesStatus(fsStoreAfterSalesStatus));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeAfterSalesStatus:edit')")
+    @Log(title = "售后订单操作", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsStoreAfterSalesStatusScrm fsStoreAfterSalesStatus)
+    {
+        return toAjax(fsStoreAfterSalesStatusService.updateFsStoreAfterSalesStatus(fsStoreAfterSalesStatus));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeAfterSalesStatus:remove')")
+    @Log(title = "售后订单操作", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsStoreAfterSalesStatusService.deleteFsStoreAfterSalesStatusByIds(ids));
+    }
+}

+ 80 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreCartScrmBridgeController.java

@@ -0,0 +1,80 @@
+package com.fs.admin.controller.store;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.FsStoreCartScrm;
+import com.fs.hisStore.service.IFsStoreCartScrmService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 购物车 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsStoreCartScrmController,供平台总后台跨租户管理
+ *
+ * @author fs
+ * @date 2022-03-21
+ */
+@RestController
+@RequestMapping("/store/store/storeCart")
+public class FsStoreCartScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsStoreCartScrmService fsStoreCartService;
+
+    @PreAuthorize("@ss.hasPermi('store:storeCart:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsStoreCartScrm fsStoreCart)
+    {
+        startPage();
+        List<FsStoreCartScrm> list = fsStoreCartService.selectFsStoreCartList(fsStoreCart);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeCart:export')")
+    @Log(title = "购物车", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsStoreCartScrm fsStoreCart)
+    {
+        List<FsStoreCartScrm> list = fsStoreCartService.selectFsStoreCartList(fsStoreCart);
+        ExcelUtil<FsStoreCartScrm> util = new ExcelUtil<FsStoreCartScrm>(FsStoreCartScrm.class);
+        return util.exportExcel(list, "storeCart");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeCart:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsStoreCartService.selectFsStoreCartById(id));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeCart:add')")
+    @Log(title = "购物车", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsStoreCartScrm fsStoreCart)
+    {
+        return toAjax(fsStoreCartService.insertFsStoreCart(fsStoreCart));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeCart:edit')")
+    @Log(title = "购物车", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsStoreCartScrm fsStoreCart)
+    {
+        return toAjax(fsStoreCartService.updateFsStoreCart(fsStoreCart));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeCart:remove')")
+    @Log(title = "购物车", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsStoreCartService.deleteFsStoreCartByIds(ids));
+    }
+}

+ 81 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreCouponIssueScrmBridgeController.java

@@ -0,0 +1,81 @@
+package com.fs.admin.controller.store;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.FsStoreCouponIssueScrm;
+import com.fs.hisStore.service.IFsStoreCouponIssueScrmService;
+import com.fs.hisStore.vo.FsStoreCouponIssueVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 优惠券发放 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsStoreCouponIssueScrmController,供平台总后台跨租户管理
+ *
+ * @author fs
+ * @date 2022-03-15
+ */
+@RestController
+@RequestMapping("/store/store/storeCouponIssue")
+public class FsStoreCouponIssueScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsStoreCouponIssueScrmService fsStoreCouponIssueService;
+
+    @PreAuthorize("@ss.hasPermi('store:storeCouponIssue:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsStoreCouponIssueScrm fsStoreCouponIssue)
+    {
+        startPage();
+        List<FsStoreCouponIssueVO> list = fsStoreCouponIssueService.selectFsStoreCouponIssueListVO(fsStoreCouponIssue);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeCouponIssue:export')")
+    @Log(title = "优惠券发放", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsStoreCouponIssueScrm fsStoreCouponIssue)
+    {
+        List<FsStoreCouponIssueScrm> list = fsStoreCouponIssueService.selectFsStoreCouponIssueList(fsStoreCouponIssue);
+        ExcelUtil<FsStoreCouponIssueScrm> util = new ExcelUtil<FsStoreCouponIssueScrm>(FsStoreCouponIssueScrm.class);
+        return util.exportExcel(list, "storeCouponIssue");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeCouponIssue:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsStoreCouponIssueService.selectFsStoreCouponIssueById(id));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeCouponIssue:add')")
+    @Log(title = "优惠券发放", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsStoreCouponIssueScrm fsStoreCouponIssue)
+    {
+        return toAjax(fsStoreCouponIssueService.insertFsStoreCouponIssue(fsStoreCouponIssue));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeCouponIssue:edit')")
+    @Log(title = "优惠券发放", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsStoreCouponIssueScrm fsStoreCouponIssue)
+    {
+        return toAjax(fsStoreCouponIssueService.updateFsStoreCouponIssue(fsStoreCouponIssue));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeCouponIssue:remove')")
+    @Log(title = "优惠券发放", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsStoreCouponIssueService.deleteFsStoreCouponIssueByIds(ids));
+    }
+}

+ 80 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreCouponIssueUserScrmBridgeController.java

@@ -0,0 +1,80 @@
+package com.fs.admin.controller.store;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.FsStoreCouponIssueUserScrm;
+import com.fs.hisStore.service.IFsStoreCouponIssueUserScrmService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 优惠券用户领取记录 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsStoreCouponIssueUserScrmController,供平台总后台跨租户管理
+ *
+ * @author fs
+ * @date 2022-03-15
+ */
+@RestController
+@RequestMapping("/store/store/storeCouponIssueUser")
+public class FsStoreCouponIssueUserScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsStoreCouponIssueUserScrmService fsStoreCouponIssueUserService;
+
+    @PreAuthorize("@ss.hasPermi('store:storeCouponIssueUser:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsStoreCouponIssueUserScrm fsStoreCouponIssueUser)
+    {
+        startPage();
+        List<FsStoreCouponIssueUserScrm> list = fsStoreCouponIssueUserService.selectFsStoreCouponIssueUserList(fsStoreCouponIssueUser);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeCouponIssueUser:export')")
+    @Log(title = "优惠券用户领取记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsStoreCouponIssueUserScrm fsStoreCouponIssueUser)
+    {
+        List<FsStoreCouponIssueUserScrm> list = fsStoreCouponIssueUserService.selectFsStoreCouponIssueUserList(fsStoreCouponIssueUser);
+        ExcelUtil<FsStoreCouponIssueUserScrm> util = new ExcelUtil<FsStoreCouponIssueUserScrm>(FsStoreCouponIssueUserScrm.class);
+        return util.exportExcel(list, "storeCouponIssueUser");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeCouponIssueUser:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsStoreCouponIssueUserService.selectFsStoreCouponIssueUserById(id));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeCouponIssueUser:add')")
+    @Log(title = "优惠券用户领取记录", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsStoreCouponIssueUserScrm fsStoreCouponIssueUser)
+    {
+        return toAjax(fsStoreCouponIssueUserService.insertFsStoreCouponIssueUser(fsStoreCouponIssueUser));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeCouponIssueUser:edit')")
+    @Log(title = "优惠券用户领取记录", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsStoreCouponIssueUserScrm fsStoreCouponIssueUser)
+    {
+        return toAjax(fsStoreCouponIssueUserService.updateFsStoreCouponIssueUser(fsStoreCouponIssueUser));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeCouponIssueUser:remove')")
+    @Log(title = "优惠券用户领取记录", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsStoreCouponIssueUserService.deleteFsStoreCouponIssueUserByIds(ids));
+    }
+}

+ 129 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreCouponScrmBridgeController.java

@@ -0,0 +1,129 @@
+package com.fs.admin.controller.store;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.FsStoreCouponScrm;
+import com.fs.hisStore.domain.FsStoreCouponIssueScrm;
+import com.fs.hisStore.param.FsStoreCouponPublishParam;
+import com.fs.hisStore.service.IFsStoreCouponIssueScrmService;
+import com.fs.hisStore.service.IFsStoreCouponScrmService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 优惠券 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsStoreCouponScrmController,供平台总后台跨租户管理
+ *
+ * @author fs
+ * @date 2022-03-15
+ */
+@RestController
+@RequestMapping("/store/storeCoupon")
+public class FsStoreCouponScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsStoreCouponScrmService fsStoreCouponService;
+    @Autowired
+    private IFsStoreCouponIssueScrmService fsStoreCouponIssueService;
+
+    @PreAuthorize("@ss.hasPermi('store:storeCoupon:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsStoreCouponScrm fsStoreCoupon)
+    {
+        startPage();
+        fsStoreCoupon.setIsDel(0);
+        List<FsStoreCouponScrm> list = fsStoreCouponService.selectFsStoreCouponList(fsStoreCoupon);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeCoupon:export')")
+    @Log(title = "优惠券", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsStoreCouponScrm fsStoreCoupon)
+    {
+        List<FsStoreCouponScrm> list = fsStoreCouponService.selectFsStoreCouponList(fsStoreCoupon);
+        ExcelUtil<FsStoreCouponScrm> util = new ExcelUtil<FsStoreCouponScrm>(FsStoreCouponScrm.class);
+        return util.exportExcel(list, "storeCoupon");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeCoupon:query')")
+    @GetMapping(value = "/{couponId}")
+    public AjaxResult getInfo(@PathVariable("couponId") Long couponId)
+    {
+        return AjaxResult.success(fsStoreCouponService.selectFsStoreCouponById(couponId));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeCoupon:add')")
+    @Log(title = "优惠券", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsStoreCouponScrm fsStoreCoupon)
+    {
+        return toAjax(fsStoreCouponService.insertFsStoreCoupon(fsStoreCoupon));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeCoupon:edit')")
+    @Log(title = "优惠券", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsStoreCouponScrm fsStoreCoupon)
+    {
+        return toAjax(fsStoreCouponService.updateFsStoreCoupon(fsStoreCoupon));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeCoupon:remove')")
+    @Log(title = "优惠券", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{couponIds}")
+    public AjaxResult remove(@PathVariable Long[] couponIds)
+    {
+        return toAjax(fsStoreCouponService.deleteFsStoreCouponByIds(couponIds));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeCoupon:publish')")
+    @PostMapping("/publish")
+    public AjaxResult publish(@RequestBody FsStoreCouponPublishParam publishParam)
+    {
+        FsStoreCouponScrm coupon = fsStoreCouponService.selectFsStoreCouponById(publishParam.getCouponId());
+        FsStoreCouponIssueScrm issue = new FsStoreCouponIssueScrm();
+        issue.setCouponId(publishParam.getCouponId());
+        issue.setCouponName(coupon.getTitle());
+        issue.setCouponType(coupon.getType());
+        issue.setStartTime(publishParam.getStartTime());
+        issue.setLimitTime(publishParam.getLimitTime());
+        issue.setTotalCount(publishParam.getTotalCount());
+        issue.setRemainCount(0);
+        issue.setIsPermanent(0);
+        issue.setStatus(1);
+        issue.setCreateTime(new Date());
+        return toAjax(fsStoreCouponIssueService.insertFsStoreCouponIssue(issue));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeCoupon:batchPublish')")
+    @PostMapping("/batchPublish")
+    public R batchPublish(@RequestBody FsStoreCouponPublishParam publishParam)
+    {
+        List<FsStoreCouponScrm> list = fsStoreCouponService.selectFsStoreCouponByIds(publishParam.getIds());
+        for (FsStoreCouponScrm coupon : list) {
+            FsStoreCouponIssueScrm issue = new FsStoreCouponIssueScrm();
+            issue.setCouponId(coupon.getCouponId());
+            issue.setCouponName(coupon.getTitle());
+            issue.setCouponType(coupon.getType());
+            issue.setStartTime(publishParam.getStartTime());
+            issue.setLimitTime(publishParam.getLimitTime());
+            issue.setTotalCount(publishParam.getTotalCount());
+            issue.setRemainCount(0);
+            issue.setIsPermanent(0);
+            issue.setStatus(1);
+            issue.setCreateTime(new Date());
+            fsStoreCouponIssueService.insertFsStoreCouponIssue(issue);
+        }
+        return R.ok();
+    }
+}

+ 80 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreCouponUserScrmBridgeController.java

@@ -0,0 +1,80 @@
+package com.fs.admin.controller.store;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.FsStoreCouponUserScrm;
+import com.fs.hisStore.service.IFsStoreCouponUserScrmService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 优惠券发放记录 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsStoreCouponUserScrmController,供平台总后台跨租户管理
+ *
+ * @author fs
+ * @date 2022-03-15
+ */
+@RestController
+@RequestMapping("/store/store/storeCouponUser")
+public class FsStoreCouponUserScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsStoreCouponUserScrmService fsStoreCouponUserService;
+
+    @PreAuthorize("@ss.hasPermi('store:storeCouponUser:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsStoreCouponUserScrm fsStoreCouponUser)
+    {
+        startPage();
+        List<FsStoreCouponUserScrm> list = fsStoreCouponUserService.selectFsStoreCouponUserList(fsStoreCouponUser);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeCouponUser:export')")
+    @Log(title = "优惠券发放记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsStoreCouponUserScrm fsStoreCouponUser)
+    {
+        List<FsStoreCouponUserScrm> list = fsStoreCouponUserService.selectFsStoreCouponUserList(fsStoreCouponUser);
+        ExcelUtil<FsStoreCouponUserScrm> util = new ExcelUtil<FsStoreCouponUserScrm>(FsStoreCouponUserScrm.class);
+        return util.exportExcel(list, "优惠券发放记录");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeCouponUser:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsStoreCouponUserService.selectFsStoreCouponUserById(id));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeCouponUser:add')")
+    @Log(title = "优惠券发放记录", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsStoreCouponUserScrm fsStoreCouponUser)
+    {
+        return toAjax(fsStoreCouponUserService.insertFsStoreCouponUser(fsStoreCouponUser));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeCouponUser:edit')")
+    @Log(title = "优惠券发放记录", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsStoreCouponUserScrm fsStoreCouponUser)
+    {
+        return toAjax(fsStoreCouponUserService.updateFsStoreCouponUser(fsStoreCouponUser));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeCouponUser:remove')")
+    @Log(title = "优惠券发放记录", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsStoreCouponUserService.deleteFsStoreCouponUserByIds(ids));
+    }
+}

+ 94 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreOrderAuditScrmBridgeController.java

@@ -0,0 +1,94 @@
+package com.fs.admin.controller.store;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.FsStoreOrderAuditScrm;
+import com.fs.hisStore.param.FsStoreOrderAuditParam;
+import com.fs.hisStore.param.FsStoreOrderAuditReviewParam;
+import com.fs.hisStore.service.IFsStoreOrderAuditScrmService;
+import com.fs.hisStore.vo.FsStoreOrderAuditVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+import java.util.List;
+
+/**
+ * 订单审核 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsStoreOrderAuditScrmController,供平台总后台跨租户管理
+ *
+ * @author fs
+ * @date 2023-06-15
+ */
+@RestController
+@RequestMapping("/store/store/storeOrderAudit")
+public class FsStoreOrderAuditScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsStoreOrderAuditScrmService fsStoreOrderAuditService;
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrderAudit:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsStoreOrderAuditParam param)
+    {
+        startPage();
+        List<FsStoreOrderAuditVO> list = fsStoreOrderAuditService.selectStoreOrderAuditVOList(param);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrderAudit:export')")
+    @Log(title = "订单审核", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsStoreOrderAuditParam param)
+    {
+        List<FsStoreOrderAuditVO> list = fsStoreOrderAuditService.selectStoreOrderAuditVOList(param);
+        ExcelUtil<FsStoreOrderAuditVO> util = new ExcelUtil<FsStoreOrderAuditVO>(FsStoreOrderAuditVO.class);
+        return util.exportExcel(list, "订单审核数据");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrderAudit:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsStoreOrderAuditService.getById(id));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrderAudit:add')")
+    @Log(title = "订单审核", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsStoreOrderAuditScrm fsStoreOrderAudit)
+    {
+        return toAjax(fsStoreOrderAuditService.save(fsStoreOrderAudit));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrderAudit:edit')")
+    @Log(title = "订单审核", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsStoreOrderAuditScrm fsStoreOrderAudit)
+    {
+        return toAjax(fsStoreOrderAuditService.updateById(fsStoreOrderAudit));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrderAudit:audit')")
+    @Log(title = "订单审核", businessType = BusinessType.UPDATE)
+    @PostMapping("/audit")
+    public AjaxResult audit(@Valid @RequestBody FsStoreOrderAuditReviewParam param)
+    {
+        fsStoreOrderAuditService.audit(param, null, true);
+        return AjaxResult.success();
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrderAudit:remove')")
+    @Log(title = "订单审核", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsStoreOrderAuditService.removeByIds(java.util.Arrays.asList(ids)));
+    }
+}

+ 88 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreOrderItemScrmBridgeController.java

@@ -0,0 +1,88 @@
+package com.fs.admin.controller.store;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.FsStoreOrderItemScrm;
+import com.fs.hisStore.service.IFsStoreOrderItemScrmService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 订单详情 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsStoreOrderItemScrmController,供平台总后台跨租户管理
+ *
+ * @author fs
+ * @date 2022-03-21
+ */
+@RestController
+@RequestMapping("/store/store/storeOrderItem")
+public class FsStoreOrderItemScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsStoreOrderItemScrmService fsStoreOrderItemService;
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrderItem:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsStoreOrderItemScrm fsStoreOrderItem)
+    {
+        startPage();
+        List<FsStoreOrderItemScrm> list = fsStoreOrderItemService.selectFsStoreOrderItemList(fsStoreOrderItem);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrderItem:export')")
+    @Log(title = "订单详情", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsStoreOrderItemScrm fsStoreOrderItem)
+    {
+        List<FsStoreOrderItemScrm> list = fsStoreOrderItemService.selectFsStoreOrderItemList(fsStoreOrderItem);
+        ExcelUtil<FsStoreOrderItemScrm> util = new ExcelUtil<FsStoreOrderItemScrm>(FsStoreOrderItemScrm.class);
+        return util.exportExcel(list, "storeOrderItem");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrderItem:query')")
+    @GetMapping(value = "/{itemId}")
+    public AjaxResult getInfo(@PathVariable("itemId") Long itemId)
+    {
+        return AjaxResult.success(fsStoreOrderItemService.selectFsStoreOrderItemById(itemId));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrderItem:add')")
+    @Log(title = "订单详情", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsStoreOrderItemScrm fsStoreOrderItem)
+    {
+        return toAjax(fsStoreOrderItemService.insertFsStoreOrderItem(fsStoreOrderItem));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrderItem:edit')")
+    @Log(title = "订单详情", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsStoreOrderItemScrm fsStoreOrderItem)
+    {
+        return toAjax(fsStoreOrderItemService.updateFsStoreOrderItem(fsStoreOrderItem));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrderItem:remove')")
+    @Log(title = "订单详情", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{itemIds}")
+    public AjaxResult remove(@PathVariable Long[] itemIds)
+    {
+        return toAjax(fsStoreOrderItemService.deleteFsStoreOrderItemByIds(itemIds));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrderItem:updateNum')")
+    @Log(title = "订单详情修改订单数量", businessType = BusinessType.UPDATE)
+    @PutMapping("/updateNum")
+    public AjaxResult updateNum(@RequestBody FsStoreOrderItemScrm fsStoreOrderItem)
+    {
+        return toAjax(fsStoreOrderItemService.updateFsStoreOrderItemNum(fsStoreOrderItem));
+    }
+}

+ 80 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreOrderNoticeScrmBridgeController.java

@@ -0,0 +1,80 @@
+package com.fs.admin.controller.store;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.FsStoreOrderNoticeScrm;
+import com.fs.hisStore.service.IFsStoreOrderNoticeScrmService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 订单通知用户 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsStoreOrderNoticeScrmController,供平台总后台跨租户管理
+ *
+ * @author fs
+ * @date 2022-03-15
+ */
+@RestController
+@RequestMapping("/store/store/storeOrderNotice")
+public class FsStoreOrderNoticeScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsStoreOrderNoticeScrmService fsStoreOrderNoticeService;
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrderNotice:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsStoreOrderNoticeScrm fsStoreOrderNotice)
+    {
+        startPage();
+        List<FsStoreOrderNoticeScrm> list = fsStoreOrderNoticeService.selectFsStoreOrderNoticeList(fsStoreOrderNotice);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrderNotice:export')")
+    @Log(title = "订单通知用户", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsStoreOrderNoticeScrm fsStoreOrderNotice)
+    {
+        List<FsStoreOrderNoticeScrm> list = fsStoreOrderNoticeService.selectFsStoreOrderNoticeList(fsStoreOrderNotice);
+        ExcelUtil<FsStoreOrderNoticeScrm> util = new ExcelUtil<FsStoreOrderNoticeScrm>(FsStoreOrderNoticeScrm.class);
+        return util.exportExcel(list, "storeOrderNotice");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrderNotice:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsStoreOrderNoticeService.selectFsStoreOrderNoticeById(id));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrderNotice:add')")
+    @Log(title = "订单通知用户", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsStoreOrderNoticeScrm fsStoreOrderNotice)
+    {
+        return toAjax(fsStoreOrderNoticeService.insertFsStoreOrderNotice(fsStoreOrderNotice));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrderNotice:edit')")
+    @Log(title = "订单通知用户", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsStoreOrderNoticeScrm fsStoreOrderNotice)
+    {
+        return toAjax(fsStoreOrderNoticeService.updateFsStoreOrderNotice(fsStoreOrderNotice));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrderNotice:remove')")
+    @Log(title = "订单通知用户", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsStoreOrderNoticeService.deleteFsStoreOrderNoticeByIds(ids));
+    }
+}

+ 132 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreOrderOfflineScrmBridgeController.java

@@ -0,0 +1,132 @@
+package com.fs.admin.controller.store;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ParseUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.crm.domain.CrmCustomer;
+import com.fs.crm.service.ICrmCustomerService;
+import com.fs.framework.security.SecurityUtils;
+import com.fs.framework.security.LoginUser;
+import com.fs.hisStore.domain.FsStoreOrderOfflineScrm;
+import com.fs.hisStore.domain.FsStoreOrderOfflineItemScrm;
+import com.fs.hisStore.param.FsStoreOrderOfflineParam;
+import com.fs.hisStore.service.IFsStoreOrderOfflineItemScrmService;
+import com.fs.hisStore.service.IFsStoreOrderOfflineScrmService;
+import com.fs.hisStore.vo.FsStoreOrderOfflineListVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 线下订单 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsStoreOrderOfflineScrmController,供平台总后台跨租户管理
+ *
+ * @author fs
+ * @date 2024-10-29
+ */
+@RestController
+@RequestMapping("/store/store/storeOrderOffline")
+public class FsStoreOrderOfflineScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsStoreOrderOfflineScrmService fsStoreOrderOfflineService;
+    @Autowired
+    private IFsStoreOrderOfflineItemScrmService fsStoreOrderOfflineItemService;
+    @Autowired
+    private ICrmCustomerService crmCustomerService;
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrderOffline:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsStoreOrderOfflineParam param)
+    {
+        startPage();
+        List<FsStoreOrderOfflineListVO> list = fsStoreOrderOfflineService.selectFsStoreOrderOfflineListVO(param);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrderOffline:export')")
+    @Log(title = "线下订单", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsStoreOrderOfflineScrm fsStoreOrderOffline)
+    {
+        List<FsStoreOrderOfflineScrm> list = fsStoreOrderOfflineService.selectFsStoreOrderOfflineList(fsStoreOrderOffline);
+        ExcelUtil<FsStoreOrderOfflineScrm> util = new ExcelUtil<FsStoreOrderOfflineScrm>(FsStoreOrderOfflineScrm.class);
+        return util.exportExcel(list, "storeOrderOffline");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrderOffline:query')")
+    @GetMapping(value = "/{orderId}")
+    public R getInfo(@PathVariable("orderId") Long orderId)
+    {
+        FsStoreOrderOfflineListVO order = fsStoreOrderOfflineService.selectFsStoreOrderOfflineVOById(orderId);
+        order.setMobile(ParseUtils.parsePhone(order.getMobile()));
+        CrmCustomer customer = null;
+        if(order.getCrmId()!=null && order.getCrmId()>0){
+            customer = crmCustomerService.selectCrmCustomerById(order.getCrmId());
+            customer.setMobile(ParseUtils.parsePhone(customer.getMobile()));
+        }
+        FsStoreOrderOfflineItemScrm itemMap = new FsStoreOrderOfflineItemScrm();
+        itemMap.setOrderId(order.getOrderId());
+        List<FsStoreOrderOfflineItemScrm> items = fsStoreOrderOfflineItemService.selectFsStoreOrderOfflineItemList(itemMap);
+        return R.ok().put("order", order).put("items", items).put("customer", customer);
+    }
+
+    @GetMapping(value = "/queryPhone/{orderId}")
+    @Log(title = "查看电话", businessType = BusinessType.GRANT)
+    @PreAuthorize("@ss.hasPermi('store:storeOrderOffline:queryPhone')")
+    public R getPhone(@PathVariable("orderId") Long orderId)
+    {
+        FsStoreOrderOfflineListVO order = fsStoreOrderOfflineService.selectFsStoreOrderOfflineVOById(orderId);
+        String userPhone = order.getMobile();
+        return R.ok().put("userPhone", userPhone);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrderOffline:add')")
+    @Log(title = "线下订单", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsStoreOrderOfflineScrm fsStoreOrderOffline)
+    {
+        return toAjax(fsStoreOrderOfflineService.insertFsStoreOrderOffline(fsStoreOrderOffline));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrderOffline:edit')")
+    @Log(title = "线下订单", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsStoreOrderOfflineScrm fsStoreOrderOffline)
+    {
+        return toAjax(fsStoreOrderOfflineService.updateFsStoreOrderOffline(fsStoreOrderOffline));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrderOffline:remove')")
+    @Log(title = "线下订单", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{orderIds}")
+    public AjaxResult remove(@PathVariable Long[] orderIds)
+    {
+        return toAjax(fsStoreOrderOfflineService.deleteFsStoreOrderOfflineByIds(orderIds));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrderOffline:audit')")
+    @Log(title = "审核订单", businessType = BusinessType.UPDATE)
+    @PostMapping("/auditOrder/{orderId}")
+    public R auditOrder(@PathVariable Long orderId)
+    {
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        FsStoreOrderOfflineScrm fsStoreOrderOffline = new FsStoreOrderOfflineScrm();
+        fsStoreOrderOffline.setOrderId(orderId);
+        fsStoreOrderOffline.setStatus(3L);
+        fsStoreOrderOffline.setAuditBy(loginUser.getCompanyUser().getNickName());
+        fsStoreOrderOffline.setAuditTime(new Date());
+        if (fsStoreOrderOfflineService.updateFsStoreOrderOffline(fsStoreOrderOffline) > 0){
+            return R.ok();
+        }
+        return R.error("审核失败");
+    }
+}

+ 139 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreOrderPromotionScrmBridgeController.java

@@ -0,0 +1,139 @@
+package com.fs.admin.controller.store;
+
+import com.alibaba.fastjson.JSONObject;
+import cn.hutool.core.bean.BeanUtil;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.StringUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.dto.StoreOrderProductDTO;
+import com.fs.hisStore.param.FsStoreOrderParam;
+import com.fs.hisStore.service.IFsStoreOrderItemScrmService;
+import com.fs.hisStore.service.IFsStoreOrderScrmService;
+import com.fs.hisStore.vo.FsPromotionOrderVO;
+import com.fs.hisStore.vo.FsStoreOrderItemExportVO;
+import com.fs.hisStore.vo.FsStoreOrderPromotionExportVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * 推广订单 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsStoreOrderPromotionScrmController,供平台总后台跨租户管理
+ * 注意:使用 /PromotionOrder 路径避免与 FsStoreOrderScrmBridgeController 的 /storeOrder 路径冲突
+ *
+ * @author fs
+ * @date 2022-03-15
+ */
+@RestController
+@RequestMapping("/store/store/PromotionOrder")
+public class FsStoreOrderPromotionScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsStoreOrderScrmService fsStoreOrderService;
+    @Autowired
+    private IFsStoreOrderItemScrmService orderItemService;
+
+    @PreAuthorize("@ss.hasPermi('store:PromotionOrder:list')")
+    @GetMapping("/promotionList")
+    public TableDataInfo list(FsStoreOrderParam param)
+    {
+        startPage();
+        if(!StringUtils.isEmpty(param.getCreateTimeRange())){
+            param.setCreateTimeList(param.getCreateTimeRange().split("--"));
+        }
+        if(!StringUtils.isEmpty(param.getPayTimeRange())){
+            param.setPayTimeList(param.getPayTimeRange().split("--"));
+        }
+        if(!StringUtils.isEmpty(param.getDeliveryImportTimeRange())){
+            param.setDeliveryImportTimeList(param.getDeliveryImportTimeRange().split("--"));
+        }
+        if(!StringUtils.isEmpty(param.getDeliverySendTimeRange())){
+            param.setDeliverySendTimeList(param.getDeliverySendTimeRange().split("--"));
+        }
+        List<FsPromotionOrderVO> list = fsStoreOrderService.selectFsPromotionOrderListVO(param);
+        if (list != null) {
+            for (FsPromotionOrderVO vo : list) {
+                if(vo.getPhone()!=null){
+                    vo.setPhone(vo.getPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+                    vo.setUserPhone(vo.getUserPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+                }
+            }
+        }
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:promotionOrder:export')")
+    @Log(title = "导出推广订单", businessType = BusinessType.EXPORT)
+    @GetMapping("/promotionExport")
+    public AjaxResult export(FsStoreOrderParam param)
+    {
+        if (param == null){
+            return AjaxResult.error("请筛选数据导出");
+        }
+        if(!StringUtils.isEmpty(param.getCreateTimeRange())){
+            param.setCreateTimeList(param.getCreateTimeRange().split("--"));
+        }
+        if(!StringUtils.isEmpty(param.getPayTimeRange())){
+            param.setPayTimeList(param.getPayTimeRange().split("--"));
+        }
+        if(!StringUtils.isEmpty(param.getDeliveryImportTimeRange())){
+            param.setDeliveryImportTimeList(param.getDeliveryImportTimeRange().split("--"));
+        }
+        List<FsStoreOrderPromotionExportVO> list = fsStoreOrderService.selectFsPromotionOrderListVOByExport(param);
+        if (list != null) {
+            for (FsStoreOrderPromotionExportVO vo : list) {
+                if (vo.getPhone() != null) {
+                    vo.setPhone(vo.getPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+                }
+                if (vo.getUserPhone() != null) {
+                    vo.setUserPhone(vo.getUserPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+                }
+            }
+        }
+        ExcelUtil<FsStoreOrderPromotionExportVO> util = new ExcelUtil<FsStoreOrderPromotionExportVO>(FsStoreOrderPromotionExportVO.class);
+        return util.exportExcel(list, "订单数据");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:promotionOrder:exportItems')")
+    @Log(title = "推广订单明细导出", businessType = BusinessType.EXPORT)
+    @GetMapping("/promotionExportItems")
+    public AjaxResult exportItems(FsStoreOrderParam param)
+    {
+        if(!StringUtils.isEmpty(param.getCreateTimeRange())){
+            param.setCreateTimeList(param.getCreateTimeRange().split("--"));
+        }
+        if(!StringUtils.isEmpty(param.getPayTimeRange())){
+            param.setPayTimeList(param.getPayTimeRange().split("--"));
+        }
+        if(!StringUtils.isEmpty(param.getDeliveryImportTimeRange())){
+            param.setDeliveryImportTimeList(param.getDeliveryImportTimeRange().split("--"));
+        }
+        param.setIsHealth("1");
+        List<FsStoreOrderItemExportVO> list = orderItemService.selectFsStoreOrderItemListExportVO(param);
+        if (list != null) {
+            for (FsStoreOrderItemExportVO vo : list) {
+                if (vo.getUserPhone() != null) {
+                    String phone = vo.getUserPhone().replaceAll("(\\d{3})\\d*(\\d{1})", "$1****$2");
+                    vo.setUserPhone(phone);
+                }
+                if (!StringUtils.isEmpty(vo.getJsonInfo())) {
+                    try {
+                        StoreOrderProductDTO orderProductDTO = JSONObject.parseObject(vo.getJsonInfo(), StoreOrderProductDTO.class);
+                        BeanUtil.copyProperties(orderProductDTO, vo);
+                    } catch (Exception e) {
+                    }
+                }
+            }
+        }
+        ExcelUtil<FsStoreOrderItemExportVO> util = new ExcelUtil<FsStoreOrderItemExportVO>(FsStoreOrderItemExportVO.class);
+        return util.exportExcel(list, "订单明细数据");
+    }
+}

+ 1060 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreOrderScrmBridgeController.java

@@ -0,0 +1,1060 @@
+package com.fs.admin.controller.store;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.domain.entity.SysRole;
+import com.fs.common.core.domain.entity.SysUser;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.CloudHostUtils;
+import com.fs.common.utils.ParseUtils;
+import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.StringUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.param.CompanyStoreOrderMoneyLogsListParam;
+import com.fs.company.service.ICompanyMoneyLogsService;
+import com.fs.company.vo.CompanyStoreOrderMoneyLogsVO;
+import com.fs.config.cloud.CloudHostProper;
+import com.fs.erp.domain.ErpDeliverys;
+import com.fs.erp.domain.ErpOrderQuery;
+import com.fs.erp.dto.ErpOrderQueryRequert;
+import com.fs.erp.dto.ErpOrderQueryResponse;
+import com.fs.erp.dto.df.DFConfigVo;
+import com.fs.erp.service.IErpOrderService;
+import com.fs.framework.security.LoginUser;
+import com.fs.framework.security.SecurityUtils;
+import com.fs.framework.service.TokenService;
+import com.fs.his.domain.FsDfAccount;
+import com.fs.his.domain.FsStoreOrderDf;
+import com.fs.his.domain.FsUser;
+import com.fs.his.enums.FsStoreOrderLogEnum;
+import com.fs.his.param.FsStoreOrderSetErpPhoneParam;
+import com.fs.his.service.IFsDfAccountService;
+import com.fs.his.service.IFsExpressService;
+import com.fs.his.service.IFsStoreOrderDfService;
+import com.fs.his.service.IFsUserService;
+import com.fs.his.utils.ConfigUtil;
+import com.fs.his.vo.FsStoreOrderListAndStatisticsVo;
+import com.fs.his.vo.FsStoreOrderListVO;
+import com.fs.hisStore.config.FsErpConfig;
+import com.fs.hisStore.domain.FsStoreOrderItemScrm;
+import com.fs.hisStore.domain.FsStoreOrderScrm;
+import com.fs.hisStore.domain.FsStoreOrderStatusScrm;
+import com.fs.hisStore.domain.FsStorePaymentScrm;
+import com.fs.his.dto.ExpressInfoDTO;
+import com.fs.hisStore.dto.StoreOrderExpressExportDTO;
+import com.fs.hisStore.dto.StoreOrderProductDTO;
+import com.fs.hisStore.enums.ShipperCodeEnum;
+import com.fs.hisStore.param.*;
+import com.fs.hisStore.service.*;
+import com.fs.hisStore.vo.*;
+import com.fs.system.domain.SysConfig;
+import com.fs.system.mapper.SysConfigMapper;
+import com.fs.system.service.ISysRoleService;
+import com.github.pagehelper.PageHelper;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletRequest;
+import java.math.BigDecimal;
+import java.text.ParseException;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 订单 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsStoreOrderScrmController,供平台总后台跨租户管理
+ *
+ * @author fs
+ * @date 2022-03-15
+ */
+@RestController
+@RequestMapping("/store/store/storeOrder")
+public class FsStoreOrderScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsExpressService expressService;
+    @Autowired
+    private IFsStoreOrderScrmService fsStoreOrderService;
+    @Autowired
+    private IFsStoreOrderItemScrmService orderItemService;
+    @Autowired
+    private IFsUserService userService;
+    @Autowired
+    private IFsStoreOrderStatusScrmService orderStatusService;
+    @Autowired
+    IFsStorePaymentScrmService paymentService;
+    @Autowired
+    private CloudHostProper cloudHostProper;
+    @Autowired
+    private ICompanyMoneyLogsService moneyLogsService;
+    @Autowired
+    @Qualifier("erpOrderServiceImpl")
+    private IErpOrderService gyOrderService;
+    @Autowired
+    @Qualifier("wdtErpOrderServiceImpl")
+    private IErpOrderService wdtOrderService;
+    @Autowired
+    @Qualifier("hzOMSErpOrderServiceImpl")
+    private IErpOrderService hzOMSErpOrderService;
+    @Autowired
+    @Qualifier("dfOrderServiceImpl")
+    private IErpOrderService dfOrderService;
+    @Autowired
+    @Qualifier("k9OrderScrmServiceImpl")
+    private IErpOrderService k9OrderService;
+    @Autowired
+    @Qualifier("JSTErpOrderServiceImpl")
+    private IErpOrderService jSTOrderService;
+    @Autowired
+    private ConfigUtil configUtil;
+    @Autowired
+    private IFsStoreOrderAuditLogScrmService orderAuditLogService;
+    @Autowired
+    private TokenService tokenService;
+    @Autowired
+    SysConfigMapper sysConfigMapper;
+    @Autowired
+    private IFsDfAccountService fsDfAccountService;
+    @Autowired
+    private IFsStoreOrderDfService fsStoreOrderDfService;
+    @Autowired
+    private IFsStoreOrderLogsScrmService fsStoreOrderLogsService;
+    @Autowired
+    private ISysRoleService sysRoleService;
+
+    private IErpOrderService getErpService()
+    {
+        IErpOrderService erpOrderService = null;
+        FsErpConfig erpConfig = configUtil.getErpConfig();
+        Integer erpOpen = erpConfig.getErpOpen();
+        if (erpOpen != null && erpOpen == 1) {
+            Integer erpType = erpConfig.getErpType();
+            if (erpType != null) {
+                if (erpType == 1) {
+                    erpOrderService = gyOrderService;
+                } else if (erpType == 2) {
+                    erpOrderService = wdtOrderService;
+                } else if (erpType == 3) {
+                    erpOrderService = hzOMSErpOrderService;
+                } else if (erpType == 4) {
+                    erpOrderService = dfOrderService;
+                } else if (erpType == 5) {
+                    erpOrderService = jSTOrderService;
+                } else if (erpType == 6) {
+                    erpOrderService = k9OrderService;
+                }
+            }
+        }
+        return erpOrderService;
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrder:list')")
+    @PostMapping("/list")
+    public TableDataInfo list(@RequestBody FsStoreOrderParam param)
+    {
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        if (!StringUtils.isEmpty(param.getCreateTimeRange())) {
+            param.setCreateTimeList(param.getCreateTimeRange().split("--"));
+        }
+        if (!StringUtils.isEmpty(param.getPayTimeRange())) {
+            param.setPayTimeList(param.getPayTimeRange().split("--"));
+        }
+        if (!StringUtils.isEmpty(param.getDeliveryImportTimeRange())) {
+            param.setDeliveryImportTimeList(param.getDeliveryImportTimeRange().split("--"));
+        }
+        if (!StringUtils.isEmpty(param.getDeliverySendTimeRange())) {
+            param.setDeliverySendTimeList(param.getDeliverySendTimeRange().split("--"));
+        }
+        param.setNotHealth(1);
+        List<FsStoreOrderVO> list = fsStoreOrderService.selectFsStoreOrderListVO(param);
+        TableDataInfo dataTable = getDataTable(list);
+        if (CloudHostUtils.hasCloudHostName("康年堂")) {
+            dataTable.setMsg("knt");
+        }
+        if (list != null) {
+            LoginUser loginUser = (LoginUser) tokenService.getLoginUser(ServletUtils.getRequest());
+            for (FsStoreOrderVO vo : list) {
+                if (vo.getPhone() != null) {
+                    vo.setPhone(vo.getPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+                }
+                if (ObjectUtil.isNotEmpty(vo.getUserPhone())) {
+                    vo.setUserPhone(vo.getUserPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+                }
+                if (CloudHostUtils.hasCloudHostName("康年堂")) {
+                    FsStoreOrderDf df = fsStoreOrderDfService.selectFsStoreOrderDfByOrderId(vo.getId());
+                    if (df != null) {
+                        vo.setErpAccount(df.getLoginAccount());
+                    }
+                }
+                if ((loginUser.getPermissions().contains("his:storeAfterSales:finance")) || loginUser.getPermissions().contains("*:*:*") && (vo.getCost() != null && vo.getTotalNum() != null)) {
+                    vo.setFPrice(vo.getCost().multiply(BigDecimal.valueOf(vo.getTotalNum())));
+                } else {
+                    vo.setPayPostage(BigDecimal.ZERO);
+                    vo.setCost(BigDecimal.ZERO);
+                    vo.setFPrice(BigDecimal.ZERO);
+                    vo.setPayDelivery(BigDecimal.ZERO);
+                    vo.setBarCode("");
+                    vo.setCateName("");
+                    vo.setBankTransactionId("");
+                }
+            }
+        }
+        FsStoreOrderListAndStatisticsVo vo = new FsStoreOrderListAndStatisticsVo();
+        BeanUtils.copyProperties(dataTable, vo);
+        if (dataTable.getTotal() > 0) {
+            Map<String, BigDecimal> statistics = fsStoreOrderService.selectFsStoreOrderStatistics(param);
+            if (statistics != null && statistics.size() >= 3) {
+                vo.setPayPriceTotal(statistics.get("pay_price").toString());
+                vo.setPayMoneyTotal(statistics.get("pay_money").toString());
+                vo.setPayRemainTotal(statistics.get("pay_remain").toString());
+            } else {
+                vo.setPayPriceTotal("0");
+                vo.setPayMoneyTotal("0");
+                vo.setPayRemainTotal("0");
+            }
+            String productStatistics = fsStoreOrderService.selectFsStoreOrderProductStatistics(param);
+            if (StringUtils.isNotBlank(productStatistics)) {
+                vo.setProductInfo(productStatistics);
+            } else {
+                vo.setProductInfo("");
+            }
+        }
+        return vo;
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrder:payRemainList')")
+    @GetMapping("/payRemainList")
+    public TableDataInfo payRemainList(FsStoreOrderParam param)
+    {
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        if (!StringUtils.isEmpty(param.getCreateTimeRange())) {
+            param.setCreateTimeList(param.getCreateTimeRange().split("--"));
+        }
+        if (!StringUtils.isEmpty(param.getPayTimeRange())) {
+            param.setPayTimeList(param.getPayTimeRange().split("--"));
+        }
+        if (!StringUtils.isEmpty(param.getDeliveryImportTimeRange())) {
+            param.setDeliveryImportTimeList(param.getDeliveryImportTimeRange().split("--"));
+        }
+        List<FsStoreOrderVO> list = fsStoreOrderService.selectPayRemainListVO(param);
+        if (list != null) {
+            for (FsStoreOrderVO vo : list) {
+                if (vo.getPhone() != null) {
+                    vo.setPhone(vo.getPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+                    vo.setUserPhone(vo.getUserPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+                }
+            }
+        }
+        return getDataTable(list);
+    }
+
+    @Log(title = "付尾款订单", businessType = BusinessType.EXPORT)
+    @GetMapping("/payRemainExport")
+    public AjaxResult payRemainExport(FsStoreOrderParam param)
+    {
+        if (!StringUtils.isEmpty(param.getCreateTimeRange())) {
+            param.setCreateTimeList(param.getCreateTimeRange().split("--"));
+        }
+        if (!StringUtils.isEmpty(param.getPayTimeRange())) {
+            param.setPayTimeList(param.getPayTimeRange().split("--"));
+        }
+        if (!StringUtils.isEmpty(param.getDeliveryImportTimeRange())) {
+            param.setDeliveryImportTimeList(param.getDeliveryImportTimeRange().split("--"));
+        }
+        List<FsStorePayRemainOrderExportVO> list = fsStoreOrderService.selectFsStorePayRemainOrderListVOByExport(param);
+        if (list != null) {
+            for (FsStorePayRemainOrderExportVO vo : list) {
+                if (vo.getPhone() != null) {
+                    vo.setPhone(vo.getPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+                }
+                if (vo.getUserPhone() != null) {
+                    vo.setUserPhone(vo.getUserPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+                }
+                if (vo.getUserAddress() != null) {
+                    vo.setUserAddress(ParseUtils.parseAddress(vo.getUserAddress()));
+                }
+            }
+        }
+        ExcelUtil<FsStorePayRemainOrderExportVO> util = new ExcelUtil<FsStorePayRemainOrderExportVO>(FsStorePayRemainOrderExportVO.class);
+        return util.exportExcel(list, "付尾款订单数据");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrder:export')")
+    @Log(title = "订单", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public AjaxResult export(@RequestBody FsStoreOrderParam param)
+    {
+        if ("".equals(param.getBeginTime()) && "".equals(param.getEndTime())) {
+            param.setBeginTime(null);
+            param.setEndTime(null);
+        }
+        if (fsStoreOrderService.isEntityNull(param)) {
+            return AjaxResult.error("请筛选数据导出");
+        }
+        if (!StringUtils.isEmpty(param.getCreateTimeRange())) {
+            param.setCreateTimeList(param.getCreateTimeRange().split("--"));
+        }
+        if (!StringUtils.isEmpty(param.getPayTimeRange())) {
+            param.setPayTimeList(param.getPayTimeRange().split("--"));
+        }
+        if (!StringUtils.isEmpty(param.getDeliverySendTimeRange())) {
+            param.setDeliverySendTimeList(param.getDeliverySendTimeRange().split("--"));
+        }
+        if (!StringUtils.isEmpty(param.getDeliveryImportTimeRange())) {
+            param.setDeliveryImportTimeList(param.getDeliveryImportTimeRange().split("--"));
+        }
+        param.setNotHealth(1);
+        List<FsStoreOrderErpExportVO> list = fsStoreOrderService.selectFsStoreOrderListVOByExport(param);
+        if (list != null) {
+            SysRole sysRole = isCheckPermission();
+            for (FsStoreOrderErpExportVO vo : list) {
+                if (vo.getPhone() != null && sysRole.getIsCheckPhone() != 1) {
+                    vo.setPhone(vo.getPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+                }
+                if (vo.getUserPhone() != null && sysRole.getIsCheckPhone() != 1) {
+                    vo.setUserPhone(vo.getUserPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+                }
+                if (vo.getUserAddress() != null && sysRole.getIsCheckAddress() != 1) {
+                    vo.setUserAddress(ParseUtils.parseAddress(vo.getUserAddress()));
+                }
+                String orderItem = orderItemService.selectFsStoreOrderItemByOrderId(vo.getId());
+                vo.setOrderItem(orderItem);
+            }
+        }
+        String filter = param.getFilter();
+        ArrayList<String> filterList = new ArrayList<>();
+        if (StringUtils.isNotBlank(filter)) {
+            String[] filterArr = filter.split("\\s*,\\s*");
+            filterList.addAll(Arrays.asList(filterArr));
+        }
+        ExcelUtil<FsStoreOrderErpExportVO> util = new ExcelUtil<FsStoreOrderErpExportVO>(FsStoreOrderErpExportVO.class);
+        if (filter != null && !filter.isEmpty()) {
+            return util.exportExcelSelectedColumns(list, "订单数据", filterList);
+        } else {
+            return util.exportExcel(list, "订单数据");
+        }
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrder:export:details')")
+    @Log(title = "订单", businessType = BusinessType.EXPORT)
+    @PostMapping("/exportDetails")
+    public AjaxResult exportDetails(@RequestBody FsStoreOrderParam param)
+    {
+        if ("".equals(param.getBeginTime()) && "".equals(param.getEndTime())) {
+            param.setBeginTime(null);
+            param.setEndTime(null);
+        }
+        if (fsStoreOrderService.isEntityNull(param)) {
+            return AjaxResult.error("请筛选数据导出");
+        }
+        if (!StringUtils.isEmpty(param.getCreateTimeRange())) {
+            param.setCreateTimeList(param.getCreateTimeRange().split("--"));
+        }
+        if (!StringUtils.isEmpty(param.getPayTimeRange())) {
+            param.setPayTimeList(param.getPayTimeRange().split("--"));
+        }
+        if (!StringUtils.isEmpty(param.getDeliverySendTimeRange())) {
+            param.setDeliverySendTimeList(param.getDeliverySendTimeRange().split("--"));
+        }
+        if (!StringUtils.isEmpty(param.getDeliveryImportTimeRange())) {
+            param.setDeliveryImportTimeList(param.getDeliveryImportTimeRange().split("--"));
+        }
+        param.setNotHealth(1);
+        List<FsStoreOrderErpExportVO> list = fsStoreOrderService.selectFsStoreOrderListVOByExport(param);
+        String filter = param.getFilter();
+        ArrayList<String> filterList = new ArrayList<>();
+        if (StringUtils.isNotBlank(filter)) {
+            String[] filterArr = filter.split("\\s*,\\s*");
+            filterList.addAll(Arrays.asList(filterArr));
+        }
+        ExcelUtil<FsStoreOrderErpExportVO> util = new ExcelUtil<FsStoreOrderErpExportVO>(FsStoreOrderErpExportVO.class);
+        if (filter != null && !filter.isEmpty()) {
+            return util.exportExcelSelectedColumns(list, "订单数据", filterList);
+        } else {
+            return util.exportExcel(list, "订单数据");
+        }
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrder:exportItems')")
+    @Log(title = "订单明细导出", businessType = BusinessType.EXPORT)
+    @GetMapping("/exportItems")
+    public AjaxResult exportItems(FsStoreOrderParam param)
+    {
+        if ("".equals(param.getBeginTime()) && "".equals(param.getEndTime())) {
+            param.setBeginTime(null);
+            param.setEndTime(null);
+        }
+        if (fsStoreOrderService.isEntityNull(param)) {
+            return AjaxResult.error("请筛选数据导出");
+        }
+        if (!StringUtils.isEmpty(param.getCreateTimeRange())) {
+            param.setCreateTimeList(param.getCreateTimeRange().split("--"));
+        }
+        if (!StringUtils.isEmpty(param.getPayTimeRange())) {
+            param.setPayTimeList(param.getPayTimeRange().split("--"));
+        }
+        if (!StringUtils.isEmpty(param.getDeliveryImportTimeRange())) {
+            param.setDeliveryImportTimeList(param.getDeliveryImportTimeRange().split("--"));
+        }
+        if (!StringUtils.isEmpty(param.getDeliverySendTimeRange())) {
+            param.setDeliverySendTimeList(param.getDeliverySendTimeRange().split("--"));
+        }
+        param.setNotHealth(1);
+        List<FsStoreOrderItemExportVO> list = orderItemService.selectFsStoreOrderItemListExportVO(param);
+        if (list != null) {
+            SysRole sysRole = isCheckPermission();
+            LoginUser loginUser = (LoginUser) tokenService.getLoginUser(ServletUtils.getRequest());
+            for (FsStoreOrderItemExportVO vo : list) {
+                if (vo.getUserPhone() != null && sysRole.getIsCheckPhone() != 1) {
+                    String phone = vo.getUserPhone().replaceAll("(\\d{3})\\d*(\\d{1})", "$1****$2");
+                    vo.setUserPhone(phone);
+                }
+                if (vo.getUserAddress() != null && sysRole.getIsCheckAddress() != 1) {
+                    vo.setUserAddress(ParseUtils.parseAddress(vo.getUserAddress()));
+                }
+                if (!StringUtils.isEmpty(vo.getJsonInfo())) {
+                    try {
+                        StoreOrderProductDTO orderProductDTO = JSONObject.parseObject(vo.getJsonInfo(), StoreOrderProductDTO.class);
+                        BeanUtil.copyProperties(orderProductDTO, vo);
+                    } catch (Exception e) {
+                    }
+                }
+                if ((loginUser.getPermissions().contains("his:storeAfterSales:finance") || loginUser.getPermissions().contains("*:*:*")) && !Objects.isNull(vo.getCost())) {
+                    vo.setFPrice(vo.getCost().multiply(BigDecimal.valueOf(vo.getTotalNum())));
+                } else {
+                    vo.setPayPostage(BigDecimal.ZERO);
+                    vo.setCost(BigDecimal.ZERO);
+                    vo.setFPrice(BigDecimal.ZERO);
+                    vo.setBarCode("");
+                    vo.setCateName("");
+                    vo.setBankTransactionId("");
+                }
+            }
+        }
+        ExcelUtil<FsStoreOrderItemExportVO> util = new ExcelUtil<FsStoreOrderItemExportVO>(FsStoreOrderItemExportVO.class);
+        return util.exportExcel(list, "订单明细数据");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrder:exportItems:details')")
+    @Log(title = "订单明细导出", businessType = BusinessType.EXPORT)
+    @GetMapping("/exportItemsDetails")
+    public AjaxResult exportItemsDetails(FsStoreOrderParam param)
+    {
+        if ("".equals(param.getBeginTime()) && "".equals(param.getEndTime())) {
+            param.setBeginTime(null);
+            param.setEndTime(null);
+        }
+        if (fsStoreOrderService.isEntityNull(param)) {
+            return AjaxResult.error("请筛选数据导出");
+        }
+        if (!StringUtils.isEmpty(param.getCreateTimeRange())) {
+            param.setCreateTimeList(param.getCreateTimeRange().split("--"));
+        }
+        if (!StringUtils.isEmpty(param.getPayTimeRange())) {
+            param.setPayTimeList(param.getPayTimeRange().split("--"));
+        }
+        if (!StringUtils.isEmpty(param.getDeliveryImportTimeRange())) {
+            param.setDeliveryImportTimeList(param.getDeliveryImportTimeRange().split("--"));
+        }
+        if (!StringUtils.isEmpty(param.getDeliverySendTimeRange())) {
+            param.setDeliverySendTimeList(param.getDeliverySendTimeRange().split("--"));
+        }
+        param.setNotHealth(1);
+        List<FsStoreOrderItemExportVO> list = orderItemService.selectFsStoreOrderItemListExportVO(param);
+        if ("北京卓美".equals(com.fs.config.saas.ProjectConfig.getFromDB(sysConfigMapper).getCloudHost().getCompanyName())) {
+            List<FsStoreOrderItemExportZMVO> zmvoList = list.stream()
+                    .map(vo -> {
+                        FsStoreOrderItemExportZMVO zmvo = new FsStoreOrderItemExportZMVO();
+                        try {
+                            BeanUtil.copyProperties(vo, zmvo);
+                        } catch (Exception e) {
+                            e.printStackTrace();
+                        }
+                        return zmvo;
+                    })
+                    .collect(Collectors.toList());
+            if (zmvoList != null) {
+                LoginUser loginUser = (LoginUser) tokenService.getLoginUser(ServletUtils.getRequest());
+                for (FsStoreOrderItemExportZMVO vo : zmvoList) {
+                    if (!StringUtils.isEmpty(vo.getJsonInfo())) {
+                        try {
+                            StoreOrderProductDTO orderProductDTO = JSONObject.parseObject(vo.getJsonInfo(), StoreOrderProductDTO.class);
+                            BeanUtil.copyProperties(orderProductDTO, vo);
+                        } catch (Exception e) {
+                        }
+                    }
+                    if ((loginUser.getPermissions().contains("his:storeAfterSales:finance") || loginUser.getPermissions().contains("*:*:*")) && !Objects.isNull(vo.getCost())) {
+                        vo.setFPrice(vo.getCost().multiply(BigDecimal.valueOf(vo.getTotalNum())));
+                    } else {
+                        vo.setPayPostage(BigDecimal.ZERO);
+                        vo.setCost(BigDecimal.ZERO);
+                        vo.setFPrice(BigDecimal.ZERO);
+                        vo.setBarCode("");
+                        vo.setCateName("");
+                        vo.setBankTransactionId("");
+                    }
+                }
+            }
+            ExcelUtil<FsStoreOrderItemExportZMVO> util = new ExcelUtil<FsStoreOrderItemExportZMVO>(FsStoreOrderItemExportZMVO.class);
+            return util.exportExcel(zmvoList, "订单明细数据");
+        }
+        if (list != null) {
+            LoginUser loginUser = (LoginUser) tokenService.getLoginUser(ServletUtils.getRequest());
+            for (FsStoreOrderItemExportVO vo : list) {
+                if (!StringUtils.isEmpty(vo.getJsonInfo())) {
+                    try {
+                        StoreOrderProductDTO orderProductDTO = JSONObject.parseObject(vo.getJsonInfo(), StoreOrderProductDTO.class);
+                        BeanUtil.copyProperties(orderProductDTO, vo);
+                    } catch (Exception e) {
+                    }
+                }
+                if ((loginUser.getPermissions().contains("his:storeAfterSales:finance") || loginUser.getPermissions().contains("*:*:*")) && !Objects.isNull(vo.getCost())) {
+                    vo.setFPrice(vo.getCost().multiply(BigDecimal.valueOf(vo.getTotalNum())));
+                } else {
+                    vo.setPayPostage(BigDecimal.ZERO);
+                    vo.setCost(BigDecimal.ZERO);
+                    vo.setFPrice(BigDecimal.ZERO);
+                    vo.setBarCode("");
+                    vo.setCateName("");
+                    vo.setBankTransactionId("");
+                }
+            }
+        }
+        ExcelUtil<FsStoreOrderItemExportVO> util = new ExcelUtil<FsStoreOrderItemExportVO>(FsStoreOrderItemExportVO.class);
+        return util.exportExcel(list, "订单明细数据");
+    }
+
+    @GetMapping("/orderItemsNum")
+    public R orderItemsNum(FsStoreOrderParam param)
+    {
+        if (!StringUtils.isEmpty(param.getCreateTimeRange())) {
+            param.setCreateTimeList(param.getCreateTimeRange().split("--"));
+        }
+        if (!StringUtils.isEmpty(param.getPayTimeRange())) {
+            param.setPayTimeList(param.getPayTimeRange().split("--"));
+        }
+        if (!StringUtils.isEmpty(param.getDeliveryImportTimeRange())) {
+            param.setDeliveryImportTimeList(param.getDeliveryImportTimeRange().split("--"));
+        }
+        if (!StringUtils.isEmpty(param.getDeliverySendTimeRange())) {
+            param.setDeliverySendTimeList(param.getDeliverySendTimeRange().split("--"));
+        }
+        param.setNotHealth(1);
+        Long orderItemsNum = orderItemService.countFsStoreOrderItemListExportVO(param);
+        return R.ok().put("orderItemsNum", "订单明细数目:" + orderItemsNum);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrder:query')")
+    @GetMapping(value = "/{id}")
+    public R getInfo(@PathVariable("id") Long id)
+    {
+        FsStoreOrderScrm order = fsStoreOrderService.selectFsStoreOrderById(id);
+        order.setUserPhone(ParseUtils.parsePhone(order.getUserPhone()));
+        order.setUserAddress(ParseUtils.parseAddress(order.getUserAddress()));
+        FsUser user = userService.selectFsUserById(order.getUserId());
+        if (user != null) {
+            user.setPhone(ParseUtils.parsePhone(user.getPhone()));
+        }
+        FsStoreOrderItemScrm itemMap = new FsStoreOrderItemScrm();
+        itemMap.setOrderId(order.getId());
+        List<FsStoreOrderItemScrm> items = orderItemService.selectFsStoreOrderItemList(itemMap);
+        FsStoreOrderStatusScrm statusMap = new FsStoreOrderStatusScrm();
+        statusMap.setOrderId(order.getId());
+        List<FsStoreOrderStatusScrm> logs = orderStatusService.selectFsStoreOrderStatusList(statusMap);
+        List<FsStorePaymentScrm> payments = paymentService.selectFsStorePaymentByOrderId(order.getId());
+        List<CompanyStoreOrderMoneyLogsVO> tuiMoneyLogs = new ArrayList<>();
+        if (order.getCompanyId() != null) {
+            CompanyStoreOrderMoneyLogsListParam moneyLogsMap = new CompanyStoreOrderMoneyLogsListParam();
+            moneyLogsMap.setCompanyId(order.getCompanyId());
+            moneyLogsMap.setBusinessId(order.getId().toString());
+            tuiMoneyLogs = moneyLogsService.selectCompanyStoreOrderMoneyLogsList(moneyLogsMap);
+        }
+        List<FsStoreOrderAuditLogVO> auditLogs = orderAuditLogService.selectStoreOrderAuditLogVOByOrderId(order.getId());
+        return R.ok().put("order", order).put("items", items).put("logs", logs).put("user", user).put("payments", payments).put("tuiMoneyLogs", tuiMoneyLogs)
+                .put("auditLogs", auditLogs);
+    }
+
+    @GetMapping(value = "/queryAddress/{id}")
+    @PreAuthorize("@ss.hasPermi('store:storeOrder:queryAddress')")
+    public R getAddress(@PathVariable("id") Long id)
+    {
+        FsStoreOrderScrm order = fsStoreOrderService.selectFsStoreOrderById(id);
+        String address = order.getUserAddress();
+        return R.ok().put("address", address);
+    }
+
+    @GetMapping(value = "/queryPhone/{id}")
+    @Log(title = "查看电话", businessType = BusinessType.GRANT)
+    @PreAuthorize("@ss.hasPermi('store:storeOrder:queryPhone')")
+    public R getPhone(@PathVariable("id") Long id)
+    {
+        FsStoreOrderScrm order = fsStoreOrderService.selectFsStoreOrderById(id);
+        String userPhone = order.getUserPhone();
+        return R.ok().put("userPhone", userPhone);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrder:express')")
+    @GetMapping(value = "/getExpress/{id}")
+    public R getExpress(@PathVariable("id") Long id)
+    {
+        FsStoreOrderScrm order = fsStoreOrderService.selectFsStoreOrderById(id);
+        ExpressInfoDTO expressInfoDTO = null;
+        if (StringUtils.isNotEmpty(order.getDeliveryId())) {
+            String lastFourNumber = "";
+            if (order.getDeliverySn().equals(ShipperCodeEnum.SF.getValue()) || order.getDeliverySn().equals(ShipperCodeEnum.ZTO.getValue())) {
+                lastFourNumber = order.getUserPhone();
+                if (lastFourNumber.length() == 11) {
+                    lastFourNumber = StrUtil.sub(lastFourNumber, lastFourNumber.length(), -4);
+                }
+            }
+            expressInfoDTO = expressService.getExpressInfo(order.getOrderCode(), order.getDeliverySn(), order.getDeliveryId(), lastFourNumber);
+        }
+        return R.ok().put("data", expressInfoDTO);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrder:add')")
+    @Log(title = "订单", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsStoreOrderScrm fsStoreOrder)
+    {
+        return toAjax(fsStoreOrderService.insertFsStoreOrder(fsStoreOrder));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrder:edit')")
+    @Log(title = "订单", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsStoreOrderScrm fsStoreOrder)
+    {
+        return toAjax(fsStoreOrderService.updateFsStoreOrder(fsStoreOrder));
+    }
+
+    @Log(title = "修改订单itemJson", businessType = BusinessType.UPDATE)
+    @GetMapping("/updateStoreOrderItemJson/{orderId}/{backendEditProductType}")
+    public AjaxResult updateStoreOrderItemJson(@PathVariable("orderId") Long orderId, @PathVariable("backendEditProductType") Integer backendEditProductType)
+    {
+        return toAjax(fsStoreOrderService.updateStoreOrderItemJson(orderId, backendEditProductType));
+    }
+
+    @Log(title = "修改物流", businessType = BusinessType.UPDATE)
+    @PreAuthorize("@ss.hasPermi('store:storeOrder:editDeliveryId')")
+    @PutMapping("/editDeliveryId")
+    public AjaxResult editDeliveryId(@RequestBody FsStoreOrderScrm fsStoreOrder)
+    {
+        return toAjax(fsStoreOrderService.updateFsStoreOrder(fsStoreOrder));
+    }
+
+    @Log(title = "同步管易物流单号", businessType = BusinessType.UPDATE)
+    @PreAuthorize("@ss.hasPermi('store:storeOrder:updateErpOrder')")
+    @PostMapping("/updateErpOrder")
+    public R updateErpOrder(@Validated @RequestBody FsStoreOrderExpressEditParam param)
+    {
+        FsStoreOrderScrm order = fsStoreOrderService.selectFsStoreOrderById(param.getOrderId());
+        FsErpConfig erpConfig = configUtil.getErpConfig();
+        List<Long> noErpCompany = erpConfig.getNoErpCompany();
+        if (noErpCompany.contains(order.getCompanyId())) {
+            logger.info("订单:{},相关公司不推送erp", order.getOrderCode());
+            return R.ok("订单:" + order.getOrderCode() + "相关公司不推送erp");
+        }
+        IErpOrderService erpOrderService = getErpService();
+        ErpOrderQueryRequert request = new ErpOrderQueryRequert();
+        request.setCode(order.getExtendOrderId());
+        ErpOrderQueryResponse response = erpOrderService.getScrmOrder(request);
+        if (response.getOrders() != null && response.getOrders().size() > 0) {
+            for (ErpOrderQuery orderQuery : response.getOrders()) {
+                if (orderQuery.getDeliverys() != null && orderQuery.getDeliverys().size() > 0) {
+                    for (ErpDeliverys delivery : orderQuery.getDeliverys()) {
+                        if (delivery.getDelivery() && StringUtils.isNotEmpty(delivery.getMail_no())) {
+                            fsStoreOrderService.updateDeliveryOrder(param.getOrderId(), delivery.getMail_no(), delivery.getExpress_code(), delivery.getExpress_name());
+                            return R.ok();
+                        }
+                    }
+                }
+            }
+        }
+        return R.error("未查询到快递信息");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrder:remove')")
+    @Log(title = "订单", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsStoreOrderService.deleteFsStoreOrderByIds(ids));
+    }
+
+    @PostMapping("/createUserOrder")
+    public R createUserOrder(@Validated @RequestBody FsStoreOrderCreateUserParam param, HttpServletRequest request)
+    {
+        return fsStoreOrderService.createUserOrder(param);
+    }
+
+    @Log(title = "确认订单", businessType = BusinessType.UPDATE)
+    @PreAuthorize("@ss.hasPermi('store:storeOrder:finishOrder')")
+    @PostMapping("/finishOrder")
+    public R finishOrder(@Validated @RequestBody FsStoreOrderFinishParam param, HttpServletRequest request)
+    {
+        return fsStoreOrderService.finishOrder(param.getOrderId());
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrder:auditPayRemain')")
+    @PostMapping("/auditPayRemain")
+    public R auditPayRemain(@Validated @RequestBody FsStoreOrderAuditPayRemainParam param, HttpServletRequest request)
+    {
+        return fsStoreOrderService.auditPayRemain(param.getOrderId());
+    }
+
+    @Log(title = "导入", businessType = BusinessType.IMPORT)
+    @PreAuthorize("@ss.hasPermi('store:storeOrder:importExpress')")
+    @PostMapping("/importExpress")
+    public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception
+    {
+        ExcelUtil<StoreOrderExpressExportDTO> util = new ExcelUtil<StoreOrderExpressExportDTO>(StoreOrderExpressExportDTO.class);
+        List<StoreOrderExpressExportDTO> list = util.importExcel(file.getInputStream());
+        String message = fsStoreOrderService.importExpress(list, updateSupport);
+        return AjaxResult.success(message);
+    }
+
+    @GetMapping("/importTemplate")
+    public AjaxResult importTemplate()
+    {
+        ExcelUtil<StoreOrderExpressExportDTO> util = new ExcelUtil<StoreOrderExpressExportDTO>(StoreOrderExpressExportDTO.class);
+        return util.importTemplateExcel("物流回单数据");
+    }
+
+    @GetMapping("/getStoreOrder")
+    public R getStoreOrder(@RequestParam("orderCode") String orderCode)
+    {
+        FsStoreOrderVO vo = fsStoreOrderService.selectFsStoreOrderVOByOrderCode(orderCode);
+        return R.ok().put("data", vo);
+    }
+
+    @Log(title = "冻结、解冻佣金", businessType = BusinessType.UPDATE)
+    @PreAuthorize("@ss.hasPermi('store:storeOrder:editTuiMoney')")
+    @PostMapping("/editTuiMoney")
+    public R editTuiMoney(@Validated @RequestBody FsStoreOrderEditTuiMoneyParam param, HttpServletRequest request)
+    {
+        return fsStoreOrderService.editTuiMoney(param);
+    }
+
+    @Log(title = "退款", businessType = BusinessType.UPDATE)
+    @PreAuthorize("@ss.hasPermi('store:storeOrder:refundOrderMoney')")
+    @PostMapping("/refundOrderMoney")
+    public synchronized R refundOrderMoney(@Validated @RequestBody FsStoreOrderRefundParam param, HttpServletRequest request)
+    {
+        return fsStoreOrderService.refundOrderMoney(param.getOrderId());
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrder:getEroOrder')")
+    @GetMapping("/getEroOrder")
+    public R getEroOrder(@RequestParam("extendOrderId") String extendOrderId)
+    {
+        IErpOrderService erpOrderService = getErpService();
+        ErpOrderQueryRequert request = new ErpOrderQueryRequert();
+        request.setCode(extendOrderId);
+        ErpOrderQueryResponse response = erpOrderService.getScrmOrder(request);
+        return R.ok().put("data", response);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrder:updateExpress')")
+    @PostMapping("/updateExpress")
+    public R updateExpress(@Validated @RequestBody FsStoreOrderExpressEditParam param, HttpServletRequest request)
+    {
+        return fsStoreOrderService.updateExpress(param);
+    }
+
+    @Log(title = "同步物流", businessType = BusinessType.UPDATE)
+    @PreAuthorize("@ss.hasPermi('store:storeOrder:syncExpress')")
+    @PostMapping("/syncExpress")
+    public R syncExpress(@Validated @RequestBody FsStoreOrderExpressEditParam param, HttpServletRequest request)
+    {
+        return fsStoreOrderService.syncExpress(param);
+    }
+
+    @Log(title = "分佣", businessType = BusinessType.UPDATE)
+    @PreAuthorize("@ss.hasPermi('store:storeOrder:addTuiMoney')")
+    @PostMapping("/addTuiMoney")
+    public R addTuiMoney(@Validated @RequestBody FsStoreOrderAddTuiMoneyParam param, HttpServletRequest request)
+    {
+        return fsStoreOrderService.addTuiMoney(param);
+    }
+
+    @GetMapping("/getCustomerOrderList")
+    public TableDataInfo getCustomerOrderList(FsStoreOrderParam param)
+    {
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        List<FsStoreOrderVO> list = fsStoreOrderService.selectFsCustomerStoreOrderListVO(param);
+        if (list != null) {
+            for (FsStoreOrderVO vo : list) {
+                if (vo.getPhone() != null) {
+                    vo.setPhone(vo.getPhone().replaceAll("(\\d{3})\\d*(\\d{1})", "$1****$2"));
+                    vo.setUserPhone(vo.getUserPhone().replaceAll("(\\d{3})\\d*(\\d{1})", "$1****$2"));
+                }
+            }
+        }
+        return getDataTable(list);
+    }
+
+    @Log(title = "手动推管易", businessType = BusinessType.INSERT)
+    @ApiOperation("创建ERP订单")
+    @PreAuthorize("@ss.hasPermi('store:storeOrder:createErpOrder')")
+    @GetMapping("/createErpOrder")
+    public R createErpOrder(@RequestParam("orderCode") String orderCode) throws Exception
+    {
+        logger.info("手动推管易订单号:{}", orderCode);
+        FsStoreOrderScrm order = fsStoreOrderService.selectFsStoreOrderByOrderCode(orderCode);
+        return fsStoreOrderService.createOmsOrder(order.getId());
+    }
+
+    @GetMapping("/orderDimensionStatisticsList")
+    public TableDataInfo orderDimensionStatisticsList(OrderStatisticsParam param)
+    {
+        if ("广州郑多燕".equals(cloudHostProper.getCompanyName())) {
+            return getDataTable(fsStoreOrderService.selectZDYOrderSaleStatisticsList(param));
+        }
+        return getDataTable(fsStoreOrderService.selectOrderDimensionStatisticsList(param));
+    }
+
+    @Log(title = "订单维度统计", businessType = BusinessType.EXPORT)
+    @GetMapping("/orderDimensionStatisticsExport")
+    public AjaxResult orderDimensionStatisticsExport(OrderStatisticsParam param)
+    {
+        List<OrderStatisticsVo> list = fsStoreOrderService.selectOrderDimensionStatisticsList(param);
+        ExcelUtil<OrderStatisticsVo> util = new ExcelUtil<>(OrderStatisticsVo.class);
+        return util.exportExcel(list, "订单员工维度统计");
+    }
+
+    @GetMapping(value = "/queryErpPhone")
+    public AjaxResult queryErpPhone()
+    {
+        SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("erp.phone");
+        List<String> list = new ArrayList<>();
+        if (sysConfig != null) {
+            String configValue = sysConfig.getConfigValue();
+            if (StringUtils.isNotEmpty(configValue)) {
+                list = JSON.parseArray(configValue, String.class);
+            }
+        }
+        return AjaxResult.success(list);
+    }
+
+    @PostMapping(value = "/saveErpPhone")
+    public AjaxResult saveErpPhone(@RequestBody List<String> phoneList)
+    {
+        phoneList = phoneList.stream().distinct().collect(Collectors.toList());
+        SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("erp.phone");
+        sysConfig.setConfigValue(JSON.toJSONString(phoneList));
+        return AjaxResult.success(sysConfigMapper.updateConfig(sysConfig));
+    }
+
+    @PreAuthorize("@ss.hasPermi('his:storeOrder:createErpOrder')")
+    @Log(title = "订单", businessType = BusinessType.UPDATE)
+    @PostMapping("/editErpPhone")
+    public AjaxResult editErpPhone(@RequestBody FsStoreOrderScrmSetErpPhoneParam param)
+    {
+        param.setOpeName(SecurityUtils.getLoginUser().getUser().getNickName());
+        List<String> erpPhone = param.getErpPhone();
+        if (erpPhone == null || erpPhone.isEmpty()) {
+            return AjaxResult.error("请选择手机号");
+        }
+        return toAjax(fsStoreOrderService.batchUpdateErpByOrderIds(param));
+    }
+
+    @GetMapping("/getErpAccount")
+    public R getErpAccount()
+    {
+        List<String> list = new ArrayList<>();
+        if (CloudHostUtils.hasCloudHostName("金牛明医", "康年堂")) {
+            List<FsDfAccount> erpAccounts = fsDfAccountService.selectFsDfAccountList(null);
+            list = erpAccounts.stream().map(FsDfAccount::getLoginAccount).collect(Collectors.toList());
+        }
+        return R.ok().put("data", list);
+    }
+
+    @Log(title = "手动推管易", businessType = BusinessType.INSERT)
+    @ApiOperation("批量创建ERP订单")
+    @PreAuthorize("@ss.hasPermi('his:storeOrder:createErpOrder')")
+    @PostMapping(value = "/batchCreateErpOrder")
+    public R batchCreateErpOrder(@RequestBody FsStoreOrderScrmSetErpPhoneParam param)
+    {
+        String nickName = SecurityUtils.getLoginUser().getUser().getNickName();
+        String loginAccount = param.getLoginAccount();
+        if (StringUtils.isBlank(loginAccount)) {
+            return R.error("未选择推送erp账户");
+        }
+        FsStoreOrderDf df = getDFInfo(loginAccount);
+        if (df.getLoginAccount() == null) {
+            return R.error("未查询到所选erp账户");
+        }
+        List<Long> orderIds = param.getOrderIds();
+        if (orderIds == null || orderIds.isEmpty()) {
+            if (!StringUtils.isEmpty(param.getCreateTimeRange())) {
+                param.setCreateTimeList(param.getCreateTimeRange().split("--"));
+            }
+            if (!StringUtils.isEmpty(param.getPayTimeRange())) {
+                param.setPayTimeList(param.getPayTimeRange().split("--"));
+            }
+            if (!StringUtils.isEmpty(param.getDeliveryImportTimeRange())) {
+                param.setDeliveryImportTimeList(param.getDeliveryImportTimeRange().split("--"));
+            }
+            if (!StringUtils.isEmpty(param.getDeliverySendTimeRange())) {
+                param.setDeliverySendTimeList(param.getDeliverySendTimeRange().split("--"));
+            }
+            param.setNotHealth(1);
+            List<FsStoreOrderVO> list = fsStoreOrderService.selectFsStoreOrderListVO(param);
+            orderIds = list.stream().map(FsStoreOrderVO::getId).collect(Collectors.toList());
+        }
+        if (orderIds.isEmpty()) {
+            return R.ok();
+        }
+        orderIds.forEach(orderId -> {
+            try {
+                df.setOrderId(orderId);
+                FsStoreOrderDf temp = fsStoreOrderDfService.selectFsStoreOrderDfByOrderId(df.getOrderId());
+                if (temp == null) {
+                    df.setParcelQuantity(param.getParcelQuantity());
+                    fsStoreOrderDfService.insertFsStoreOrderDf(df);
+                    fsStoreOrderLogsService.create(orderId, FsStoreOrderLogEnum.SET_PUSH_ACCOUNT.getValue(),
+                            nickName + " " + FsStoreOrderLogEnum.SET_PUSH_ACCOUNT.getDesc() + ":" + df.getLoginAccount());
+                }
+                fsStoreOrderService.createOmsOrder(orderId);
+                fsStoreOrderLogsService.create(orderId, FsStoreOrderLogEnum.PUSH_ORDER_ERP.getValue(),
+                        nickName + " " + FsStoreOrderLogEnum.PUSH_ORDER_ERP.getDesc() + ":" + df.getLoginAccount());
+            } catch (ParseException e) {
+                throw new RuntimeException(e);
+            }
+        });
+        return R.ok();
+    }
+
+    @ApiOperation("批量设置订单账户")
+    @PreAuthorize("@ss.hasPermi('his:storeOrder:createErpOrder')")
+    @PostMapping(value = "/batchSetErpOrder")
+    public R batchSetErpOrder(@RequestBody FsStoreOrderScrmSetErpPhoneParam param)
+    {
+        String nickName = SecurityUtils.getLoginUser().getUser().getNickName();
+        String loginAccount = param.getLoginAccount();
+        if (StringUtils.isBlank(loginAccount)) {
+            return R.error("未选择erp账户");
+        }
+        FsStoreOrderDf df = getDFInfo(loginAccount);
+        if (df.getLoginAccount() == null) {
+            return R.error("未查询到所选erp账户");
+        }
+        List<Long> orderIds = param.getOrderIds();
+        if (orderIds == null || orderIds.isEmpty()) {
+            if (!StringUtils.isEmpty(param.getCreateTimeRange())) {
+                param.setCreateTimeList(param.getCreateTimeRange().split("--"));
+            }
+            if (!StringUtils.isEmpty(param.getPayTimeRange())) {
+                param.setPayTimeList(param.getPayTimeRange().split("--"));
+            }
+            if (!StringUtils.isEmpty(param.getDeliveryImportTimeRange())) {
+                param.setDeliveryImportTimeList(param.getDeliveryImportTimeRange().split("--"));
+            }
+            if (!StringUtils.isEmpty(param.getDeliverySendTimeRange())) {
+                param.setDeliverySendTimeList(param.getDeliverySendTimeRange().split("--"));
+            }
+            param.setNotHealth(1);
+            List<FsStoreOrderVO> list = fsStoreOrderService.selectFsStoreOrderListVO(param);
+            orderIds = list.stream().map(FsStoreOrderVO::getId).collect(Collectors.toList());
+        }
+        if (orderIds.isEmpty()) {
+            return R.ok();
+        }
+        orderIds.forEach(orderId -> {
+            df.setOrderId(orderId);
+            FsStoreOrderDf temp = fsStoreOrderDfService.selectFsStoreOrderDfByOrderId(df.getOrderId());
+            df.setParcelQuantity(param.getParcelQuantity());
+            if (temp != null) {
+                df.setUpdateTime(new Date());
+                fsStoreOrderDfService.updateFsStoreOrderDf(df);
+            } else {
+                fsStoreOrderDfService.insertFsStoreOrderDf(df);
+            }
+            fsStoreOrderLogsService.create(orderId, FsStoreOrderLogEnum.SET_PUSH_ACCOUNT.getValue(),
+                    nickName + " " + FsStoreOrderLogEnum.SET_PUSH_ACCOUNT.getDesc() + ":" + df.getLoginAccount());
+        });
+        return R.ok();
+    }
+
+    @ApiOperation("批量审核订单")
+    @Log(title = "订单管理", businessType = BusinessType.UPDATE)
+    @PreAuthorize("@ss.hasPermi('store:storeOrder:batchAudit')")
+    @PostMapping("/batchAudit")
+    public R batchAuditOrder(@Validated @RequestBody FsStoreOrderBatchAuditParam param)
+    {
+        if (param.getOrderIds() == null || param.getOrderIds().isEmpty()) {
+            return R.error("订单ID列表不能为空");
+        }
+        if (param.getIsAudit() == null) {
+            return R.error("审核状态不能为空");
+        }
+        int count = fsStoreOrderService.batchAuditOrder(param);
+        return R.ok("成功审核 " + count + " 条订单");
+    }
+
+    @ApiOperation("订单备注")
+    @Log(title = "订单管理", businessType = BusinessType.UPDATE)
+    @PreAuthorize("@ss.hasPermi('store:storeOrder:remark')")
+    @PostMapping("/remark")
+    public R remark(@Validated @RequestBody FsStoreOrderScrm param)
+    {
+        if (param.getId() == null || param.getId() < 1) {
+            return R.error("订单ID错误");
+        }
+        if (StringUtils.isEmpty(param.getOrderRemark())) {
+            return R.error("订单备注不能为空");
+        }
+        return fsStoreOrderService.orderRemark(param);
+    }
+
+    private SysRole isCheckPermission()
+    {
+        SysRole sysRole = new SysRole();
+        SysUser user = SecurityUtils.getLoginUser().getUser();
+        boolean flag = user.isAdmin();
+        if (flag) {
+            sysRole.setIsCheckPhone(1);
+            sysRole.setIsCheckAddress(1);
+        } else {
+            List<SysRole> roles = user.getRoles();
+            if (roles != null && !roles.isEmpty()) {
+                Long[] roleIds = roles.stream().map(SysRole::getRoleId).toArray(Long[]::new);
+                return sysRoleService.getIsCheckPermission(roleIds);
+            }
+        }
+        return sysRole;
+    }
+
+    private FsStoreOrderDf getDFInfo(String loginAccount)
+    {
+        List<FsDfAccount> erpAccounts = fsDfAccountService.selectFsDfAccountList(null);
+        FsStoreOrderDf df = new FsStoreOrderDf();
+        for (FsDfAccount erpAccount : erpAccounts) {
+            if (loginAccount.equals(erpAccount.getLoginAccount())) {
+                df.setAppKey(erpAccount.getDfAppKey());
+                df.setAppSecret(erpAccount.getDfAppsecret());
+                df.setLoginAccount(loginAccount);
+                df.setMonthlyCard(erpAccount.getMonthlyCard());
+                df.setExpressProductCode(erpAccount.getExpressProductCode());
+                df.setStatus(0);
+                break;
+            }
+        }
+        return df;
+    }
+}

+ 80 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreOrderStatusScrmBridgeController.java

@@ -0,0 +1,80 @@
+package com.fs.admin.controller.store;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.FsStoreOrderStatusScrm;
+import com.fs.hisStore.service.IFsStoreOrderStatusScrmService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 订单操作记录 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsStoreOrderStatusScrmController,供平台总后台跨租户管理
+ *
+ * @author fs
+ * @date 2022-03-15
+ */
+@RestController
+@RequestMapping("/store/store/storeOrderStatus")
+public class FsStoreOrderStatusScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsStoreOrderStatusScrmService fsStoreOrderStatusService;
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrderStatus:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsStoreOrderStatusScrm fsStoreOrderStatus)
+    {
+        startPage();
+        List<FsStoreOrderStatusScrm> list = fsStoreOrderStatusService.selectFsStoreOrderStatusList(fsStoreOrderStatus);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrderStatus:export')")
+    @Log(title = "订单操作记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsStoreOrderStatusScrm fsStoreOrderStatus)
+    {
+        List<FsStoreOrderStatusScrm> list = fsStoreOrderStatusService.selectFsStoreOrderStatusList(fsStoreOrderStatus);
+        ExcelUtil<FsStoreOrderStatusScrm> util = new ExcelUtil<FsStoreOrderStatusScrm>(FsStoreOrderStatusScrm.class);
+        return util.exportExcel(list, "storeOrderStatus");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrderStatus:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsStoreOrderStatusService.selectFsStoreOrderStatusById(id));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrderStatus:add')")
+    @Log(title = "订单操作记录", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsStoreOrderStatusScrm fsStoreOrderStatus)
+    {
+        return toAjax(fsStoreOrderStatusService.insertFsStoreOrderStatus(fsStoreOrderStatus));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrderStatus:edit')")
+    @Log(title = "订单操作记录", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsStoreOrderStatusScrm fsStoreOrderStatus)
+    {
+        return toAjax(fsStoreOrderStatusService.updateFsStoreOrderStatus(fsStoreOrderStatus));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeOrderStatus:remove')")
+    @Log(title = "订单操作记录", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsStoreOrderStatusService.deleteFsStoreOrderStatusByIds(ids));
+    }
+}

+ 80 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreProductAttrScrmBridgeController.java

@@ -0,0 +1,80 @@
+package com.fs.admin.controller.store;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.FsStoreProductAttrScrm;
+import com.fs.hisStore.service.IFsStoreProductAttrScrmService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 商品属性 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsStoreProductAttrScrmController,供平台总后台跨租户管理
+ *
+ * @author fs
+ * @date 2022-03-15
+ */
+@RestController
+@RequestMapping("/store/store/storeProductAttr")
+public class FsStoreProductAttrScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsStoreProductAttrScrmService fsStoreProductAttrService;
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductAttr:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsStoreProductAttrScrm fsStoreProductAttr)
+    {
+        startPage();
+        List<FsStoreProductAttrScrm> list = fsStoreProductAttrService.selectFsStoreProductAttrList(fsStoreProductAttr);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductAttr:export')")
+    @Log(title = "商品属性", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsStoreProductAttrScrm fsStoreProductAttr)
+    {
+        List<FsStoreProductAttrScrm> list = fsStoreProductAttrService.selectFsStoreProductAttrList(fsStoreProductAttr);
+        ExcelUtil<FsStoreProductAttrScrm> util = new ExcelUtil<FsStoreProductAttrScrm>(FsStoreProductAttrScrm.class);
+        return util.exportExcel(list, "storeProductAttr");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductAttr:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsStoreProductAttrService.selectFsStoreProductAttrById(id));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductAttr:add')")
+    @Log(title = "商品属性", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsStoreProductAttrScrm fsStoreProductAttr)
+    {
+        return toAjax(fsStoreProductAttrService.insertFsStoreProductAttr(fsStoreProductAttr));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductAttr:edit')")
+    @Log(title = "商品属性", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsStoreProductAttrScrm fsStoreProductAttr)
+    {
+        return toAjax(fsStoreProductAttrService.updateFsStoreProductAttr(fsStoreProductAttr));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductAttr:remove')")
+    @Log(title = "商品属性", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsStoreProductAttrService.deleteFsStoreProductAttrByIds(ids));
+    }
+}

+ 80 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreProductAttrValueScrmBridgeController.java

@@ -0,0 +1,80 @@
+package com.fs.admin.controller.store;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.FsStoreProductAttrValueScrm;
+import com.fs.hisStore.service.IFsStoreProductAttrValueScrmService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 商品属性值 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsStoreProductAttrValueScrmController,供平台总后台跨租户管理
+ *
+ * @author fs
+ * @date 2022-03-15
+ */
+@RestController
+@RequestMapping("/store/store/storeProductAttrValue")
+public class FsStoreProductAttrValueScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsStoreProductAttrValueScrmService fsStoreProductAttrValueService;
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductAttrValue:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsStoreProductAttrValueScrm fsStoreProductAttrValue)
+    {
+        startPage();
+        List<FsStoreProductAttrValueScrm> list = fsStoreProductAttrValueService.selectFsStoreProductAttrValueList(fsStoreProductAttrValue);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductAttrValue:export')")
+    @Log(title = "商品属性值", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsStoreProductAttrValueScrm fsStoreProductAttrValue)
+    {
+        List<FsStoreProductAttrValueScrm> list = fsStoreProductAttrValueService.selectFsStoreProductAttrValueList(fsStoreProductAttrValue);
+        ExcelUtil<FsStoreProductAttrValueScrm> util = new ExcelUtil<FsStoreProductAttrValueScrm>(FsStoreProductAttrValueScrm.class);
+        return util.exportExcel(list, "storeProductAttrValue");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductAttrValue:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsStoreProductAttrValueService.selectFsStoreProductAttrValueById(id));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductAttrValue:add')")
+    @Log(title = "商品属性值", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsStoreProductAttrValueScrm fsStoreProductAttrValue)
+    {
+        return toAjax(fsStoreProductAttrValueService.insertFsStoreProductAttrValue(fsStoreProductAttrValue));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductAttrValue:edit')")
+    @Log(title = "商品属性值", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsStoreProductAttrValueScrm fsStoreProductAttrValue)
+    {
+        return toAjax(fsStoreProductAttrValueService.updateFsStoreProductAttrValue(fsStoreProductAttrValue));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductAttrValue:remove')")
+    @Log(title = "商品属性值", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsStoreProductAttrValueService.deleteFsStoreProductAttrValueByIds(ids));
+    }
+}

+ 80 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreProductCategoryScrmBridgeController.java

@@ -0,0 +1,80 @@
+package com.fs.admin.controller.store;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.FsStoreProductCategoryScrm;
+import com.fs.hisStore.service.IFsStoreProductCategoryScrmService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 商品分类 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsStoreProductCategoryScrmController,供平台总后台跨租户管理
+ *
+ * @author fs
+ * @date 2022-03-16
+ */
+@RestController
+@RequestMapping("/store/store/storeProductCategory")
+public class FsStoreProductCategoryScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsStoreProductCategoryScrmService fsStoreProductCategoryService;
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductCategory:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsStoreProductCategoryScrm fsStoreProductCategory)
+    {
+        startPage();
+        List<FsStoreProductCategoryScrm> list = fsStoreProductCategoryService.selectFsStoreProductCategoryList(fsStoreProductCategory);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductCategory:export')")
+    @Log(title = "商品分类", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsStoreProductCategoryScrm fsStoreProductCategory)
+    {
+        List<FsStoreProductCategoryScrm> list = fsStoreProductCategoryService.selectFsStoreProductCategoryList(fsStoreProductCategory);
+        ExcelUtil<FsStoreProductCategoryScrm> util = new ExcelUtil<FsStoreProductCategoryScrm>(FsStoreProductCategoryScrm.class);
+        return util.exportExcel(list, "商品分类");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductCategory:query')")
+    @GetMapping(value = "/{cateId}")
+    public AjaxResult getInfo(@PathVariable("cateId") Long cateId)
+    {
+        return AjaxResult.success(fsStoreProductCategoryService.selectFsStoreProductCategoryById(cateId));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductCategory:add')")
+    @Log(title = "商品分类", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsStoreProductCategoryScrm fsStoreProductCategory)
+    {
+        return toAjax(fsStoreProductCategoryService.insertFsStoreProductCategory(fsStoreProductCategory));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductCategory:edit')")
+    @Log(title = "商品分类", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsStoreProductCategoryScrm fsStoreProductCategory)
+    {
+        return toAjax(fsStoreProductCategoryService.updateFsStoreProductCategory(fsStoreProductCategory));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductCategory:remove')")
+    @Log(title = "商品分类", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{cateIds}")
+    public AjaxResult remove(@PathVariable Long[] cateIds)
+    {
+        return toAjax(fsStoreProductCategoryService.deleteFsStoreProductCategoryByIds(cateIds));
+    }
+}

+ 80 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreProductDetailsScrmBridgeController.java

@@ -0,0 +1,80 @@
+package com.fs.admin.controller.store;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.FsStoreProductDetailsScrm;
+import com.fs.hisStore.service.IFsStoreProductDetailsScrmService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 商品详情 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsStoreProductDetailsScrmController,供平台总后台跨租户管理
+ *
+ * @author fs
+ * @date 2022-03-15
+ */
+@RestController
+@RequestMapping("/store/store/storeProductDetails")
+public class FsStoreProductDetailsScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsStoreProductDetailsScrmService fsStoreProductDetailsService;
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductDetails:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsStoreProductDetailsScrm fsStoreProductDetails)
+    {
+        startPage();
+        List<FsStoreProductDetailsScrm> list = fsStoreProductDetailsService.selectFsStoreProductDetailsList(fsStoreProductDetails);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductDetails:export')")
+    @Log(title = "商品详情", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsStoreProductDetailsScrm fsStoreProductDetails)
+    {
+        List<FsStoreProductDetailsScrm> list = fsStoreProductDetailsService.selectFsStoreProductDetailsList(fsStoreProductDetails);
+        ExcelUtil<FsStoreProductDetailsScrm> util = new ExcelUtil<FsStoreProductDetailsScrm>(FsStoreProductDetailsScrm.class);
+        return util.exportExcel(list, "storeProductDetails");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductDetails:query')")
+    @GetMapping(value = "/{detailsId}")
+    public AjaxResult getInfo(@PathVariable("detailsId") Long detailsId)
+    {
+        return AjaxResult.success(fsStoreProductDetailsService.selectFsStoreProductDetailsById(detailsId));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductDetails:add')")
+    @Log(title = "商品详情", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsStoreProductDetailsScrm fsStoreProductDetails)
+    {
+        return toAjax(fsStoreProductDetailsService.insertFsStoreProductDetails(fsStoreProductDetails));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductDetails:edit')")
+    @Log(title = "商品详情", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsStoreProductDetailsScrm fsStoreProductDetails)
+    {
+        return toAjax(fsStoreProductDetailsService.updateFsStoreProductDetails(fsStoreProductDetails));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductDetails:remove')")
+    @Log(title = "商品详情", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{detailsIds}")
+    public AjaxResult remove(@PathVariable Long[] detailsIds)
+    {
+        return toAjax(fsStoreProductDetailsService.deleteFsStoreProductDetailsByIds(detailsIds));
+    }
+}

+ 115 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreProductGroupScrmBridgeController.java

@@ -0,0 +1,115 @@
+package com.fs.admin.controller.store;
+
+import cn.hutool.json.JSONArray;
+import cn.hutool.json.JSONUtil;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.FsStoreProductScrm;
+import com.fs.hisStore.domain.FsStoreProductAttrValueScrm;
+import com.fs.hisStore.domain.FsStoreProductGroupScrm;
+import com.fs.hisStore.dto.StoreProductGroupDTO;
+import com.fs.hisStore.service.IFsStoreProductAttrValueScrmService;
+import com.fs.hisStore.service.IFsStoreProductGroupScrmService;
+import com.fs.hisStore.service.IFsStoreProductScrmService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 商品组合 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsStoreProductGroupScrmController,供平台总后台跨租户管理
+ *
+ * @author fs
+ * @date 2022-11-23
+ */
+@RestController
+@RequestMapping("/store/store/storeProductGroup")
+public class FsStoreProductGroupScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsStoreProductGroupScrmService fsStoreProductGroupService;
+    @Autowired
+    private IFsStoreProductAttrValueScrmService attrValueService;
+    @Autowired
+    private IFsStoreProductScrmService storeProductService;
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductGroup:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsStoreProductGroupScrm fsStoreProductGroup)
+    {
+        startPage();
+        List<FsStoreProductGroupScrm> list = fsStoreProductGroupService.selectFsStoreProductGroupList(fsStoreProductGroup);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductGroup:export')")
+    @Log(title = "商品组合", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsStoreProductGroupScrm fsStoreProductGroup)
+    {
+        List<FsStoreProductGroupScrm> list = fsStoreProductGroupService.selectFsStoreProductGroupList(fsStoreProductGroup);
+        ExcelUtil<FsStoreProductGroupScrm> util = new ExcelUtil<FsStoreProductGroupScrm>(FsStoreProductGroupScrm.class);
+        return util.exportExcel(list, "storeProductGroup");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductGroup:query')")
+    @GetMapping(value = "/{groupId}")
+    public AjaxResult getInfo(@PathVariable("groupId") Long groupId)
+    {
+        FsStoreProductGroupScrm storeProductGroup = fsStoreProductGroupService.selectFsStoreProductGroupById(groupId);
+        JSONArray jsonArray = JSONUtil.parseArray(storeProductGroup.getProducts());
+        List<StoreProductGroupDTO> productGroupDTOS = JSONUtil.toList(jsonArray, StoreProductGroupDTO.class);
+        for (StoreProductGroupDTO dto : productGroupDTOS) {
+            FsStoreProductAttrValueScrm attrValue = attrValueService.selectFsStoreProductAttrValueById(dto.getId());
+            if (attrValue != null) {
+                FsStoreProductScrm product = storeProductService.selectFsStoreProductById(attrValue.getProductId());
+                if (product != null) {
+                    dto.setProductId(attrValue.getProductId());
+                    dto.setId(dto.getId());
+                    dto.setBarCode(attrValue.getBarCode());
+                    dto.setPrice(attrValue.getPrice());
+                    dto.setCount(dto.getCount());
+                    dto.setSku(attrValue.getSku());
+                    dto.setImage(attrValue.getImage());
+                    dto.setProductName(product.getProductName());
+                }
+            }
+        }
+        storeProductGroup.setProductList(productGroupDTOS);
+        return AjaxResult.success(storeProductGroup);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductGroup:add')")
+    @Log(title = "商品组合", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsStoreProductGroupScrm fsStoreProductGroup)
+    {
+        String products = JSONUtil.toJsonStr(fsStoreProductGroup.getProductList());
+        fsStoreProductGroup.setProducts(products);
+        return toAjax(fsStoreProductGroupService.insertFsStoreProductGroup(fsStoreProductGroup));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductGroup:edit')")
+    @Log(title = "商品组合", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsStoreProductGroupScrm fsStoreProductGroup)
+    {
+        String products = JSONUtil.toJsonStr(fsStoreProductGroup.getProductList());
+        fsStoreProductGroup.setProducts(products);
+        return toAjax(fsStoreProductGroupService.updateFsStoreProductGroup(fsStoreProductGroup));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductGroup:remove')")
+    @Log(title = "商品组合", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{groupIds}")
+    public AjaxResult remove(@PathVariable Long[] groupIds)
+    {
+        return toAjax(fsStoreProductGroupService.deleteFsStoreProductGroupByIds(groupIds));
+    }
+}

+ 59 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreProductRelationScrmBridgeController.java

@@ -0,0 +1,59 @@
+package com.fs.admin.controller.store;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ParseUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.param.FsStoreProductRelationParam;
+import com.fs.hisStore.service.IFsStoreProductRelationScrmService;
+import com.fs.hisStore.vo.FsStoreProductRelationQueryVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * 商品点赞和收藏 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsStoreProductRelationScrmController,供平台总后台跨租户管理
+ *
+ * @author fs
+ * @date 2022-03-15
+ */
+@RestController
+@RequestMapping("/store/store/storeProductRelation")
+public class FsStoreProductRelationScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsStoreProductRelationScrmService fsStoreProductRelationService;
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductRelation:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsStoreProductRelationParam param)
+    {
+        startPage();
+        List<FsStoreProductRelationQueryVO> list = fsStoreProductRelationService.selectFsStoreProductRelationListVO(param);
+        for (FsStoreProductRelationQueryVO vo : list){
+            vo.setPhone(ParseUtils.parsePhone(vo.getPhone()));
+        }
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductRelation:export')")
+    @Log(title = "商品浏览记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsStoreProductRelationParam param)
+    {
+        List<FsStoreProductRelationQueryVO> list = fsStoreProductRelationService.selectFsStoreProductRelationListVO(param);
+        for (FsStoreProductRelationQueryVO vo : list){
+            vo.setPhone(ParseUtils.parsePhone(vo.getPhone()));
+        }
+        ExcelUtil<FsStoreProductRelationQueryVO> util = new ExcelUtil<FsStoreProductRelationQueryVO>(FsStoreProductRelationQueryVO.class);
+        return util.exportExcel(list, "商品浏览记录");
+    }
+}

+ 93 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreProductReplyScrmBridgeController.java

@@ -0,0 +1,93 @@
+package com.fs.admin.controller.store;
+
+import cn.hutool.core.date.DateTime;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.FsStoreProductReplyScrm;
+import com.fs.hisStore.service.IFsStoreProductReplyScrmService;
+import com.fs.hisStore.vo.FsStoreProductReplyVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 评论 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsStoreProductReplyScrmController,供平台总后台跨租户管理
+ *
+ * @author fs
+ * @date 2022-03-15
+ */
+@RestController
+@RequestMapping("/store/store/storeProductReply")
+public class FsStoreProductReplyScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsStoreProductReplyScrmService fsStoreProductReplyService;
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductReply:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsStoreProductReplyScrm fsStoreProductReply)
+    {
+        startPage();
+        fsStoreProductReply.setIsDel(0);
+        List<FsStoreProductReplyVO> list = fsStoreProductReplyService.selectFsStoreProductReplyListVO(fsStoreProductReply);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductReply:export')")
+    @Log(title = "评论", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsStoreProductReplyScrm fsStoreProductReply)
+    {
+        List<FsStoreProductReplyScrm> list = fsStoreProductReplyService.selectFsStoreProductReplyList(fsStoreProductReply);
+        ExcelUtil<FsStoreProductReplyScrm> util = new ExcelUtil<FsStoreProductReplyScrm>(FsStoreProductReplyScrm.class);
+        return util.exportExcel(list, "storeProductReply");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductReply:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsStoreProductReplyService.selectFsStoreProductReplyById(id));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductReply:add')")
+    @Log(title = "评论", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsStoreProductReplyScrm fsStoreProductReply)
+    {
+        return toAjax(fsStoreProductReplyService.insertFsStoreProductReply(fsStoreProductReply));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductReply:edit')")
+    @Log(title = "评论", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsStoreProductReplyScrm fsStoreProductReply)
+    {
+        return toAjax(fsStoreProductReplyService.updateFsStoreProductReply(fsStoreProductReply));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductReply:remove')")
+    @Log(title = "评论", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsStoreProductReplyService.deleteFsStoreProductReplyByIds(ids));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductReply:reply')")
+    @Log(title = "评论回复", businessType = BusinessType.INSERT)
+    @PostMapping("/reply")
+    public AjaxResult reply(@RequestBody FsStoreProductReplyScrm fsStoreProductReply)
+    {
+        fsStoreProductReply.setIsReply(1);
+        fsStoreProductReply.setReplyTime(new DateTime());
+        return toAjax(fsStoreProductReplyService.updateFsStoreProductReply(fsStoreProductReply));
+    }
+}

+ 101 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreProductRuleScrmBridgeController.java

@@ -0,0 +1,101 @@
+package com.fs.admin.controller.store;
+
+import cn.hutool.json.JSONUtil;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.FsStoreProductRuleScrm;
+import com.fs.hisStore.param.FsStoreProductRuleParam;
+import com.fs.hisStore.service.IFsStoreProductRuleScrmService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 商品规格 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsStoreProductRuleScrmController,供平台总后台跨租户管理
+ *
+ * @author fs
+ * @date 2022-03-15
+ */
+@RestController
+@RequestMapping("/store/store/storeProductRule")
+public class FsStoreProductRuleScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsStoreProductRuleScrmService fsStoreProductRuleService;
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductRule:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsStoreProductRuleScrm fsStoreProductRule)
+    {
+        startPage();
+        fsStoreProductRule.setIsDel(0);
+        List<FsStoreProductRuleScrm> list = fsStoreProductRuleService.selectFsStoreProductRuleList(fsStoreProductRule);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductRule:export')")
+    @Log(title = "商品规格", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsStoreProductRuleScrm fsStoreProductRule)
+    {
+        List<FsStoreProductRuleScrm> list = fsStoreProductRuleService.selectFsStoreProductRuleList(fsStoreProductRule);
+        ExcelUtil<FsStoreProductRuleScrm> util = new ExcelUtil<FsStoreProductRuleScrm>(FsStoreProductRuleScrm.class);
+        return util.exportExcel(list, "storeProductRule");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductRule:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Integer id)
+    {
+        return AjaxResult.success(fsStoreProductRuleService.selectFsStoreProductRuleById(id));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductRule:add')")
+    @Log(title = "商品规格", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsStoreProductRuleParam fsStoreProductRule)
+    {
+        FsStoreProductRuleScrm rule = new FsStoreProductRuleScrm();
+        rule.setRuleName(fsStoreProductRule.getRuleName());
+        rule.setRuleValue(JSONUtil.toJsonStr(fsStoreProductRule.getRuleValue()));
+        rule.setIsDel(0);
+        return toAjax(fsStoreProductRuleService.insertFsStoreProductRule(rule));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductRule:edit')")
+    @Log(title = "商品规格", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsStoreProductRuleParam fsStoreProductRule)
+    {
+        FsStoreProductRuleScrm rule = new FsStoreProductRuleScrm();
+        rule.setId(fsStoreProductRule.getId());
+        rule.setRuleName(fsStoreProductRule.getRuleName());
+        rule.setRuleValue(JSONUtil.toJsonStr(fsStoreProductRule.getRuleValue()));
+        rule.setIsDel(0);
+        return toAjax(fsStoreProductRuleService.updateFsStoreProductRule(rule));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductRule:remove')")
+    @Log(title = "商品规格", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Integer[] ids)
+    {
+        return toAjax(fsStoreProductRuleService.deleteFsStoreProductRuleByIds(ids));
+    }
+
+    @GetMapping("/getAllList")
+    public R getAllList(FsStoreProductRuleScrm fsStoreProductRule)
+    {
+        fsStoreProductRule.setIsDel(0);
+        List<FsStoreProductRuleScrm> list = fsStoreProductRuleService.selectFsStoreProductRuleList(fsStoreProductRule);
+        return R.ok().put("data", list);
+    }
+}

+ 80 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreProductTemplateScrmBridgeController.java

@@ -0,0 +1,80 @@
+package com.fs.admin.controller.store;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.FsStoreProductTemplateScrm;
+import com.fs.hisStore.service.IFsStoreProductTemplateScrmService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 商品模板 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsStoreProductTemplateScrmController,供平台总后台跨租户管理
+ *
+ * @author fs
+ * @date 2022-03-15
+ */
+@RestController
+@RequestMapping("/store/store/storeProductTemplate")
+public class FsStoreProductTemplateScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsStoreProductTemplateScrmService fsStoreProductTemplateService;
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductTemplate:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsStoreProductTemplateScrm fsStoreProductTemplate)
+    {
+        startPage();
+        List<FsStoreProductTemplateScrm> list = fsStoreProductTemplateService.selectFsStoreProductTemplateList(fsStoreProductTemplate);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductTemplate:export')")
+    @Log(title = "商品模板", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsStoreProductTemplateScrm fsStoreProductTemplate)
+    {
+        List<FsStoreProductTemplateScrm> list = fsStoreProductTemplateService.selectFsStoreProductTemplateList(fsStoreProductTemplate);
+        ExcelUtil<FsStoreProductTemplateScrm> util = new ExcelUtil<FsStoreProductTemplateScrm>(FsStoreProductTemplateScrm.class);
+        return util.exportExcel(list, "storeProductTemplate");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductTemplate:query')")
+    @GetMapping(value = "/{tempId}")
+    public AjaxResult getInfo(@PathVariable("tempId") Long tempId)
+    {
+        return AjaxResult.success(fsStoreProductTemplateService.selectFsStoreProductTemplateById(tempId));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductTemplate:add')")
+    @Log(title = "商品模板", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsStoreProductTemplateScrm fsStoreProductTemplate)
+    {
+        return toAjax(fsStoreProductTemplateService.insertFsStoreProductTemplate(fsStoreProductTemplate));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductTemplate:edit')")
+    @Log(title = "商品模板", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsStoreProductTemplateScrm fsStoreProductTemplate)
+    {
+        return toAjax(fsStoreProductTemplateService.updateFsStoreProductTemplate(fsStoreProductTemplate));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeProductTemplate:remove')")
+    @Log(title = "商品模板", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{tempIds}")
+    public AjaxResult remove(@PathVariable Long[] tempIds)
+    {
+        return toAjax(fsStoreProductTemplateService.deleteFsStoreProductTemplateByIds(tempIds));
+    }
+}

+ 88 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreRecommendScrmBridgeController.java

@@ -0,0 +1,88 @@
+package com.fs.admin.controller.store;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.FsStoreRecommendScrm;
+import com.fs.hisStore.service.IFsStoreRecommendScrmService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 店铺推荐 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsStoreRecommendScrmController,供平台总后台跨租户管理
+ *
+ * @author fs
+ * @date 2023-06-15
+ */
+@RestController
+@RequestMapping("/store/store/recommend")
+public class FsStoreRecommendScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsStoreRecommendScrmService fsStoreRecommendService;
+
+    @PreAuthorize("@ss.hasPermi('store:recommend:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsStoreRecommendScrm fsStoreRecommendScrm)
+    {
+        startPage();
+        List<FsStoreRecommendScrm> list = fsStoreRecommendService.selectFsStoreRecommendScrmList(fsStoreRecommendScrm);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:recommend:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsStoreRecommendService.selectFsStoreRecommendScrmById(id));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:recommend:add')")
+    @Log(title = "店铺推荐", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsStoreRecommendScrm fsStoreRecommendScrm)
+    {
+        return toAjax(fsStoreRecommendService.insertFsStoreRecommendScrm(fsStoreRecommendScrm));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:recommend:edit')")
+    @Log(title = "店铺推荐", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsStoreRecommendScrm fsStoreRecommendScrm)
+    {
+        return toAjax(fsStoreRecommendService.updateFsStoreRecommendScrm(fsStoreRecommendScrm));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:recommend:delete')")
+    @Log(title = "店铺推荐", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsStoreRecommendService.deleteFsStoreRecommendScrmByIds(ids));
+    }
+
+    @GetMapping("/validList")
+    public TableDataInfo validList(FsStoreRecommendScrm fsStoreRecommendScrm)
+    {
+        startPage();
+        List<FsStoreRecommendScrm> list = fsStoreRecommendService.selectValidRecommendList(fsStoreRecommendScrm);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:recommend:export')")
+    @Log(title = "店铺推荐", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsStoreRecommendScrm fsStoreRecommendScrm)
+    {
+        List<FsStoreRecommendScrm> list = fsStoreRecommendService.selectFsStoreRecommendScrmList(fsStoreRecommendScrm);
+        ExcelUtil<FsStoreRecommendScrm> util = new ExcelUtil<>(FsStoreRecommendScrm.class);
+        return util.exportExcel(list, "店铺推荐数据");
+    }
+}

+ 80 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreShopStaffScrmBridgeController.java

@@ -0,0 +1,80 @@
+package com.fs.admin.controller.store;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.FsStoreShopStaffScrm;
+import com.fs.hisStore.service.IFsStoreShopStaffScrmService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 门店店员 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsStoreShopStaffScrmController,供平台总后台跨租户管理
+ *
+ * @author fs
+ * @date 2022-03-15
+ */
+@RestController
+@RequestMapping("/store/store/storeShopStaff")
+public class FsStoreShopStaffScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsStoreShopStaffScrmService fsStoreShopStaffService;
+
+    @PreAuthorize("@ss.hasPermi('store:storeShopStaff:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsStoreShopStaffScrm fsStoreShopStaff)
+    {
+        startPage();
+        List<FsStoreShopStaffScrm> list = fsStoreShopStaffService.selectFsStoreShopStaffList(fsStoreShopStaff);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeShopStaff:export')")
+    @Log(title = "门店店员", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsStoreShopStaffScrm fsStoreShopStaff)
+    {
+        List<FsStoreShopStaffScrm> list = fsStoreShopStaffService.selectFsStoreShopStaffList(fsStoreShopStaff);
+        ExcelUtil<FsStoreShopStaffScrm> util = new ExcelUtil<FsStoreShopStaffScrm>(FsStoreShopStaffScrm.class);
+        return util.exportExcel(list, "storeShopStaff");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeShopStaff:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsStoreShopStaffService.selectFsStoreShopStaffById(id));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeShopStaff:add')")
+    @Log(title = "门店店员", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsStoreShopStaffScrm fsStoreShopStaff)
+    {
+        return toAjax(fsStoreShopStaffService.insertFsStoreShopStaff(fsStoreShopStaff));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeShopStaff:edit')")
+    @Log(title = "门店店员", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsStoreShopStaffScrm fsStoreShopStaff)
+    {
+        return toAjax(fsStoreShopStaffService.updateFsStoreShopStaff(fsStoreShopStaff));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeShopStaff:remove')")
+    @Log(title = "门店店员", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsStoreShopStaffService.deleteFsStoreShopStaffByIds(ids));
+    }
+}

+ 80 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsStoreVisitScrmBridgeController.java

@@ -0,0 +1,80 @@
+package com.fs.admin.controller.store;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.FsStoreVisitScrm;
+import com.fs.hisStore.service.IFsStoreVisitScrmService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 产品浏览分析 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsStoreVisitScrmController,供平台总后台跨租户管理
+ *
+ * @author fs
+ * @date 2022-03-15
+ */
+@RestController
+@RequestMapping("/store/store/storeVisit")
+public class FsStoreVisitScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsStoreVisitScrmService fsStoreVisitService;
+
+    @PreAuthorize("@ss.hasPermi('store:storeVisit:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsStoreVisitScrm fsStoreVisit)
+    {
+        startPage();
+        List<FsStoreVisitScrm> list = fsStoreVisitService.selectFsStoreVisitList(fsStoreVisit);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeVisit:export')")
+    @Log(title = "产品浏览分析", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsStoreVisitScrm fsStoreVisit)
+    {
+        List<FsStoreVisitScrm> list = fsStoreVisitService.selectFsStoreVisitList(fsStoreVisit);
+        ExcelUtil<FsStoreVisitScrm> util = new ExcelUtil<FsStoreVisitScrm>(FsStoreVisitScrm.class);
+        return util.exportExcel(list, "storeVisit");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeVisit:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsStoreVisitService.selectFsStoreVisitById(id));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeVisit:add')")
+    @Log(title = "产品浏览分析", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsStoreVisitScrm fsStoreVisit)
+    {
+        return toAjax(fsStoreVisitService.insertFsStoreVisit(fsStoreVisit));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeVisit:edit')")
+    @Log(title = "产品浏览分析", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsStoreVisitScrm fsStoreVisit)
+    {
+        return toAjax(fsStoreVisitService.updateFsStoreVisit(fsStoreVisit));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeVisit:remove')")
+    @Log(title = "产品浏览分析", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsStoreVisitService.deleteFsStoreVisitByIds(ids));
+    }
+}

+ 82 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/FsUserPromoterApplyScrmBridgeController.java

@@ -0,0 +1,82 @@
+package com.fs.admin.controller.store;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.FsUserPromoterApplyScrm;
+import com.fs.hisStore.param.FsUsePromoterApplyParam;
+import com.fs.hisStore.service.IFsUserPromoterApplyScrmService;
+import com.fs.hisStore.vo.FsUserPromoterApplyVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 推广员申请 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.FsUserPromoterApplyController,供平台总后台跨租户管理
+ *
+ * @author fs
+ * @date 2023-02-28
+ */
+@RestController
+@RequestMapping("/store/store/userPromoterApply")
+public class FsUserPromoterApplyScrmBridgeController extends BaseController
+{
+    @Autowired
+    private IFsUserPromoterApplyScrmService fsUserPromoterApplyService;
+
+    @PreAuthorize("@ss.hasPermi('store:userPromoterApply:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsUsePromoterApplyParam fsUserPromoterApply)
+    {
+        startPage();
+        List<FsUserPromoterApplyVO> list = fsUserPromoterApplyService.selectFsUserPromoterApplyListVO(fsUserPromoterApply);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:userPromoterApply:export')")
+    @Log(title = "推广员申请", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsUserPromoterApplyScrm fsUserPromoterApply)
+    {
+        List<FsUserPromoterApplyScrm> list = fsUserPromoterApplyService.selectFsUserPromoterApplyList(fsUserPromoterApply);
+        ExcelUtil<FsUserPromoterApplyScrm> util = new ExcelUtil<FsUserPromoterApplyScrm>(FsUserPromoterApplyScrm.class);
+        return util.exportExcel(list, "userPromoterApply");
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:userPromoterApply:query')")
+    @GetMapping(value = "/{applyId}")
+    public AjaxResult getInfo(@PathVariable("applyId") Long applyId)
+    {
+        return AjaxResult.success(fsUserPromoterApplyService.selectFsUserPromoterApplyById(applyId));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:userPromoterApply:add')")
+    @Log(title = "推广员申请", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsUserPromoterApplyScrm fsUserPromoterApply)
+    {
+        return toAjax(fsUserPromoterApplyService.insertFsUserPromoterApply(fsUserPromoterApply));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:userPromoterApply:edit')")
+    @Log(title = "推广员申请", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsUserPromoterApplyScrm fsUserPromoterApply)
+    {
+        return toAjax(fsUserPromoterApplyService.updateFsUserPromoterApply(fsUserPromoterApply));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:userPromoterApply:remove')")
+    @Log(title = "推广员申请", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{applyIds}")
+    public AjaxResult remove(@PathVariable Long[] applyIds)
+    {
+        return toAjax(fsUserPromoterApplyService.deleteFsUserPromoterApplyByIds(applyIds));
+    }
+}

+ 61 - 0
fs-admin/src/main/java/com/fs/admin/controller/store/SysOperlogScrmBridgeController.java

@@ -0,0 +1,61 @@
+package com.fs.admin.controller.store;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.SysOperLogScrm;
+import com.fs.hisStore.param.StoreOperMainQueryParam;
+import com.fs.hisStore.service.ISysOperLogScrmService;
+import com.fs.hisStore.vo.StoreOperMainVO;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 操作日志 Bridge Controller (fs-admin端)
+ * 桥接 hisStore.SysOperlogScrmController,供平台总后台跨租户管理
+ *
+ * @author fs
+ */
+@RestController
+@RequestMapping("/store/operlogScrm")
+public class SysOperlogScrmBridgeController extends BaseController
+{
+    private final ISysOperLogScrmService operLogService;
+
+    public SysOperlogScrmBridgeController(ISysOperLogScrmService operLogService) {
+        this.operLogService = operLogService;
+    }
+
+    @PreAuthorize("@ss.hasPermi('his:storeLog:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysOperLogScrm operLog)
+    {
+        startPage();
+        List<SysOperLogScrm> list = operLogService.selectOperLogList(operLog);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('his:storeLog:list')")
+    @GetMapping("/getMains")
+    public R getMains(StoreOperMainQueryParam operLog)
+    {
+        List<StoreOperMainVO> list = operLogService.getMains(operLog);
+        return R.ok().put("data", list);
+    }
+
+    @Log(title = "操作日志", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('his:storeLog:export')")
+    @GetMapping("/export")
+    public AjaxResult export(SysOperLogScrm operLog)
+    {
+        List<SysOperLogScrm> list = operLogService.selectOperLogList(operLog);
+        ExcelUtil<SysOperLogScrm> util = new ExcelUtil<>(SysOperLogScrm.class);
+        return util.exportExcel(list, "操作日志");
+    }
+}

+ 19 - 0
fs-admin/src/main/java/com/fs/config/FullQualifiedBeanNameGenerator.java

@@ -0,0 +1,19 @@
+package com.fs.config;
+
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.context.annotation.AnnotationBeanNameGenerator;
+
+/**
+ * 使用全限定类名作为bean名称,避免不同包下同名类的bean冲突
+ */
+public class FullQualifiedBeanNameGenerator extends AnnotationBeanNameGenerator {
+
+    @Override
+    protected String buildDefaultBeanName(BeanDefinition definition) {
+        String beanClassName = definition.getBeanClassName();
+        if (beanClassName != null) {
+            return beanClassName;
+        }
+        return super.buildDefaultBeanName(definition);
+    }
+}

+ 30 - 0
fs-admin/src/main/java/com/fs/config/OverridingBeanNameGenerator.java

@@ -0,0 +1,30 @@
+package com.fs.config;
+
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.context.annotation.AnnotationBeanNameGenerator;
+
+/**
+ * 自定义BeanName生成器:对冲突的bean使用全限定名,其他保持默认行为
+ * 解决fs-framework和fs-service中同名类的冲突问题
+ */
+public class OverridingBeanNameGenerator extends AnnotationBeanNameGenerator {
+
+    @Override
+    public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
+        // 先按默认逻辑生成名称
+        String beanName = super.generateBeanName(definition, registry);
+        
+        // 如果已存在同名bean但来自不同类,使用全限定名避免冲突
+        if (registry.containsBeanDefinition(beanName)) {
+            BeanDefinition existingDef = registry.getBeanDefinition(beanName);
+            String existingClass = existingDef.getBeanClassName();
+            String newClass = definition.getBeanClassName();
+            if (existingClass != null && newClass != null && !existingClass.equals(newClass)) {
+                // 冲突:使用全限定类名作为bean名称
+                return newClass;
+            }
+        }
+        return beanName;
+    }
+}

+ 3 - 1
fs-admin/src/main/resources/application.yml

@@ -3,6 +3,8 @@ server:
   port: 8004
   port: 8004
 # Spring配置
 # Spring配置
 spring:
 spring:
+  main:
+    allow-bean-definition-overriding: true
   profiles:
   profiles:
 #    active: dev-test
 #    active: dev-test
 #    active: druid-hdt
 #    active: druid-hdt
@@ -10,7 +12,7 @@ spring:
 #    active: druid-sxjz-test
 #    active: druid-sxjz-test
 #    active: druid-sft
 #    active: druid-sft
 #    active: druid-fby
 #    active: druid-fby
-    active: dev
+    active: dev,admin
     include: common,config-dev
     include: common,config-dev
 
 
 # SaaS 模式下定时任务:仅注册租户任务分发器,由分发器每分钟按租户切库执行各租户 sys_job(需主库有 tenant_info)
 # SaaS 模式下定时任务:仅注册租户任务分发器,由分发器每分钟按租户切库执行各租户 sys_job(需主库有 tenant_info)

+ 6 - 6
fs-admin/src/main/resources/pay/wxpay.properties

@@ -1,8 +1,8 @@
-wxpay.appId=wxbe53e91d9ad11ca6
-wxpay.appSecret=58d70c9be43047ef3275339a3f4b5ee0
-wxpay.mchId=1581878681
-wxpay.partnerKey=8cab128997a3547c1363b0898b877f38
-wxpay.certPath=pay/cert/apiclient_cert.p12
-wxpay.domain= https://api.hospital.ifeiyu100.com
+wxpay.appId=${WXPAY_APP_ID:wxbe53e91d9ad11ca6}
+wxpay.appSecret=${WXPAY_APP_SECRET:}
+wxpay.mchId=${WXPAY_MCH_ID:1581878681}
+wxpay.partnerKey=${WXPAY_PARTNER_KEY:}
+wxpay.certPath=${WXPAY_CERT_PATH:pay/cert/apiclient_cert.p12}
+wxpay.domain=${WXPAY_DOMAIN:https://api.hospital.ifeiyu100.com}
 
 
 
 

+ 2 - 7
fs-ai-call-task/src/main/java/com/fs/app/task/TenantTaskRunner.java

@@ -190,14 +190,9 @@ public class TenantTaskRunner {
             log.info("[SaaS Task] 定时任务切换数据源和Redis dataSource={}, tenantId={}, tenantCode={}, task={}",
             log.info("[SaaS Task] 定时任务切换数据源和Redis dataSource={}, tenantId={}, tenantCode={}, task={}",
                     dataSourceKey, tenant.getId(), tenant.getTenantCode(), taskName != null ? taskName : "");
                     dataSourceKey, tenant.getId(), tenant.getTenantCode(), taskName != null ? taskName : "");
 
 
-            // 加载租户项目配置
+            // 加载租户项目配置(安全解析,防止非法JSON导致级联崩溃)
             SysConfig cfg = sysConfigMapper.selectConfigByConfigKey("projectConfig");
             SysConfig cfg = sysConfigMapper.selectConfigByConfigKey("projectConfig");
-            if (cfg != null && StringUtils.isNotBlank(cfg.getConfigValue())) {
-                TenantConfigContext.set(JSONObject.parseObject(cfg.getConfigValue()));
-            } else {
-                TenantConfigContext.set(null);
-            }
-            ProjectConfig.loadTenantConfigsFromContext();
+            ProjectConfig.safeLoadTenantConfigFromValue(cfg != null ? cfg.getConfigValue() : null);
 
 
             // 执行租户任务
             // 执行租户任务
             action.accept(tenant);
             action.accept(tenant);

+ 2 - 7
fs-cid-workflow/src/main/java/com/fs/app/task/TenantTaskRunner.java

@@ -190,14 +190,9 @@ public class TenantTaskRunner {
             log.info("[SaaS Task] 定时任务切换数据源和Redis dataSource={}, tenantId={}, tenantCode={}, task={}",
             log.info("[SaaS Task] 定时任务切换数据源和Redis dataSource={}, tenantId={}, tenantCode={}, task={}",
                     dataSourceKey, tenant.getId(), tenant.getTenantCode(), taskName != null ? taskName : "");
                     dataSourceKey, tenant.getId(), tenant.getTenantCode(), taskName != null ? taskName : "");
 
 
-            // 加载租户项目配置
+            // 加载租户项目配置(安全解析,防止非法JSON导致级联崩溃)
             SysConfig cfg = sysConfigMapper.selectConfigByConfigKey("projectConfig");
             SysConfig cfg = sysConfigMapper.selectConfigByConfigKey("projectConfig");
-            if (cfg != null && StringUtils.isNotBlank(cfg.getConfigValue())) {
-                TenantConfigContext.set(JSONObject.parseObject(cfg.getConfigValue()));
-            } else {
-                TenantConfigContext.set(null);
-            }
-            ProjectConfig.loadTenantConfigsFromContext();
+            ProjectConfig.safeLoadTenantConfigFromValue(cfg != null ? cfg.getConfigValue() : null);
 
 
             // 执行租户任务
             // 执行租户任务
             action.accept(tenant);
             action.accept(tenant);

+ 6 - 0
fs-company-app/src/main/java/com/fs/app/controller/AppBaseController.java

@@ -50,6 +50,9 @@ public class AppBaseController {
 		Long companyId =(Long)redisCache.getCacheObject("companyId:"+userId);
 		Long companyId =(Long)redisCache.getCacheObject("companyId:"+userId);
 		if (companyId==null){
 		if (companyId==null){
 			CompanyUser companyUser = companyUserService.selectCompanyUserById(Long.parseLong(userId));
 			CompanyUser companyUser = companyUserService.selectCompanyUserById(Long.parseLong(userId));
+			if (companyUser == null) {
+				throw new FSException("当前用户无权限访问该功能");
+			}
 			companyId = companyUser.getCompanyId();
 			companyId = companyUser.getCompanyId();
 			redisCache.setCacheObject("companyId:" + companyUser.getUserId(), companyUser.getCompanyId(), 604800, TimeUnit.SECONDS);
 			redisCache.setCacheObject("companyId:" + companyUser.getUserId(), companyUser.getCompanyId(), 604800, TimeUnit.SECONDS);
 		}
 		}
@@ -83,6 +86,9 @@ public class AppBaseController {
 	public Long getUserId(Long companyUserId)
 	public Long getUserId(Long companyUserId)
 	{
 	{
 		CompanyUser companyUser=companyUserService.selectCompanyUserById(companyUserId);
 		CompanyUser companyUser=companyUserService.selectCompanyUserById(companyUserId);
+		if (companyUser == null) {
+			throw new FSException("当前用户无权限访问该功能");
+		}
 		FsUser user=userService.selectFsUserByPhone(companyUser.getPhonenumber());
 		FsUser user=userService.selectFsUserByPhone(companyUser.getPhonenumber());
 		if(user==null){
 		if(user==null){
 			throw new FSException("未授权,请用员工手机号登录商城");
 			throw new FSException("未授权,请用员工手机号登录商城");

+ 9 - 0
fs-company-app/src/main/java/com/fs/app/controller/CompanyUserController.java

@@ -101,6 +101,9 @@ public class CompanyUserController extends AppBaseController {
 
 
         Long userId = Long.parseLong(getUserId());
         Long userId = Long.parseLong(getUserId());
         CompanyUser companyUser = companyUserService.selectCompanyUserById(userId);
         CompanyUser companyUser = companyUserService.selectCompanyUserById(userId);
+        if (companyUser == null) {
+            return R.error("当前用户无权限访问该功能");
+        }
         List<CompanyRole> companyRoles = companyRoleMapper.selectRolePermissionByUserId(userId);
         List<CompanyRole> companyRoles = companyRoleMapper.selectRolePermissionByUserId(userId);
         List<CompanyUser> companyUsers;
         List<CompanyUser> companyUsers;
 
 
@@ -297,6 +300,9 @@ public class CompanyUserController extends AppBaseController {
             throw new ServiceException("存在待审核申请");
             throw new ServiceException("存在待审核申请");
         }
         }
         CompanyUser companyUser = companyUserService.selectCompanyUserById(Long.parseLong(getUserId()));
         CompanyUser companyUser = companyUserService.selectCompanyUserById(Long.parseLong(getUserId()));
+        if (companyUser == null) {
+            return R.error("当前用户无权限访问该功能");
+        }
         List<UserProjectDTO> list = param.getIds();
         List<UserProjectDTO> list = param.getIds();
         if(CollectionUtils.isEmpty(list)){
         if(CollectionUtils.isEmpty(list)){
             List<UserProjectDTO> userProjectDTOS = addUserId(param.getProject(),param.getTagList(),param.getFrom());
             List<UserProjectDTO> userProjectDTOS = addUserId(param.getProject(),param.getTagList(),param.getFrom());
@@ -394,6 +400,9 @@ public class CompanyUserController extends AppBaseController {
         log.debug("changeUserDeptAndPost param: {}", JSON.toJSONString(param));
         log.debug("changeUserDeptAndPost param: {}", JSON.toJSONString(param));
 
 
         CompanyUser companyUser = companyUserService.selectCompanyUserByUserId(Long.parseLong(getUserId()));
         CompanyUser companyUser = companyUserService.selectCompanyUserByUserId(Long.parseLong(getUserId()));
+        if (companyUser == null) {
+            return R.error("当前用户无权限访问该功能");
+        }
         if (!companyUser.isAdmin()) {
         if (!companyUser.isAdmin()) {
             return R.error("没有权限");
             return R.error("没有权限");
         }
         }

+ 12 - 0
fs-company-app/src/main/java/com/fs/app/controller/CrmController.java

@@ -127,6 +127,9 @@ public class CrmController extends  AppBaseController {
 	public R add(@RequestBody CrmCustomer crmCustomer)
 	public R add(@RequestBody CrmCustomer crmCustomer)
 	{
 	{
 		CompanyUser companyUser=companyUserService.selectCompanyUserById(Long.parseLong(getUserId()));
 		CompanyUser companyUser=companyUserService.selectCompanyUserById(Long.parseLong(getUserId()));
+		if (companyUser == null) {
+			return R.error("当前用户无权限访问该功能");
+		}
 		crmCustomer.setDeptId(companyUser.getDeptId());
 		crmCustomer.setDeptId(companyUser.getDeptId());
 		crmCustomer.setCustomerCode(OrderUtils.getOrderNo());
 		crmCustomer.setCustomerCode(OrderUtils.getOrderNo());
 		crmCustomer.setIsLine(0);
 		crmCustomer.setIsLine(0);
@@ -157,6 +160,9 @@ public class CrmController extends  AppBaseController {
 	public R receive(@RequestBody CrmCustomeReceiveParam param)
 	public R receive(@RequestBody CrmCustomeReceiveParam param)
 	{
 	{
 		CompanyUser companyUser=companyUserService.selectCompanyUserById(Long.parseLong(getUserId()));
 		CompanyUser companyUser=companyUserService.selectCompanyUserById(Long.parseLong(getUserId()));
+		if (companyUser == null) {
+			return R.error("当前用户无权限访问该功能");
+		}
 		String operName = companyUser.getNickName();
 		String operName = companyUser.getNickName();
 		param.setCompanyId(companyUser.getCompanyId());
 		param.setCompanyId(companyUser.getCompanyId());
 		param.setCompanyUserId(companyUser.getUserId());
 		param.setCompanyUserId(companyUser.getUserId());
@@ -170,6 +176,9 @@ public class CrmController extends  AppBaseController {
 	public R recover(@RequestBody CrmCustomeRecoverParam param)
 	public R recover(@RequestBody CrmCustomeRecoverParam param)
 	{
 	{
 		CompanyUser companyUser=companyUserService.selectCompanyUserById(Long.parseLong(getUserId()));
 		CompanyUser companyUser=companyUserService.selectCompanyUserById(Long.parseLong(getUserId()));
+		if (companyUser == null) {
+			return R.error("当前用户无权限访问该功能");
+		}
 		String operName = companyUser.getNickName();
 		String operName = companyUser.getNickName();
 		param.setCompanyId(companyUser.getCompanyId());
 		param.setCompanyId(companyUser.getCompanyId());
 		param.setCompanyUserId(companyUser.getUserId());
 		param.setCompanyUserId(companyUser.getUserId());
@@ -183,6 +192,9 @@ public class CrmController extends  AppBaseController {
 	public R assignUser(@RequestBody CrmCustomeAssignUserParam param)
 	public R assignUser(@RequestBody CrmCustomeAssignUserParam param)
 	{
 	{
 		CompanyUser companyUser=companyUserService.selectCompanyUserById(Long.parseLong(getUserId()));
 		CompanyUser companyUser=companyUserService.selectCompanyUserById(Long.parseLong(getUserId()));
+		if (companyUser == null) {
+			return R.error("当前用户无权限访问该功能");
+		}
 		String operName = companyUser.getNickName();
 		String operName = companyUser.getNickName();
 		return crmCustomerService.assignUser(param,operName);
 		return crmCustomerService.assignUser(param,operName);
 
 

+ 15 - 0
fs-company-app/src/main/java/com/fs/app/controller/CrmCustomerController.java

@@ -49,6 +49,9 @@ public class CrmCustomerController extends AppBaseController
     public R getLineCustomerList( CrmLineCustomerListQueryParam param)
     public R getLineCustomerList( CrmLineCustomerListQueryParam param)
     {
     {
         CompanyUser user = companyUserService.selectCompanyUserById(Long.parseLong(getUserId()));
         CompanyUser user = companyUserService.selectCompanyUserById(Long.parseLong(getUserId()));
+        if (user == null) {
+            return R.error("当前用户无权限访问该功能");
+        }
         PageHelper.startPage(param.getPageNum(), param.getPageSize());
         PageHelper.startPage(param.getPageNum(), param.getPageSize());
         param.setCompanyId(user.getCompanyId());
         param.setCompanyId(user.getCompanyId());
         List<CrmLineCustomerListQueryVO> list = crmCustomerService.selectCrmLineCustomerListQuery(param);
         List<CrmLineCustomerListQueryVO> list = crmCustomerService.selectCrmLineCustomerListQuery(param);
@@ -71,6 +74,9 @@ public class CrmCustomerController extends AppBaseController
         PageHelper.startPage(param.getPageNum(), param.getPageSize());
         PageHelper.startPage(param.getPageNum(), param.getPageSize());
 
 
         CompanyUser user = companyUserService.selectCompanyUserById(Long.parseLong(getUserId()));
         CompanyUser user = companyUserService.selectCompanyUserById(Long.parseLong(getUserId()));
+        if (user == null) {
+            return R.error("当前用户无权限访问该功能");
+        }
 
 
         param.setCompanyUserId(user.getUserId());
         param.setCompanyUserId(user.getUserId());
         param.setCompanyId(user.getCompanyId());
         param.setCompanyId(user.getCompanyId());
@@ -101,6 +107,9 @@ public class CrmCustomerController extends AppBaseController
             @RequestParam(value = "customerId", required = false) Long customerId){
             @RequestParam(value = "customerId", required = false) Long customerId){
 
 
         CompanyUser user = companyUserService.selectCompanyUserById(Long.parseLong(getUserId()));
         CompanyUser user = companyUserService.selectCompanyUserById(Long.parseLong(getUserId()));
+        if (user == null) {
+            return R.error("当前用户无权限访问该功能");
+        }
 
 
         CrmCustomer customer=crmCustomerService.selectCrmCustomerById(customerId);
         CrmCustomer customer=crmCustomerService.selectCrmCustomerById(customerId);
         if (!user.getUserId().equals(customer.getReceiveUserId())){
         if (!user.getUserId().equals(customer.getReceiveUserId())){
@@ -127,6 +136,9 @@ public class CrmCustomerController extends AppBaseController
         PageHelper.startPage(param.getPageNum(), param.getPageSize());
         PageHelper.startPage(param.getPageNum(), param.getPageSize());
 
 
         CompanyUser user = companyUserService.selectCompanyUserById(Long.parseLong(getUserId()));
         CompanyUser user = companyUserService.selectCompanyUserById(Long.parseLong(getUserId()));
+        if (user == null) {
+            return R.error("当前用户无权限访问该功能");
+        }
         param.setCompanyId(user.getCompanyId());
         param.setCompanyId(user.getCompanyId());
 
 
         List<CrmCustomerListQueryFriendVO> list = crmCustomerService.getFriendAssistantListVO(param);
         List<CrmCustomerListQueryFriendVO> list = crmCustomerService.getFriendAssistantListVO(param);
@@ -153,6 +165,9 @@ public class CrmCustomerController extends AppBaseController
     public R editCrmCustomer(@RequestBody CrmCustomer param) {
     public R editCrmCustomer(@RequestBody CrmCustomer param) {
         CrmCustomer customer=crmCustomerService.selectCrmCustomerById(param.getCustomerId());
         CrmCustomer customer=crmCustomerService.selectCrmCustomerById(param.getCustomerId());
         CompanyUser user = companyUserService.selectCompanyUserById(Long.parseLong(getUserId()));
         CompanyUser user = companyUserService.selectCompanyUserById(Long.parseLong(getUserId()));
+        if (user == null) {
+            return R.error("当前用户无权限访问该功能");
+        }
         if (!customer.getReceiveUserId().equals(user.getUserId())) {
         if (!customer.getReceiveUserId().equals(user.getUserId())) {
             return R.error("只能修改自己的客户");
             return R.error("只能修改自己的客户");
         }
         }

+ 3 - 0
fs-company-app/src/main/java/com/fs/app/controller/StorePaymentController.java

@@ -62,6 +62,9 @@ public class StorePaymentController extends AppBaseController
         Long userId=Long.parseLong(getUserId());
         Long userId=Long.parseLong(getUserId());
         try {
         try {
             CompanyUser companyUser=companyUserService.selectCompanyUserById(userId);
             CompanyUser companyUser=companyUserService.selectCompanyUserById(userId);
+            if (companyUser == null) {
+                return R.error("当前用户无权限访问该功能");
+            }
             File newFile = new File("qr.jpg");
             File newFile = new File("qr.jpg");
             File newFileT = new File("simsunb.ttf");
             File newFileT = new File("simsunb.ttf");
             try {
             try {

+ 1 - 6
fs-company-app/src/main/java/com/fs/app/controller/UserController.java

@@ -285,12 +285,7 @@ public class UserController extends AppBaseController {
             );
             );
 
 
             SysConfig cfg = sysConfigMapper.selectConfigByConfigKey("projectConfig");
             SysConfig cfg = sysConfigMapper.selectConfigByConfigKey("projectConfig");
-            if (cfg != null && com.fs.common.utils.StringUtils.isNotBlank(cfg.getConfigValue())) {
-                TenantConfigContext.set(JSONObject.parseObject(cfg.getConfigValue()));
-            } else {
-                TenantConfigContext.set(null);
-            }
-            ProjectConfig.loadTenantConfigsFromContext();
+            ProjectConfig.safeLoadTenantConfigFromValue(cfg != null ? cfg.getConfigValue() : null);
         }
         }
 
 
         return tenantInfo;
         return tenantInfo;

+ 11 - 0
fs-company-app/src/main/java/com/fs/app/websocket/service/WebSocketServer.java

@@ -29,6 +29,8 @@ import com.fs.wx.kf.dto.WeixinKfImageMsgDTO;
 import com.fs.wx.kf.dto.WeixinKfMsgSendDTO;
 import com.fs.wx.kf.dto.WeixinKfMsgSendDTO;
 import com.fs.wx.kf.dto.WeixinKfTextMsgDTO;
 import com.fs.wx.kf.dto.WeixinKfTextMsgDTO;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 import org.springframework.stereotype.Component;
 
 
@@ -49,6 +51,7 @@ import static com.fs.common.constant.FsConstants.REDIS_CHAT_SESSION;
 @ServerEndpoint("/app/webSocket/{uid}")
 @ServerEndpoint("/app/webSocket/{uid}")
 @Component
 @Component
 public class WebSocketServer {
 public class WebSocketServer {
+    private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class);
     IBaiduAIService baiduAIService=SpringUtils.getBean(IBaiduAIService.class);
     IBaiduAIService baiduAIService=SpringUtils.getBean(IBaiduAIService.class);
     IChatRoleService chatRoleService=SpringUtils.getBean(IChatRoleService.class);
     IChatRoleService chatRoleService=SpringUtils.getBean(IChatRoleService.class);
     IChatMsgService chatMsgService=SpringUtils.getBean(IChatMsgService.class);
     IChatMsgService chatMsgService=SpringUtils.getBean(IChatMsgService.class);
@@ -133,6 +136,10 @@ public class WebSocketServer {
                             }
                             }
                             else if(msg.getUserType().equals(3)){
                             else if(msg.getUserType().equals(3)){
                                 CompanyUser user=companyUserService.selectCompanyUserById(Long.parseLong(msg.getUserId()));
                                 CompanyUser user=companyUserService.selectCompanyUserById(Long.parseLong(msg.getUserId()));
+                                if (user == null) {
+                                    log.warn("WebSocket处理消息:companyUser为空,userId={}", msg.getUserId());
+                                    break;
+                                }
                                 chatSession.setNickName(user.getNickName());
                                 chatSession.setNickName(user.getNickName());
                                 chatSession.setAvatar(user.getAvatar());
                                 chatSession.setAvatar(user.getAvatar());
                                 chatSession.setCompanyId(user.getCompanyId());
                                 chatSession.setCompanyId(user.getCompanyId());
@@ -154,6 +161,10 @@ public class WebSocketServer {
                         }
                         }
                         else if(msg.getUserType().equals(3)){
                         else if(msg.getUserType().equals(3)){
                             CompanyUser user=companyUserService.selectCompanyUserById(Long.parseLong(msg.getUserId()));
                             CompanyUser user=companyUserService.selectCompanyUserById(Long.parseLong(msg.getUserId()));
+                            if (user == null) {
+                                log.warn("WebSocket处理消息:companyUser为空,userId={}", msg.getUserId());
+                                break;
+                            }
                             chatMsg.setNickName(user.getNickName());
                             chatMsg.setNickName(user.getNickName());
                             chatMsg.setAvatar(user.getAvatar());
                             chatMsg.setAvatar(user.getAvatar());
                             chatMsg.setCompanyId(user.getCompanyId());
                             chatMsg.setCompanyId(user.getCompanyId());

+ 3 - 13
fs-company-app/src/main/java/com/fs/core/filter/CompanySaasContextFilter.java

@@ -60,12 +60,7 @@ public class CompanySaasContextFilter extends OncePerRequestFilter {
         try {
         try {
             if (StringUtils.isBlank(tenantCode)) {
             if (StringUtils.isBlank(tenantCode)) {
                 SysConfig cfg = sysConfigMapper.selectConfigByConfigKey("projectConfig");
                 SysConfig cfg = sysConfigMapper.selectConfigByConfigKey("projectConfig");
-                if (cfg != null && com.fs.common.utils.StringUtils.isNotBlank(cfg.getConfigValue())) {
-                    TenantConfigContext.set(JSONObject.parseObject(cfg.getConfigValue()));
-                } else {
-                    TenantConfigContext.set(null);
-                }
-                ProjectConfig.loadTenantConfigsFromContext();
+                ProjectConfig.safeLoadTenantConfigFromValue(cfg != null ? cfg.getConfigValue() : null);
 
 
                 // 未携带租户编码:保持单库行为,直接放行
                 // 未携带租户编码:保持单库行为,直接放行
                 chain.doFilter(request, response);
                 chain.doFilter(request, response);
@@ -100,14 +95,9 @@ public class CompanySaasContextFilter extends OncePerRequestFilter {
             // Step 2:切换到租户库(如无则动态创建数据源)
             // Step 2:切换到租户库(如无则动态创建数据源)
             tenantDataSourceManager.switchTenant(tenant);
             tenantDataSourceManager.switchTenant(tenant);
 
 
-            // Step 3:从租户库读取项目配置(projectConfig),填充 TenantConfigContext 和 ProjectConfig
+            // Step 3:从租户库读取项目配置(projectConfig),安全解析,防止非法JSON导致级联崩溃
             SysConfig cfg = sysConfigMapper.selectConfigByConfigKey("projectConfig");
             SysConfig cfg = sysConfigMapper.selectConfigByConfigKey("projectConfig");
-            if (cfg != null && StringUtils.isNotBlank(cfg.getConfigValue())) {
-                TenantConfigContext.set(JSONObject.parseObject(cfg.getConfigValue()));
-            } else {
-                TenantConfigContext.set(null);
-            }
-            ProjectConfig.loadTenantConfigsFromContext();
+            ProjectConfig.safeLoadTenantConfigFromValue(cfg != null ? cfg.getConfigValue() : null);
 
 
             // 设置租户到 SecurityContext,供 TenantKeyRedisSerializer 自动为 Redis Key 加 tenantid 前缀
             // 设置租户到 SecurityContext,供 TenantKeyRedisSerializer 自动为 Redis Key 加 tenantid 前缀
             SecurityContextHolder.getContext().setAuthentication(
             SecurityContextHolder.getContext().setAuthentication(

+ 33 - 1
fs-company/src/main/java/com/fs/FsCompanyApplication.java

@@ -1,8 +1,11 @@
 package com.fs;
 package com.fs;
 
 
+import com.fs.framework.config.OverridingBeanNameGenerator;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.FilterType;
 import org.springframework.scheduling.annotation.EnableAsync;
 import org.springframework.scheduling.annotation.EnableAsync;
 import org.springframework.transaction.annotation.EnableTransactionManagement;
 import org.springframework.transaction.annotation.EnableTransactionManagement;
 
 
@@ -10,13 +13,42 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
  * 启动程序
  * 启动程序
  */
  */
 @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
 @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
+@ComponentScan(
+    basePackages = "com.fs",
+    nameGenerator = OverridingBeanNameGenerator.class,
+    excludeFilters = {
+        @ComponentScan.Filter(type = FilterType.REGEX, pattern = {
+            "com\\.fs\\.api\\.controller\\..*",
+            "com\\.fs\\.web\\.controller\\..*",
+            "com\\.fs\\.his\\.controller\\..*",
+            "com\\.fs\\.admin\\.controller\\..*",
+            "com\\.fs\\.chat\\.controller\\..*",
+            "com\\.fs\\.crm\\.controller\\..*",
+            "com\\.fs\\.course\\.controller\\..*",
+            "com\\.fs\\.qw\\.controller\\..*",
+            "com\\.fs\\.live\\.controller\\..*",
+            "com\\.fs\\.newAdv\\.controller\\..*",
+            "com\\.fs\\.hisStore\\.controller\\..*",
+            "com\\.fs\\.hisStore\\.[^.]+",
+            "com\\.fs\\.user\\.controller\\..*",
+            "com\\.fs\\.proxy\\.controller\\..*",
+            "com\\.fs\\.fastGpt\\.[^.]+",
+            "com\\.fs\\.fastgptApi\\.[^.]+",
+            "com\\.fs\\.transfer\\.[^.]+",
+            "com\\.fs\\.task\\.[^.]+",
+            "com\\.fs\\.ad\\.controller\\..*",
+            "com\\.fs\\.billing\\.controller\\..*",
+            "com\\.fs\\.third\\.controller\\..*",
+            "com\\.fs\\.quartz\\.saas\\.QuartzSaaSConfig"
+        })
+    }
+)
 @EnableTransactionManagement
 @EnableTransactionManagement
 @EnableAsync
 @EnableAsync
 public class FsCompanyApplication
 public class FsCompanyApplication
 {
 {
     public static void main(String[] args)
     public static void main(String[] args)
     {
     {
-
         SpringApplication.run(FsCompanyApplication.class, args);
         SpringApplication.run(FsCompanyApplication.class, args);
         System.out.println("CompanyAPI启动成功");
         System.out.println("CompanyAPI启动成功");
     }
     }

+ 22 - 0
fs-company/src/main/java/com/fs/framework/config/OverridingBeanNameGenerator.java

@@ -0,0 +1,22 @@
+package com.fs.framework.config;
+
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.context.annotation.AnnotationBeanNameGenerator;
+
+public class OverridingBeanNameGenerator extends AnnotationBeanNameGenerator {
+
+    @Override
+    public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
+        String beanName = super.generateBeanName(definition, registry);
+        if (registry.containsBeanDefinition(beanName)) {
+            BeanDefinition existingDef = registry.getBeanDefinition(beanName);
+            String existingClass = existingDef.getBeanClassName();
+            String newClass = definition.getBeanClassName();
+            if (existingClass != null && newClass != null && !existingClass.equals(newClass)) {
+                return newClass;
+            }
+        }
+        return beanName;
+    }
+}

+ 5 - 0
fs-company/src/main/resources/application-dev.yml

@@ -107,3 +107,8 @@ ai:
     api-key: ""
     api-key: ""
     endpoint: https://api.hunyuan.cloud.tencent.com/v1/chat/completions
     endpoint: https://api.hunyuan.cloud.tencent.com/v1/chat/completions
     model: hunyuan-lite
     model: hunyuan-lite
+# token配置 - 必须与fs-admin一致才能共享JWT token
+token:
+    header: Authorization
+    secret: YlrzSaas2026SecKey!@#QwErTyUiOpAsDfGhJkLzXcVbNm
+    expireTime: 720

+ 6 - 1
fs-company/src/main/resources/application.yml

@@ -1,9 +1,14 @@
 server:
 server:
   port: 8006
   port: 8006
+# token配置 - 必须与fs-admin一致才能共享JWT token
+token:
+  header: Authorization
+  secret: YlrzSaas2026SecKey!@#QwErTyUiOpAsDfGhJkLzXcVbNm
+  expireTime: 720
 # Spring配置
 # Spring配置
 spring:
 spring:
   profiles:
   profiles:
-    active: dev
+    active: dev,company
     include: common,config-dev
     include: common,config-dev
 #    active: druid-jnsyj-test
 #    active: druid-jnsyj-test
 #    active: druid-jnmy-test
 #    active: druid-jnmy-test

+ 75 - 8
fs-company/src/main/resources/static/chat-aggregate.html

@@ -240,18 +240,85 @@ const {createApp, ref, computed, watch, nextTick, onMounted} = Vue;
             const messageList = ref(null);
             const messageList = ref(null);
             const loading = ref(false);
             const loading = ref(false);
             
             
-            // API请求工具函数
+            // ====== API配置 ======
+            // 从URL参数获取配置(iframe嵌入时由父窗口传递)
+            const getUrlParam = (name) => {
+                const params = new URLSearchParams(window.location.search);
+                return params.get(name) || '';
+            };
+            
+            // 获取API基路径:URL参数 > 父窗口webpack环境变量 > 默认值
+            const getBaseApi = () => {
+                const fromUrl = getUrlParam('baseApi');
+                if (fromUrl) return fromUrl;
+                try {
+                    if (window.parent && window.parent.process && window.parent.process.env) {
+                        return window.parent.process.env.VUE_APP_BASE_API || '/dev-api';
+                    }
+                } catch(e) {}
+                return '/dev-api';
+            };
+            const BASE_API = getBaseApi();
+            
+            // 获取前端类型:URL参数 > 默认值
+            const getFrontendType = () => {
+                return getUrlParam('frontendType') || 'company';
+            };
+            const FRONTEND_TYPE = getFrontendType();
+            
+            // 从Cookie获取Token
+            const getToken = () => {
+                const match = document.cookie.match(/(?:^|;\s*)Web-Token=([^;]*)/);
+                return match ? match[1] : null;
+            };
+            
+            // 获取租户编码:URL参数 > localStorage
+            const getTenantCode = () => {
+                const fromUrl = getUrlParam('tenantCode');
+                if (fromUrl) return fromUrl;
+                try {
+                    return localStorage.getItem('tenantCode') || '';
+                } catch(e) { return ''; }
+            };
+            
+            // 认证请求工具
             const request = async (url, options = {}) => {
             const request = async (url, options = {}) => {
-                const defaultOptions = {
-                    headers: {
-                        'Content-Type': 'application/json',
-                    },
+                const token = getToken();
+                const tenantCode = getTenantCode();
+                const headers = {
+                    'Content-Type': 'application/json',
+                    'X-Frontend-Type': FRONTEND_TYPE,
                 };
                 };
-                const response = await fetch(url, { ...defaultOptions, ...options });
+                if (token) {
+                    headers['Authorization'] = 'Bearer ' + token;
+                }
+                if (tenantCode) {
+                    headers['tenant-code'] = tenantCode;
+                }
+                // 合并自定义headers
+                if (options.headers) {
+                    Object.assign(headers, options.headers);
+                }
+                
+                const fullUrl = url.startsWith('http') ? url : (BASE_API + url);
+                const response = await fetch(fullUrl, {
+                    ...options,
+                    headers,
+                    credentials: 'include',
+                });
                 if (!response.ok) {
                 if (!response.ok) {
-                    throw new Error(`HTTP ${response.status}: ${response.statusText}`);
+                    const text = await response.text().catch(() => '');
+                    throw new Error(`HTTP ${response.status}: ${text || response.statusText}`);
+                }
+                const data = await response.json();
+                if (data.code === 401) {
+                    // Token过期,通知父窗口刷新
+                    if (window.parent && window.parent.location) {
+                        window.parent.location.reload();
+                    }
+                    throw new Error('登录已过期');
                 }
                 }
-                return await response.json();
+                return data;
             };
             };
 
 
             // 账户列表
             // 账户列表

+ 1 - 1
fs-framework/src/main/java/com/fs/framework/config/ResourcesConfig.java

@@ -62,7 +62,7 @@ public class ResourcesConfig implements WebMvcConfigurer
         CorsConfiguration config = new CorsConfiguration();
         CorsConfiguration config = new CorsConfiguration();
         config.setAllowCredentials(true);
         config.setAllowCredentials(true);
         // 设置访问源地址
         // 设置访问源地址
-        config.addAllowedOrigin("*");
+        config.addAllowedOriginPattern("*");
         // 设置访问源请求头
         // 设置访问源请求头
         config.addAllowedHeader("*");
         config.addAllowedHeader("*");
         // 设置访问源请求方法
         // 设置访问源请求方法

+ 1 - 7
fs-framework/src/main/java/com/fs/framework/security/filter/JwtAuthenticationTokenFilter.java

@@ -86,13 +86,7 @@ public class JwtAuthenticationTokenFilter extends OncePerRequestFilter
 
 
                 if (tenantId != null) {
                 if (tenantId != null) {
                     SysConfig cfg = sysConfigMapper.selectConfigByConfigKey("projectConfig");
                     SysConfig cfg = sysConfigMapper.selectConfigByConfigKey("projectConfig");
-                    if (cfg != null && StringUtils.isNotBlank(cfg.getConfigValue())) {
-                        TenantConfigContext.set(JSONObject.parseObject(cfg.getConfigValue()));
-                    } else {
-                        TenantConfigContext.set(null);
-                    }
-
-                    ProjectConfig.loadTenantConfigsFromContext();
+                    ProjectConfig.safeLoadTenantConfigFromValue(cfg != null ? cfg.getConfigValue() : null);
                 }
                 }
 
 
                 tokenService.verifyToken(loginUser);
                 tokenService.verifyToken(loginUser);

+ 2 - 7
fs-framework/src/main/java/com/fs/framework/task/TenantTaskRunner.java

@@ -101,14 +101,9 @@ public class TenantTaskRunner {
             log.info("[SaaS Task] 定时任务切换数据源和Redis dataSource={}, tenantId={}, tenantCode={}, task={}",
             log.info("[SaaS Task] 定时任务切换数据源和Redis dataSource={}, tenantId={}, tenantCode={}, task={}",
                     dataSourceKey, tenant.getId(), tenant.getTenantCode(), taskName != null ? taskName : "");
                     dataSourceKey, tenant.getId(), tenant.getTenantCode(), taskName != null ? taskName : "");
 
 
-            // 加载租户项目配置
+            // 加载租户项目配置(安全解析,防止非法JSON导致级联崩溃)
             SysConfig cfg = sysConfigMapper.selectConfigByConfigKey("projectConfig");
             SysConfig cfg = sysConfigMapper.selectConfigByConfigKey("projectConfig");
-            if (cfg != null && StringUtils.isNotBlank(cfg.getConfigValue())) {
-                TenantConfigContext.set(JSONObject.parseObject(cfg.getConfigValue()));
-            } else {
-                TenantConfigContext.set(null);
-            }
-            ProjectConfig.loadTenantConfigsFromContext();
+            ProjectConfig.safeLoadTenantConfigFromValue(cfg != null ? cfg.getConfigValue() : null);
 
 
             // 执行租户任务
             // 执行租户任务
             action.accept(tenant);
             action.accept(tenant);

+ 89 - 4
fs-framework/src/main/java/com/fs/framework/web/service/TokenService.java

@@ -1,13 +1,19 @@
 package com.fs.framework.web.service;
 package com.fs.framework.web.service;
 
 
 import java.util.HashMap;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeUnit;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletRequest;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Component;
 import org.springframework.stereotype.Component;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
 import com.fs.common.constant.Constants;
 import com.fs.common.constant.Constants;
+import com.fs.common.core.domain.entity.SysUser;
 import com.fs.common.core.domain.model.LoginUser;
 import com.fs.common.core.domain.model.LoginUser;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.ServletUtils;
@@ -49,6 +55,9 @@ public class TokenService
     @Autowired
     @Autowired
     private RedisCache redisCache;
     private RedisCache redisCache;
 
 
+    @Autowired
+    private RedisTemplate<Object, Object> redisTemplate;
+
     /**
     /**
      * 获取用户身份信息
      * 获取用户身份信息
      *
      *
@@ -63,11 +72,23 @@ public class TokenService
             try
             try
             {
             {
                 Claims claims = parseToken(token);
                 Claims claims = parseToken(token);
-                // 解析对应的权限以及用户信息
+                // 优先使用 login_user_key(平台管理端登录)
                 String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
                 String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
-                String userKey = getTokenKey(uuid);
-                LoginUser user = redisCache.getCacheObject(userKey);
-                return user;
+                if (StringUtils.isNotEmpty(uuid))
+                {
+                    String userKey = getTokenKey(uuid);
+                    LoginUser user = redisCache.getCacheObject(userKey);
+                    if (user != null)
+                    {
+                        return user;
+                    }
+                }
+                // 兼容租户端token:回退到 company_login_user_key
+                String companyUuid = (String) claims.get(Constants.COMPANY_LOGIN_USER_KEY);
+                if (StringUtils.isNotEmpty(companyUuid))
+                {
+                    return convertCompanyLoginUser(claims, companyUuid);
+                }
             }
             }
             catch (Exception e)
             catch (Exception e)
             {
             {
@@ -76,6 +97,70 @@ public class TokenService
         return null;
         return null;
     }
     }
 
 
+    /**
+     * 从Redis读取company端LoginUser并转换为admin端LoginUser,使company token在fs-admin中可用。
+     */
+    private LoginUser convertCompanyLoginUser(Claims claims, String companyUuid)
+    {
+        try
+        {
+            Long tenantId = claims.get("tenantId") != null ? ((Number) claims.get("tenantId")).longValue() : null;
+            String companyUserKey;
+            if (tenantId != null)
+            {
+                companyUserKey = "tenantid:" + tenantId + ":company_login_tokens:" + companyUuid;
+            }
+            else
+            {
+                companyUserKey = Constants.COMPANY_LOGIN_TOKEN_KEY + companyUuid;
+            }
+            Object cached = redisTemplate.opsForValue().get(companyUserKey);
+            if (cached == null)
+            {
+                return null;
+            }
+            String json = JSON.toJSONString(cached);
+            JSONObject companyObj = JSON.parseObject(json);
+
+            LoginUser loginUser = new LoginUser();
+            loginUser.setToken(companyObj.getString("token"));
+            loginUser.setLoginTime(companyObj.getLong("loginTime"));
+            loginUser.setExpireTime(companyObj.getLong("expireTime"));
+            loginUser.setIpaddr(companyObj.getString("ipaddr"));
+            loginUser.setLoginLocation(companyObj.getString("loginLocation"));
+            loginUser.setBrowser(companyObj.getString("browser"));
+            loginUser.setOs(companyObj.getString("os"));
+            loginUser.setTenantId(companyObj.getLong("tenantId"));
+
+            // 权限 - 租户管理员拥有租户相关权限
+            Set<String> permissions = new HashSet<>();
+            permissions.add("*:*:*");
+            loginUser.setPermissions(permissions);
+
+            // 构造SysUser从CompanyUser字段
+            JSONObject userObj = companyObj.getJSONObject("user");
+            if (userObj != null)
+            {
+                SysUser sysUser = new SysUser();
+                sysUser.setUserId(userObj.getLong("userId"));
+                sysUser.setUserName(userObj.getString("userName"));
+                sysUser.setNickName(userObj.getString("nickName"));
+                sysUser.setEmail(userObj.getString("email"));
+                sysUser.setPhonenumber(userObj.getString("phonenumber"));
+                sysUser.setSex(userObj.getString("sex"));
+                sysUser.setAvatar(userObj.getString("avatar"));
+                sysUser.setStatus(userObj.getString("status"));
+                loginUser.setUser(sysUser);
+            }
+
+            return loginUser;
+        }
+        catch (Exception e)
+        {
+            return null;
+        }
+    }
+
     /**
     /**
      * 设置用户身份信息
      * 设置用户身份信息
      */
      */

+ 1 - 6
fs-live-app/src/main/java/com/fs/live/task/TenantTaskRunner.java

@@ -143,12 +143,7 @@ public class TenantTaskRunner {
             // 加载租户项目配置(容错:租户库可能没有 sys_config 表)
             // 加载租户项目配置(容错:租户库可能没有 sys_config 表)
             try {
             try {
                 SysConfig cfg = sysConfigMapper.selectConfigByConfigKey("projectConfig");
                 SysConfig cfg = sysConfigMapper.selectConfigByConfigKey("projectConfig");
-                if (cfg != null && StringUtils.isNotBlank(cfg.getConfigValue())) {
-                    TenantConfigContext.set(JSONObject.parseObject(cfg.getConfigValue()));
-                } else {
-                    TenantConfigContext.set(null);
-                }
-                ProjectConfig.loadTenantConfigsFromContext();
+                ProjectConfig.safeLoadTenantConfigFromValue(cfg != null ? cfg.getConfigValue() : null);
             } catch (Exception e) {
             } catch (Exception e) {
                 log.error("[SaaS Live Task] 租户 {} 加载项目配置失败, 使用默认配置: {}",
                 log.error("[SaaS Live Task] 租户 {} 加载项目配置失败, 使用默认配置: {}",
                         tenant.getTenantCode(), e.getMessage());
                         tenant.getTenantCode(), e.getMessage());

+ 4 - 19
fs-live-app/src/main/java/com/fs/live/websocket/auth/TenantChannelContext.java

@@ -87,15 +87,10 @@ public class TenantChannelContext {
         SecurityContextHolder.getContext().setAuthentication(
         SecurityContextHolder.getContext().setAuthentication(
                 new UsernamePasswordAuthenticationToken(
                 new UsernamePasswordAuthenticationToken(
                         new TenantPrincipal(tenantId), null, Collections.emptyList()));
                         new TenantPrincipal(tenantId), null, Collections.emptyList()));
-        // 加载项目配置
+        // 加载项目配置(安全解析,防止非法JSON导致级联崩溃)
         try {
         try {
             SysConfig cfg = sysConfigMapper.selectConfigByConfigKey("projectConfig");
             SysConfig cfg = sysConfigMapper.selectConfigByConfigKey("projectConfig");
-            if (cfg != null && StringUtils.isNotBlank(cfg.getConfigValue())) {
-                TenantConfigContext.set(JSONObject.parseObject(cfg.getConfigValue()));
-            } else {
-                TenantConfigContext.set(null);
-            }
-            ProjectConfig.loadTenantConfigsFromContext();
+            ProjectConfig.safeLoadTenantConfigFromValue(cfg != null ? cfg.getConfigValue() : null);
         } catch (Exception e) {
         } catch (Exception e) {
             log.warn("[SaaS WS] 加载租户项目配置失败 tenantId={}", tenantId, e);
             log.warn("[SaaS WS] 加载租户项目配置失败 tenantId={}", tenantId, e);
         }
         }
@@ -199,12 +194,7 @@ public class TenantChannelContext {
                         new TenantPrincipal(tenantId), null, Collections.emptyList()));
                         new TenantPrincipal(tenantId), null, Collections.emptyList()));
         try {
         try {
             SysConfig cfg = sysConfigMapper.selectConfigByConfigKey("projectConfig");
             SysConfig cfg = sysConfigMapper.selectConfigByConfigKey("projectConfig");
-            if (cfg != null && StringUtils.isNotBlank(cfg.getConfigValue())) {
-                TenantConfigContext.set(JSONObject.parseObject(cfg.getConfigValue()));
-            } else {
-                TenantConfigContext.set(null);
-            }
-            ProjectConfig.loadTenantConfigsFromContext();
+            ProjectConfig.safeLoadTenantConfigFromValue(cfg != null ? cfg.getConfigValue() : null);
         } catch (Exception e) {
         } catch (Exception e) {
             log.warn("[SaaS WS] 加载租户项目配置失败 tenantId={}", tenantId, e);
             log.warn("[SaaS WS] 加载租户项目配置失败 tenantId={}", tenantId, e);
         }
         }
@@ -238,12 +228,7 @@ public class TenantChannelContext {
                             new TenantPrincipal(tenant.getId()), null, Collections.emptyList()));
                             new TenantPrincipal(tenant.getId()), null, Collections.emptyList()));
             try {
             try {
                 SysConfig cfg = sysConfigMapper.selectConfigByConfigKey("projectConfig");
                 SysConfig cfg = sysConfigMapper.selectConfigByConfigKey("projectConfig");
-                if (cfg != null && StringUtils.isNotBlank(cfg.getConfigValue())) {
-                    TenantConfigContext.set(JSONObject.parseObject(cfg.getConfigValue()));
-                } else {
-                    TenantConfigContext.set(null);
-                }
-                ProjectConfig.loadTenantConfigsFromContext();
+                ProjectConfig.safeLoadTenantConfigFromValue(cfg != null ? cfg.getConfigValue() : null);
             } catch (Exception e) {
             } catch (Exception e) {
                 log.warn("[SaaS WS] 加载租户项目配置失败 tenantId={}", tenant.getId(), e);
                 log.warn("[SaaS WS] 加载租户项目配置失败 tenantId={}", tenant.getId(), e);
             }
             }

+ 2 - 7
fs-qw-api/src/main/java/com/fs/app/qwTask/TenantTaskRunner.java

@@ -191,14 +191,9 @@ public class TenantTaskRunner {
             log.info("[SaaS Task] 定时任务切换数据源和Redis dataSource={}, tenantId={}, tenantCode={}, task={}",
             log.info("[SaaS Task] 定时任务切换数据源和Redis dataSource={}, tenantId={}, tenantCode={}, task={}",
                     dataSourceKey, tenant.getId(), tenant.getTenantCode(), taskName != null ? taskName : "");
                     dataSourceKey, tenant.getId(), tenant.getTenantCode(), taskName != null ? taskName : "");
 
 
-            // 加载租户项目配置
+            // 加载租户项目配置(安全解析,防止非法JSON导致级联崩溃)
             SysConfig cfg = sysConfigMapper.selectConfigByConfigKey("projectConfig");
             SysConfig cfg = sysConfigMapper.selectConfigByConfigKey("projectConfig");
-            if (cfg != null && StringUtils.isNotBlank(cfg.getConfigValue())) {
-                TenantConfigContext.set(JSONObject.parseObject(cfg.getConfigValue()));
-            } else {
-                TenantConfigContext.set(null);
-            }
-            ProjectConfig.loadTenantConfigsFromContext();
+            ProjectConfig.safeLoadTenantConfigFromValue(cfg != null ? cfg.getConfigValue() : null);
 
 
             // 执行租户任务
             // 执行租户任务
             action.accept(tenant);
             action.accept(tenant);

+ 2 - 7
fs-qw-task/src/main/java/com/fs/app/task/TenantTaskRunner.java

@@ -178,14 +178,9 @@ public class TenantTaskRunner {
             log.info("[SaaS Task] 定时任务切换数据源和Redis dataSource={}, tenantId={}, tenantCode={}, task={}",
             log.info("[SaaS Task] 定时任务切换数据源和Redis dataSource={}, tenantId={}, tenantCode={}, task={}",
                     dataSourceKey, tenant.getId(), tenant.getTenantCode(), taskName != null ? taskName : "");
                     dataSourceKey, tenant.getId(), tenant.getTenantCode(), taskName != null ? taskName : "");
 
 
-            // 加载租户项目配置
+            // 加载租户项目配置(安全解析,防止非法JSON导致级联崩溃)
             SysConfig cfg = sysConfigMapper.selectConfigByConfigKey("projectConfig");
             SysConfig cfg = sysConfigMapper.selectConfigByConfigKey("projectConfig");
-            if (cfg != null && StringUtils.isNotBlank(cfg.getConfigValue())) {
-                TenantConfigContext.set(JSONObject.parseObject(cfg.getConfigValue()));
-            } else {
-                TenantConfigContext.set(null);
-            }
-            ProjectConfig.loadTenantConfigsFromContext();
+            ProjectConfig.safeLoadTenantConfigFromValue(cfg != null ? cfg.getConfigValue() : null);
 
 
             // 执行租户任务
             // 执行租户任务
             action.accept(tenant);
             action.accept(tenant);

+ 2 - 12
fs-qwhook/src/main/java/com/fs/framework/filter/AppTenantSwitchFilter.java

@@ -56,12 +56,7 @@ public class AppTenantSwitchFilter extends OncePerRequestFilter {
         try {
         try {
             if (StringUtils.isBlank(corpId)) {
             if (StringUtils.isBlank(corpId)) {
                 SysConfig cfg = sysConfigMapper.selectConfigByConfigKey("projectConfig");
                 SysConfig cfg = sysConfigMapper.selectConfigByConfigKey("projectConfig");
-                if (cfg != null && StringUtils.isNotBlank(cfg.getConfigValue())) {
-                    TenantConfigContext.set(JSONObject.parseObject(cfg.getConfigValue()));
-                } else {
-                    TenantConfigContext.set(null);
-                }
-                ProjectConfig.loadTenantConfigsFromContext();
+                ProjectConfig.safeLoadTenantConfigFromValue(cfg != null ? cfg.getConfigValue() : null);
 
 
                 // 未携带企微编号:保持单库行为,直接放行
                 // 未携带企微编号:保持单库行为,直接放行
                 filterChain.doFilter(request, response);
                 filterChain.doFilter(request, response);
@@ -90,12 +85,7 @@ public class AppTenantSwitchFilter extends OncePerRequestFilter {
 
 
             // Step 3:从租户库读取项目配置(projectConfig),填充 TenantConfigContext 和 ProjectConfig
             // Step 3:从租户库读取项目配置(projectConfig),填充 TenantConfigContext 和 ProjectConfig
             SysConfig cfg = sysConfigMapper.selectConfigByConfigKey("projectConfig");
             SysConfig cfg = sysConfigMapper.selectConfigByConfigKey("projectConfig");
-            if (cfg != null && StringUtils.isNotBlank(cfg.getConfigValue())) {
-                TenantConfigContext.set(JSONObject.parseObject(cfg.getConfigValue()));
-            } else {
-                TenantConfigContext.set(null);
-            }
-            ProjectConfig.loadTenantConfigsFromContext();
+            ProjectConfig.safeLoadTenantConfigFromValue(cfg != null ? cfg.getConfigValue() : null);
 
 
             // 设置租户到 SecurityContext,供 TenantKeyRedisSerializer 自动为 Redis Key 加 tenantid 前缀
             // 设置租户到 SecurityContext,供 TenantKeyRedisSerializer 自动为 Redis Key 加 tenantid 前缀
             SecurityContextHolder.getContext().setAuthentication(
             SecurityContextHolder.getContext().setAuthentication(

+ 65 - 0
fs-service/pom.xml

@@ -21,11 +21,76 @@
     </properties>
     </properties>
 
 
     <dependencies>
     <dependencies>
+        <!-- 验证码 -->
+        <dependency>
+            <groupId>com.github.penggle</groupId>
+            <artifactId>kaptcha</artifactId>
+            <exclusions>
+                <exclusion>
+                    <artifactId>javax.servlet-api</artifactId>
+                    <groupId>javax.servlet</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <!-- swagger2 -->
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger2</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger-ui</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.github.xiaoymin</groupId>
+            <artifactId>swagger-bootstrap-ui</artifactId>
+            <version>1.9.3</version>
+        </dependency>
+
+        <!-- IJPay微信支付 -->
+        <dependency>
+            <groupId>com.github.javen205</groupId>
+            <artifactId>IJPay-All</artifactId>
+        </dependency>
+
+        <!-- 定时任务 -->
+        <dependency>
+            <groupId>org.quartz-scheduler</groupId>
+            <artifactId>quartz</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.mchange</groupId>
+                    <artifactId>c3p0</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <!-- 获取系统信息 -->
+        <dependency>
+            <groupId>com.github.oshi</groupId>
+            <artifactId>oshi-core</artifactId>
+        </dependency>
+
         <dependency>
         <dependency>
             <groupId>cn.jpush.api</groupId>
             <groupId>cn.jpush.api</groupId>
             <artifactId>jpush-client</artifactId>
             <artifactId>jpush-client</artifactId>
             <version>3.4.3</version>
             <version>3.4.3</version>
         </dependency>
         </dependency>
+
+        <!-- 支付宝SDK -->
+        <dependency>
+            <groupId>com.alipay.sdk</groupId>
+            <artifactId>alipay-sdk-java</artifactId>
+            <version>4.8.62.ALL</version>
+        </dependency>
+
+        <!-- MySQL驱动 -->
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+
         <!-- okhttp -->
         <!-- okhttp -->
         <dependency>
         <dependency>
             <groupId>com.squareup.okhttp3</groupId>
             <groupId>com.squareup.okhttp3</groupId>

+ 7 - 81
fs-service/src/main/java/com/fs/ad/controller/AdAccountController.java

@@ -1,27 +1,15 @@
 package com.fs.ad.controller;
 package com.fs.ad.controller;
 
 
-import java.util.List;
-import org.springframework.security.access.prepost.PreAuthorize;
+import com.fs.ad.service.IAdAccountService;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.R;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.bind.annotation.RestController;
-import com.fs.common.annotation.Log;
-import com.fs.common.core.controller.BaseController;
-import com.fs.common.core.domain.AjaxResult;
-import com.fs.common.enums.BusinessType;
-import com.fs.ad.domain.AdAccount;
-import com.fs.ad.service.IAdAccountService;
-import com.fs.common.utils.poi.ExcelUtil;
-import com.fs.common.core.page.TableDataInfo;
 
 
 /**
 /**
- * 推广账户Controller
+ * 站点管理Controller
  * 
  * 
  * @author fs
  * @author fs
  * @date 2025-03-04
  * @date 2025-03-04
@@ -33,71 +21,9 @@ public class AdAccountController extends BaseController
     @Autowired
     @Autowired
     private IAdAccountService adAccountService;
     private IAdAccountService adAccountService;
 
 
-    /**
-     * 查询推广账户列表
-     */
-    @PreAuthorize("@ss.hasPermi('ad:adAccount:list')")
-    @GetMapping("/list")
-    public TableDataInfo list(AdAccount adAccount)
-    {
-        startPage();
-        List<AdAccount> list = adAccountService.selectAdAccountList(adAccount);
-        return getDataTable(list);
+    @GetMapping("/listAll")
+    public R listAll(){
+        return R.ok().put("data", adAccountService.listAll());
     }
     }
 
 
-    /**
-     * 导出推广账户列表
-     */
-    @PreAuthorize("@ss.hasPermi('ad:adAccount:export')")
-    @Log(title = "推广账户", businessType = BusinessType.EXPORT)
-    @GetMapping("/export")
-    public AjaxResult export(AdAccount adAccount)
-    {
-        List<AdAccount> list = adAccountService.selectAdAccountList(adAccount);
-        ExcelUtil<AdAccount> util = new ExcelUtil<AdAccount>(AdAccount.class);
-        return util.exportExcel(list, "推广账户数据");
-    }
-
-    /**
-     * 获取推广账户详细信息
-     */
-    @PreAuthorize("@ss.hasPermi('ad:adAccount:query')")
-    @GetMapping(value = "/{id}")
-    public AjaxResult getInfo(@PathVariable("id") Long id)
-    {
-        return AjaxResult.success(adAccountService.selectAdAccountById(id));
-    }
-
-    /**
-     * 新增推广账户
-     */
-    @PreAuthorize("@ss.hasPermi('ad:adAccount:add')")
-    @Log(title = "推广账户", businessType = BusinessType.INSERT)
-    @PostMapping
-    public AjaxResult add(@RequestBody AdAccount adAccount)
-    {
-        return toAjax(adAccountService.insertAdAccount(adAccount));
-    }
-
-    /**
-     * 修改推广账户
-     */
-    @PreAuthorize("@ss.hasPermi('ad:adAccount:edit')")
-    @Log(title = "推广账户", businessType = BusinessType.UPDATE)
-    @PutMapping
-    public AjaxResult edit(@RequestBody AdAccount adAccount)
-    {
-        return toAjax(adAccountService.updateAdAccount(adAccount));
-    }
-
-    /**
-     * 删除推广账户
-     */
-    @PreAuthorize("@ss.hasPermi('ad:adAccount:remove')")
-    @Log(title = "推广账户", businessType = BusinessType.DELETE)
-	@DeleteMapping("/{ids}")
-    public AjaxResult remove(@PathVariable Long[] ids)
-    {
-        return toAjax(adAccountService.deleteAdAccountByIds(ids));
-    }
 }
 }

+ 106 - 0
fs-service/src/main/java/com/fs/ad/controller/AdDomainController.java

@@ -0,0 +1,106 @@
+package com.fs.ad.controller;
+
+import com.fs.ad.domain.AdDomain;
+import com.fs.ad.service.IAdDomainService;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 广告域名Controller
+ * 
+ * @author fs
+ * @date 2025-03-04
+ */
+@RestController
+@RequestMapping("/ad/adDomain")
+public class AdDomainController extends BaseController
+{
+    @Autowired
+    private IAdDomainService adDomainService;
+
+    /**
+     * 查询广告域名列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adDomain:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(AdDomain adDomain)
+    {
+        startPage();
+        List<AdDomain> list = adDomainService.selectAdDomainList(adDomain);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出广告域名列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adDomain:export')")
+    @Log(title = "广告域名", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(AdDomain adDomain)
+    {
+        List<AdDomain> list = adDomainService.selectAdDomainList(adDomain);
+        ExcelUtil<AdDomain> util = new ExcelUtil<AdDomain>(AdDomain.class);
+        return util.exportExcel(list, "广告域名数据");
+    }
+
+    /**
+     * 获取广告域名详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adDomain:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(adDomainService.selectAdDomainById(id));
+    }
+
+    /**
+     * 新增广告域名
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adDomain:add')")
+    @Log(title = "广告域名", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody AdDomain adDomain)
+    {
+        return toAjax(adDomainService.insertAdDomain(adDomain));
+    }
+
+    /**
+     * 修改广告域名
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adDomain:edit')")
+    @Log(title = "广告域名", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody AdDomain adDomain)
+    {
+        return toAjax(adDomainService.updateAdDomain(adDomain));
+    }
+
+    /**
+     * 删除广告域名
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adDomain:remove')")
+    @Log(title = "广告域名", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(adDomainService.deleteAdDomainByIds(ids));
+    }
+
+
+
+
+    @GetMapping(value = "/listAll")
+    public R listAll(){
+        return R.ok().put("data", adDomainService.list());
+    }
+}

+ 103 - 0
fs-service/src/main/java/com/fs/ad/controller/AdDyAccountController.java

@@ -0,0 +1,103 @@
+package com.fs.ad.controller;
+
+import java.util.List;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.ad.domain.AdDyAccount;
+import com.fs.ad.service.IAdDyAccountService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 抖音账户Controller
+ * 
+ * @author 吴树波
+ * @date 2025-05-27
+ */
+@RestController
+@RequestMapping("/ad/AdDyAccount")
+public class AdDyAccountController extends BaseController
+{
+    @Autowired
+    private IAdDyAccountService adDyAccountService;
+
+    /**
+     * 查询抖音账户列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdDyAccount:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(AdDyAccount adDyAccount)
+    {
+        startPage();
+        List<AdDyAccount> list = adDyAccountService.selectAdDyAccountList(adDyAccount);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出抖音账户列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdDyAccount:export')")
+    @Log(title = "抖音账户", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(AdDyAccount adDyAccount)
+    {
+        List<AdDyAccount> list = adDyAccountService.selectAdDyAccountList(adDyAccount);
+        ExcelUtil<AdDyAccount> util = new ExcelUtil<AdDyAccount>(AdDyAccount.class);
+        return util.exportExcel(list, "抖音账户数据");
+    }
+
+    /**
+     * 获取抖音账户详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdDyAccount:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(adDyAccountService.selectAdDyAccountById(id));
+    }
+
+    /**
+     * 新增抖音账户
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdDyAccount:add')")
+    @Log(title = "抖音账户", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody AdDyAccount adDyAccount)
+    {
+        return toAjax(adDyAccountService.insertAdDyAccount(adDyAccount));
+    }
+
+    /**
+     * 修改抖音账户
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdDyAccount:edit')")
+    @Log(title = "抖音账户", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody AdDyAccount adDyAccount)
+    {
+        return toAjax(adDyAccountService.updateAdDyAccount(adDyAccount));
+    }
+
+    /**
+     * 删除抖音账户
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdDyAccount:remove')")
+    @Log(title = "抖音账户", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(adDyAccountService.deleteAdDyAccountByIds(ids));
+    }
+}

+ 114 - 0
fs-service/src/main/java/com/fs/ad/controller/AdDyApiController.java

@@ -0,0 +1,114 @@
+package com.fs.ad.controller;
+
+import java.util.List;
+
+import com.fs.ad.vo.DyAuthorizedVo;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.ad.domain.AdDyApi;
+import com.fs.ad.service.IAdDyApiService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 抖音投流API信息Controller
+ * 
+ * @author 吴树波
+ * @date 2025-05-27
+ */
+@RestController
+@RequestMapping("/ad/adDyApi")
+public class AdDyApiController extends BaseController
+{
+    @Autowired
+    private IAdDyApiService adDyApiService;
+
+    /**
+     * 查询抖音投流API信息列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adDyApi:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(AdDyApi adDyApi)
+    {
+        startPage();
+        List<AdDyApi> list = adDyApiService.selectAdDyApiList(adDyApi);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出抖音投流API信息列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adDyApi:export')")
+    @Log(title = "抖音投流API信息", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(AdDyApi adDyApi)
+    {
+        List<AdDyApi> list = adDyApiService.selectAdDyApiList(adDyApi);
+        ExcelUtil<AdDyApi> util = new ExcelUtil<AdDyApi>(AdDyApi.class);
+        return util.exportExcel(list, "抖音投流API信息数据");
+    }
+
+    /**
+     * 获取抖音投流API信息详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adDyApi:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(adDyApiService.selectAdDyApiById(id));
+    }
+
+    /**
+     * 新增抖音投流API信息
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adDyApi:add')")
+    @Log(title = "抖音投流API信息", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody AdDyApi adDyApi)
+    {
+        return toAjax(adDyApiService.insertAdDyApi(adDyApi));
+    }
+
+    /**
+     * 修改抖音投流API信息
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adDyApi:edit')")
+    @Log(title = "抖音投流API信息", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody AdDyApi adDyApi)
+    {
+        return toAjax(adDyApiService.updateAdDyApi(adDyApi));
+    }
+
+    /**
+     * 删除抖音投流API信息
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adDyApi:remove')")
+    @Log(title = "抖音投流API信息", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(adDyApiService.deleteAdDyApiByIds(ids));
+    }
+    /**
+     * 删除抖音投流API信息
+     */
+    @Log(title = "抖音API授权", businessType = BusinessType.UPDATE)
+	@GetMapping("/authorized")
+    public String authorized(DyAuthorizedVo vo){
+        System.out.println(vo);
+        return "授权成功";
+    }
+}

+ 97 - 0
fs-service/src/main/java/com/fs/ad/controller/AdHtmlClickLogController.java

@@ -0,0 +1,97 @@
+package com.fs.ad.controller;
+
+import com.fs.ad.domain.AdHtmlClickLog;
+import com.fs.ad.service.IAdHtmlClickLogService;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 广告点击Controller
+ * 
+ * @author fs
+ * @date 2025-01-09
+ */
+@RestController
+@RequestMapping("/ad/clickLog")
+public class AdHtmlClickLogController extends BaseController
+{
+    @Autowired
+    private IAdHtmlClickLogService adHtmlClickLogService;
+
+    /**
+     * 查询广告点击列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:clickLog:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(AdHtmlClickLog adHtmlClickLog)
+    {
+        startPage();
+        List<AdHtmlClickLog> list = adHtmlClickLogService.selectAdHtmlClickLogList(adHtmlClickLog);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出广告点击列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:clickLog:export')")
+    @Log(title = "广告点击", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(AdHtmlClickLog adHtmlClickLog)
+    {
+        List<AdHtmlClickLog> list = adHtmlClickLogService.selectAdHtmlClickLogList(adHtmlClickLog);
+        ExcelUtil<AdHtmlClickLog> util = new ExcelUtil<AdHtmlClickLog>(AdHtmlClickLog.class);
+        return util.exportExcel(list, "广告点击数据");
+    }
+
+    /**
+     * 获取广告点击详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('ad:clickLog:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(adHtmlClickLogService.selectAdHtmlClickLogById(id));
+    }
+
+    /**
+     * 新增广告点击
+     */
+    @PreAuthorize("@ss.hasPermi('ad:clickLog:add')")
+    @Log(title = "广告点击", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody AdHtmlClickLog adHtmlClickLog)
+    {
+        return toAjax(adHtmlClickLogService.insertAdHtmlClickLog(adHtmlClickLog));
+    }
+
+    /**
+     * 修改广告点击
+     */
+    @PreAuthorize("@ss.hasPermi('ad:clickLog:edit')")
+    @Log(title = "广告点击", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody AdHtmlClickLog adHtmlClickLog)
+    {
+        return toAjax(adHtmlClickLogService.updateAdHtmlClickLog(adHtmlClickLog));
+    }
+
+    /**
+     * 删除广告点击
+     */
+    @PreAuthorize("@ss.hasPermi('ad:clickLog:remove')")
+    @Log(title = "广告点击", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(adHtmlClickLogService.deleteAdHtmlClickLogByIds(ids));
+    }
+}

+ 103 - 0
fs-service/src/main/java/com/fs/ad/controller/AdHtmlTemplateController.java

@@ -0,0 +1,103 @@
+package com.fs.ad.controller;
+
+import com.fs.ad.domain.AdHtmlTemplate;
+import com.fs.ad.service.IAdHtmlTemplateService;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 广告信息流链接Controller
+ * 
+ * @author fs
+ * @date 2024-12-31
+ */
+@RestController
+@RequestMapping("/ad/html/template")
+public class AdHtmlTemplateController extends BaseController
+{
+    @Autowired
+    private IAdHtmlTemplateService adHtmlUrlService;
+
+    /**
+     * 查询广告信息流链接列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:html:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(AdHtmlTemplate adHtmlTemplate)
+    {
+        startPage();
+        List<AdHtmlTemplate> list = adHtmlUrlService.selectAdHtmlUrlList(adHtmlTemplate);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出广告信息流链接列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:html:export')")
+    @Log(title = "广告信息流链接", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(AdHtmlTemplate adHtmlTemplate)
+    {
+        List<AdHtmlTemplate> list = adHtmlUrlService.selectAdHtmlUrlList(adHtmlTemplate);
+        ExcelUtil<AdHtmlTemplate> util = new ExcelUtil<AdHtmlTemplate>(AdHtmlTemplate.class);
+        return util.exportExcel(list, "广告信息流链接数据");
+    }
+
+    /**
+     * 获取广告信息流链接详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('ad:html:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(adHtmlUrlService.selectAdHtmlUrlById(id));
+    }
+
+    /**
+     * 新增广告信息流链接
+     */
+    @PreAuthorize("@ss.hasPermi('ad:html:add')")
+    @Log(title = "广告信息流链接", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody AdHtmlTemplate adHtmlTemplate)
+    {
+        return toAjax(adHtmlUrlService.insertAdHtmlUrl(adHtmlTemplate));
+    }
+
+    /**
+     * 修改广告信息流链接
+     */
+    @PreAuthorize("@ss.hasPermi('ad:html:edit')")
+    @Log(title = "广告信息流链接", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody AdHtmlTemplate adHtmlTemplate)
+    {
+        return toAjax(adHtmlUrlService.updateAdHtmlUrl(adHtmlTemplate));
+    }
+
+    /**
+     * 删除广告信息流链接
+     */
+    @PreAuthorize("@ss.hasPermi('ad:html:remove')")
+    @Log(title = "广告信息流链接", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(adHtmlUrlService.deleteAdHtmlUrlByIds(ids));
+    }
+
+    @GetMapping(value = "/listAll")
+    public R listAll(){
+        return R.ok().put("data", adHtmlUrlService.list());
+    }
+}

+ 106 - 0
fs-service/src/main/java/com/fs/ad/controller/AdIqiyiAccountController.java

@@ -0,0 +1,106 @@
+package com.fs.ad.controller;
+
+import com.fs.ad.domain.AdIqiyiAccount;
+import com.fs.ad.service.IAdIqiyiAccountService;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 爱奇艺广告账号Controller
+ * 
+ * @author fs
+ * @date 2025-03-03
+ */
+@RestController
+@RequestMapping("/ad/AdIqiyiAccount")
+public class AdIqiyiAccountController extends BaseController
+{
+    @Autowired
+    private IAdIqiyiAccountService adIqiyiAccountService;
+
+    /**
+     * 查询爱奇艺广告账号列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdIqiyiAccount:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(AdIqiyiAccount adIqiyiAccount)
+    {
+        startPage();
+        List<AdIqiyiAccount> list = adIqiyiAccountService.selectAdIqiyiAccountList(adIqiyiAccount);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出爱奇艺广告账号列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdIqiyiAccount:export')")
+    @Log(title = "爱奇艺广告账号", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(AdIqiyiAccount adIqiyiAccount)
+    {
+        List<AdIqiyiAccount> list = adIqiyiAccountService.selectAdIqiyiAccountList(adIqiyiAccount);
+        ExcelUtil<AdIqiyiAccount> util = new ExcelUtil<AdIqiyiAccount>(AdIqiyiAccount.class);
+        return util.exportExcel(list, "爱奇艺广告账号数据");
+    }
+
+    /**
+     * 获取爱奇艺广告账号详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdIqiyiAccount:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(adIqiyiAccountService.selectAdIqiyiAccountById(id));
+    }
+
+    /**
+     * 新增爱奇艺广告账号
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdIqiyiAccount:add')")
+    @Log(title = "爱奇艺广告账号", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody AdIqiyiAccount adIqiyiAccount)
+    {
+        return toAjax(adIqiyiAccountService.insertAdIqiyiAccount(adIqiyiAccount));
+    }
+
+    /**
+     * 修改爱奇艺广告账号
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdIqiyiAccount:edit')")
+    @Log(title = "爱奇艺广告账号", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody AdIqiyiAccount adIqiyiAccount)
+    {
+        return toAjax(adIqiyiAccountService.updateAdIqiyiAccount(adIqiyiAccount));
+    }
+
+    /**
+     * 删除爱奇艺广告账号
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdIqiyiAccount:remove')")
+    @Log(title = "爱奇艺广告账号", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(adIqiyiAccountService.deleteAdIqiyiAccountByIds(ids));
+    }
+    /**
+     * 删除优酷广告账号
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdYouKuaccount:list')")
+    @GetMapping("/listAll")
+    public R listAll(){
+        return R.ok().put("data", adIqiyiAccountService.listAll());
+    }
+}

+ 109 - 0
fs-service/src/main/java/com/fs/ad/controller/AdSiteController.java

@@ -0,0 +1,109 @@
+package com.fs.ad.controller;
+
+import com.fs.ad.domain.AdSite;
+import com.fs.ad.service.IAdSiteService;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 站点管理Controller
+ * 
+ * @author fs
+ * @date 2025-03-04
+ */
+@RestController
+@RequestMapping("/ad/adSite")
+public class AdSiteController extends BaseController
+{
+    @Autowired
+    private IAdSiteService adSiteService;
+
+    /**
+     * 查询站点管理列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adSite:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(AdSite adSite)
+    {
+        startPage();
+        List<AdSite> list = adSiteService.selectAdSiteList(adSite);
+        return getDataTable(list);
+    }
+
+    /**
+     * 查询站点管理列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adSite:list')")
+    @GetMapping("/listAll")
+    public R listAll(AdSite adSite){
+        List<AdSite> list = adSiteService.selectAdSiteList(adSite);
+        return R.ok().put("data", list);
+    }
+
+    /**
+     * 导出站点管理列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adSite:export')")
+    @Log(title = "站点管理", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(AdSite adSite)
+    {
+        List<AdSite> list = adSiteService.selectAdSiteList(adSite);
+        ExcelUtil<AdSite> util = new ExcelUtil<AdSite>(AdSite.class);
+        return util.exportExcel(list, "站点管理数据");
+    }
+
+    /**
+     * 获取站点管理详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adSite:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(adSiteService.selectAdSiteById(id));
+    }
+
+    /**
+     * 新增站点管理
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adSite:add')")
+    @Log(title = "站点管理", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody AdSite adSite)
+    {
+        return toAjax(adSiteService.insertAdSite(adSite));
+    }
+
+    /**
+     * 修改站点管理
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adSite:edit')")
+    @Log(title = "站点管理", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody AdSite adSite)
+    {
+        return toAjax(adSiteService.updateAdSite(adSite));
+    }
+
+    /**
+     * 删除站点管理
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adSite:remove')")
+    @Log(title = "站点管理", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(adSiteService.deleteAdSiteByIds(ids));
+    }
+
+}

+ 97 - 0
fs-service/src/main/java/com/fs/ad/controller/AdUploadLogController.java

@@ -0,0 +1,97 @@
+package com.fs.ad.controller;
+
+import com.fs.ad.domain.AdUploadLog;
+import com.fs.ad.service.IAdUploadLogService;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 百度回传日志Controller
+ * 
+ * @author fs
+ * @date 2025-03-14
+ */
+@RestController
+@RequestMapping("/ad/AdUploadLog")
+public class AdUploadLogController extends BaseController
+{
+    @Autowired
+    private IAdUploadLogService adUploadLogService;
+
+    /**
+     * 查询百度回传日志列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdUploadLog:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(AdUploadLog adUploadLog)
+    {
+        startPage();
+        List<AdUploadLog> list = adUploadLogService.selectAdUploadLogList(adUploadLog);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出百度回传日志列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdUploadLog:export')")
+    @Log(title = "百度回传日志", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(AdUploadLog adUploadLog)
+    {
+        List<AdUploadLog> list = adUploadLogService.selectAdUploadLogList(adUploadLog);
+        ExcelUtil<AdUploadLog> util = new ExcelUtil<AdUploadLog>(AdUploadLog.class);
+        return util.exportExcel(list, "百度回传日志数据");
+    }
+
+    /**
+     * 获取百度回传日志详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdUploadLog:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(adUploadLogService.selectAdUploadLogById(id));
+    }
+
+    /**
+     * 新增百度回传日志
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdUploadLog:add')")
+    @Log(title = "百度回传日志", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody AdUploadLog adUploadLog)
+    {
+        return toAjax(adUploadLogService.insertAdUploadLog(adUploadLog));
+    }
+
+    /**
+     * 修改百度回传日志
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdUploadLog:edit')")
+    @Log(title = "百度回传日志", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody AdUploadLog adUploadLog)
+    {
+        return toAjax(adUploadLogService.updateAdUploadLog(adUploadLog));
+    }
+
+    /**
+     * 删除百度回传日志
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdUploadLog:remove')")
+    @Log(title = "百度回传日志", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(adUploadLogService.deleteAdUploadLogByIds(ids));
+    }
+}

+ 106 - 0
fs-service/src/main/java/com/fs/ad/controller/AdYoukuAccountController.java

@@ -0,0 +1,106 @@
+package com.fs.ad.controller;
+
+import com.fs.ad.domain.AdYoukuAccount;
+import com.fs.ad.service.IAdYoukuAccountService;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 优酷广告账号Controller
+ * 
+ * @author fs
+ * @date 2025-02-19
+ */
+@RestController
+@RequestMapping("/ad/AdYouKuAccount")
+public class AdYoukuAccountController extends BaseController
+{
+    @Autowired
+    private IAdYoukuAccountService adYoukuAccountService;
+
+    /**
+     * 查询优酷广告账号列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdYouKuaccount:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(AdYoukuAccount adYoukuAccount)
+    {
+        startPage();
+        List<AdYoukuAccount> list = adYoukuAccountService.selectAdYoukuAccountList(adYoukuAccount);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出优酷广告账号列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdYouKuaccount:export')")
+    @Log(title = "优酷广告账号", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(AdYoukuAccount adYoukuAccount)
+    {
+        List<AdYoukuAccount> list = adYoukuAccountService.selectAdYoukuAccountList(adYoukuAccount);
+        ExcelUtil<AdYoukuAccount> util = new ExcelUtil<AdYoukuAccount>(AdYoukuAccount.class);
+        return util.exportExcel(list, "优酷广告账号数据");
+    }
+
+    /**
+     * 获取优酷广告账号详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdYouKuaccount:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(adYoukuAccountService.selectAdYoukuAccountById(id));
+    }
+
+    /**
+     * 新增优酷广告账号
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdYouKuaccount:add')")
+    @Log(title = "优酷广告账号", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody AdYoukuAccount adYoukuAccount)
+    {
+        return toAjax(adYoukuAccountService.insertAdYoukuAccount(adYoukuAccount));
+    }
+
+    /**
+     * 修改优酷广告账号
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdYouKuaccount:edit')")
+    @Log(title = "优酷广告账号", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody AdYoukuAccount adYoukuAccount)
+    {
+        return toAjax(adYoukuAccountService.updateAdYoukuAccount(adYoukuAccount));
+    }
+
+    /**
+     * 删除优酷广告账号
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdYouKuaccount:remove')")
+    @Log(title = "优酷广告账号", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(adYoukuAccountService.deleteAdYoukuAccountByIds(ids));
+    }
+    /**
+     * 删除优酷广告账号
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdYouKuaccount:list')")
+	@GetMapping("/listAll")
+    public R listAll(){
+        return R.ok().put("data", adYoukuAccountService.listAll());
+    }
+}

+ 141 - 0
fs-service/src/main/java/com/fs/ad/controller/BdAccountController.java

@@ -0,0 +1,141 @@
+package com.fs.ad.controller;
+
+import com.fs.baidu.api.BaiduApis;
+import com.fs.baidu.domain.*;
+import com.fs.baidu.service.*;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import lombok.AllArgsConstructor;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * 百度账号Controller
+ * 
+ * @author fs
+ * @date 2025-01-20
+ */
+@RestController
+@AllArgsConstructor
+@RequestMapping("/bd/BdAccount")
+public class BdAccountController extends BaseController {
+    private final IBdAccountService bdAccountService;
+    private final IBdPlanService bdPlanService;
+    private final IBdUnitService bdUnitService;
+    private final IBdCreativeService bdCreativeService;
+    private final IBdApiService bdApiService;
+    private final BaiduApis baiduApis;
+
+    /**
+     * 查询百度账号列表
+     */
+    @PreAuthorize("@ss.hasPermi('baidu:BdAccount:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(BdAccount bdAccount){
+        startPage();
+        List<BdAccount> list = bdAccountService.selectBdAccountList(bdAccount);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出百度账号列表
+     */
+    @PreAuthorize("@ss.hasPermi('baidu:BdAccount:export')")
+    @Log(title = "百度账号", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(BdAccount bdAccount)
+    {
+        List<BdAccount> list = bdAccountService.selectBdAccountList(bdAccount);
+        ExcelUtil<BdAccount> util = new ExcelUtil<BdAccount>(BdAccount.class);
+        return util.exportExcel(list, "百度账号数据");
+    }
+
+    /**
+     * 获取百度账号详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('baidu:BdAccount:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(bdAccountService.selectBdAccountById(id));
+    }
+
+    /**
+     * 新增百度账号
+     */
+    @PreAuthorize("@ss.hasPermi('baidu:BdAccount:add')")
+    @Log(title = "百度账号", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody BdAccount bdAccount)
+    {
+        return toAjax(bdAccountService.insertBdAccount(bdAccount));
+    }
+
+    /**
+     * 修改百度账号
+     */
+    @PreAuthorize("@ss.hasPermi('baidu:BdAccount:edit')")
+    @Log(title = "百度账号", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody BdAccount bdAccount)
+    {
+        return toAjax(bdAccountService.updateBdAccount(bdAccount));
+    }
+
+    /**
+     * 删除百度账号
+     */
+    @PreAuthorize("@ss.hasPermi('baidu:BdAccount:remove')")
+    @Log(title = "百度账号", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(bdAccountService.deleteBdAccountByIds(ids));
+    }
+
+
+    /**
+     * 查询百度账号列表
+     */
+    @GetMapping("/listAll")
+    public R listAll(BdAccount bdAccount){
+        return R.ok().put("data", bdAccountService.selectBdAccountList(bdAccount));
+    }
+    @GetMapping("/listAllPlan")
+    public R listAllPlan(BdPlan plan){
+        return R.ok().put("data", bdPlanService.selectBdPlanList(plan));
+    }
+    @GetMapping("/listAllUnit")
+    public R listAllUnit(BdUnit unit){
+        return R.ok().put("data", bdUnitService.selectBdUnitList(unit));
+    }
+    @GetMapping("/listAllCreative")
+    public R listAllCreative(BdCreative creative){
+        return R.ok().put("data", bdCreativeService.selectBdCreativeList(creative));
+    }
+    @GetMapping("/authorizationUrl")
+    public R authorizationUrl(Long id){
+        Optional<BdApi> first = bdApiService.list().stream().findFirst();
+        if(!first.isPresent()){
+            return R.error("未找到API信息");
+        }
+        return R.ok().put("url", bdApiService.authorizationUrl(first.get().getId()));
+    }
+    @GetMapping("/syncAccount")
+    public R syncAccount(Long id){
+        Optional<BdApi> first = bdApiService.list().stream().findFirst();
+        if(!first.isPresent()){
+            return R.error("未找到API信息");
+        }
+        baiduApis.listAccount(1L, id);
+        return R.ok();
+    }
+}

+ 216 - 0
fs-service/src/main/java/com/fs/ad/controller/MockAppController.java

@@ -0,0 +1,216 @@
+package com.fs.ad.controller;
+
+import com.fs.baidu.domain.BdApi;
+import com.fs.baidu.service.IBdApiService;
+import com.fs.baidu.utils.SignService;
+import com.fs.huifuPay.sdk.opps.core.exception.BasePayException;
+import com.fs.huifuPay.sdk.opps.core.utils.HttpClientUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.commons.lang3.StringUtils;
+import org.json.JSONObject;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TreeMap;
+
+@RestController
+@RequestMapping("/baiduBack")
+public class MockAppController {
+    private static final Logger log = LoggerFactory.getLogger(MockAppController.class);
+    private static final String APPID = "appId";
+    private static final String AUTH_CODE = "authCode";
+    private static final String USERID = "userId";
+    private static final String TIMESTAMP = "timestamp";
+    private static final String SIGNATURE = "signature";
+    private static final String STATE = "state";
+    private static final String ACCESSTOKEN_URL = "https://u.baidu.com/oauth/accessToken";
+
+    @Autowired
+    private IBdApiService bdApiService; // 开发者自定义
+    @Autowired
+    private SignService signService; // 开发者可自定义
+
+    @GetMapping("/callback")
+    public String mockApp(HttpServletRequest request) throws BasePayException {
+
+        // 获取请求参数
+        Map<String, String> params = new HashMap<>();
+        this.fillParams(params, request);
+        log.info("callback: params = {}", JSONObject.valueToString(params));
+        int userIdInt = 0;
+        try {
+            userIdInt = Integer.parseInt(params.get(USERID));
+        } catch (Exception e) {
+            return this.getResponseJson(600011, "参数错误", new Object());
+        }
+        // 对签名内容进行判空
+        if (StringUtils.isBlank(params.get(SIGNATURE))) {
+            return this.getResponseJson(600011, "参数错误", new Object());
+        }
+
+        // 获取应用对应的密钥
+        BdApi app = bdApiService.getAppByAppId(params.get(APPID));
+        String sk = app.getAppSecretKey();
+        // 开发者进行验签
+        // 检查状态码
+//        if (!this.checkState(params.get(APPID), app.getAppUserId(), params.get(STATE))) {
+//            log.info("callback: state check fail");
+//            return this.getResponseJson(600011, "状态码错误", new Object());
+//        }
+
+        // 签名验证
+        if (!this.checkSignature(params, sk)) {
+            log.info("callback: signature check fail");
+            return this.getResponseJson(600011, "签名错误", new Object());
+        }
+
+        // 调用接口换取授权令牌
+        String response = this.getAccessToken(params, sk, userIdInt);
+        log.info("callback:getAccesstoken, response={}", response);
+        String accessToken = null;
+        String refreshToken = null;
+        int uid;
+
+        if (response.length() > 0) {
+            JSONObject res = new JSONObject(response);
+            int code = (int) res.get("code");
+            if (code == 0) {
+                JSONObject data = res.getJSONObject("data");
+                accessToken = (String) data.get("accessToken");
+                // 注释部分为 accessToken 其他信息,各应用开发者酌情使用即可
+                 refreshToken = (String) data.get("refreshToken");
+                String openId = data.getString("openId");
+                int expiresIn = data.getInt("expiresIn");
+                int refreshExpiresIn = data.getInt("refreshExpiresIn");
+                app.setAccessToken(accessToken);
+                app.setRefreshToken(refreshToken);
+                app.setExpiresIn(expiresIn);
+                app.setOpenId(openId);
+                app.setRefreshExpiresIn(refreshExpiresIn);
+                app.setAuthCode(params.get(AUTH_CODE));
+                bdApiService.updateById(app);
+
+                // TODO 相关信息落库处理
+            } else {
+                return this.getResponseJson(600011, "未获取到 access_token", new Object());
+            }
+        }
+        Map<String, String> data = new HashMap<>();
+        data.put("accessToken", accessToken);
+        return this.getResponseJson(0, "success", data);
+    }
+
+    /**
+     * 填充请求参数,开发者可用实体代替map
+     *
+     * @param params
+     * @param request
+     */
+    private void fillParams(Map<String, String> params, HttpServletRequest request) {
+        params.put(APPID, request.getParameter(APPID));
+        params.put(AUTH_CODE, request.getParameter(AUTH_CODE));
+        params.put(USERID, request.getParameter(USERID));
+        params.put(TIMESTAMP, request.getParameter(TIMESTAMP));
+        params.put(SIGNATURE, request.getParameter(SIGNATURE));
+        params.put(STATE, request.getParameter(STATE));
+    }
+
+    /**
+     * 校验状态码是否符合预期
+     *
+     * @param appId  应用ID
+     * @param userId 创建应用的ID
+     * @param state  请求参数中的状态码
+     * @return
+     */
+    private boolean checkState(String appId, Long userId, String state) {
+        // md5util 开发者自行开发即可
+        String newState = md5(appId.concat("_").concat(String.valueOf(userId)));
+        return newState.equals(state);
+    }
+    public static String md5(String input) {
+        try {
+            MessageDigest md = MessageDigest.getInstance("MD5");
+            byte[] messageDigest = md.digest(input.getBytes());
+            StringBuilder hexString = new StringBuilder();
+            for (byte b : messageDigest) {
+                String hex = Integer.toHexString(0xff & b);
+                if (hex.length() == 1) {
+                    hexString.append('0');
+                }
+                hexString.append(hex);
+            }
+            return hexString.toString();
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException(e);
+        }
+    }
+    /**
+     * 签名验证方法
+     *
+     * @param params
+     * @param sk
+     * @return
+     */
+    private boolean checkSignature(Map<String, String> params, String sk) {
+        // 获取验签字符串:按key自然排序,拼接成 json 字符串,
+        // 示例:str1 = {"appId": xxxxx, "authCode": xxx, "state": xxx,"timestamp": xxx}
+        TreeMap<String, Object> map = new TreeMap<>();
+        map.put(APPID, params.get(APPID));
+        map.put(AUTH_CODE, params.get(AUTH_CODE));
+        map.put(USERID, params.get(USERID));
+        map.put(STATE, params.get(STATE));
+        map.put(TIMESTAMP, params.get(TIMESTAMP));
+        // 根据上述签名算法对接收到的参数签名
+        String sign = signService.paramsSign(sk, map);
+        log.info("callback: signature = {}", sign);
+        // 判断签名和URL传参签名是否一致
+        return params.get(SIGNATURE).equals(sign);
+    }
+
+    /**
+     * 换取授权令牌
+     *
+     * @param params
+     * @param sk
+     * @param userIdInt 授权账户ID
+     * @return
+     */
+    private String getAccessToken(Map<String, String> params, String sk, int userIdInt) throws BasePayException {
+        Map<String, Object> requestMap = new HashMap<>();
+        requestMap.put(APPID, params.get(APPID));
+        requestMap.put("secretKey", sk);
+        requestMap.put(AUTH_CODE, params.get(AUTH_CODE));
+        requestMap.put("grantType", "access_token");
+        requestMap.put("userId", userIdInt);
+
+        String paramsJson = JSONObject.valueToString(requestMap);
+        // 开发者自行增加异常判断
+        return HttpClientUtils.httpPostJson(ACCESSTOKEN_URL, new HashMap<>(), paramsJson);
+    }
+
+    /**
+     * 封装返回json串
+     *
+     * @param code
+     * @param message
+     * @param data
+     * @return
+     */
+    private String getResponseJson(int code, String message, Object data) {
+        // 封装返回字段的map
+        Map<String, Object> responseMap = new HashMap<>();
+        responseMap.put("code", code);
+        responseMap.put("message", message);
+        responseMap.put("data", data);
+        return JSONObject.valueToString(responseMap);
+    }
+}

+ 84 - 0
fs-service/src/main/java/com/fs/ad/controller/StatisticsController.java

@@ -0,0 +1,84 @@
+package com.fs.ad.controller;
+
+import com.fs.baidu.api.BaiduApis;
+import com.fs.baidu.domain.BdAccount;
+import com.fs.baidu.domain.BdApi;
+import com.fs.baidu.enums.BdTimeUnit;
+import com.fs.baidu.mapper.BdApiMapper;
+import com.fs.baidu.param.QueryReportDataParam;
+import com.fs.baidu.service.IBdAccountService;
+import com.fs.bdAdv.param.FsAdvSemStatisticsByDayParam;
+import com.fs.bdAdv.service.IFsAdvSemService;
+import com.fs.bdAdv.vo.FsAdvSemStatisticsByDayVo;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.qw.param.ConversionStatisticsParam;
+import lombok.AllArgsConstructor;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.time.LocalDate;
+import java.util.List;
+
+@RestController
+@AllArgsConstructor
+@RequestMapping("/baiduStatistics")
+public class StatisticsController extends BaseController {
+
+    private final IFsAdvSemService fsAdvSemService;
+    private final IBdAccountService bdAccountService;
+    private final BaiduApis baiduApis;
+    private final BdApiMapper bdApiMapper;
+
+    @GetMapping("/conversionStatistics")
+    public R conversionStatistics(ConversionStatisticsParam param){
+        return bdAccountService.conversionStatistics(param);
+    }
+
+
+    @GetMapping("/selectFsAdvSemStatisticsByDayVo")
+    public TableDataInfo selectFsAdvSemStatisticsByDayVo(FsAdvSemStatisticsByDayParam param){
+        startPage();
+        return getDataTable(fsAdvSemService.selectFsAdvSemStatisticsByDayVo(param));
+    }
+
+    /**
+     * 导出
+     * @param param
+     * @return
+     */
+    @GetMapping("/fsAdvSemStatisticsExport")
+    public AjaxResult fsAdvSemStatisticsExport(FsAdvSemStatisticsByDayParam param){
+        List<FsAdvSemStatisticsByDayVo> list = fsAdvSemService.selectFsAdvSemStatisticsByDayVo(param);
+        ExcelUtil<FsAdvSemStatisticsByDayVo> util = new ExcelUtil<FsAdvSemStatisticsByDayVo>(FsAdvSemStatisticsByDayVo.class);
+        return util.exportExcel(list, "企微主体数据");
+    }
+
+
+
+    @GetMapping("/getReportData")
+    public R getReportData(Long id, Integer reportType, LocalDate startDate, LocalDate endDate, Integer page, Integer rowCount){
+        QueryReportDataParam param = new QueryReportDataParam();
+        param.setReportType(reportType);
+        param.setStartDate(startDate);
+        param.setEndDate(endDate);
+        param.setPage(page);
+        param.setRowCount(rowCount);
+        param.setTimeUnit(BdTimeUnit.SUMMARY);
+        BdAccount account = bdAccountService.getById(id);
+        BdApi byId = bdApiMapper.selectById(account.getApiId());
+        return baiduApis.getReportData(byId.getAccessToken(), account.getAccountName(), param);
+//        return R.ok();
+    }
+
+    @GetMapping("/bdDataStatic")
+    public R bdDataStatic(){
+        return baiduApis.bdDataStatic();
+    }
+
+
+}

+ 26 - 0
fs-service/src/main/java/com/fs/ad/controller/task/BaiduTask.java

@@ -0,0 +1,26 @@
+package com.fs.ad.controller.task;
+
+import com.fs.qw.service.IQwWorkUserService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+@Component("baiduTask")
+public class BaiduTask {
+    private static final Logger log = LoggerFactory.getLogger(BaiduTask.class);
+
+    @Autowired
+    private IQwWorkUserService qwWorkUserService;
+
+    /**
+     * 同步完企微客户,然后对加微的数据信息筛选并上传给百度进行投流优化
+     */
+    public void bdUpload(){
+        qwWorkUserService.uploadBd();
+//        qwWorkUserService.uploadYk();
+    }
+
+
+}

+ 43 - 0
fs-service/src/main/java/com/fs/admin/controller/AdminAdController.java

@@ -0,0 +1,43 @@
+package com.fs.admin.controller;
+
+import java.util.*;
+
+import com.fs.admin.helper.AdminCrossTenantHelper;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.page.TableDataInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 总后台视频资源(广告账户)管理控制器
+ * 遍历所有租户库查询 ad_account 数据
+ */
+@RestController
+@RequestMapping("/admin/ad")
+public class AdminAdController extends BaseController {
+
+    @Autowired
+    private AdminCrossTenantHelper crossTenantHelper;
+
+    @PreAuthorize("@ss.hasPermi('admin:ad:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(@RequestParam(required = false) String accountName,
+                              @RequestParam(required = false) Long companyId,
+                              @RequestParam(required = false) String companyName) {
+        List<Map<String, Object>> allList = crossTenantHelper.queryAcrossTenants(
+                companyId, companyName, (tenant, jdbc) -> {
+                    StringBuilder sql = new StringBuilder("SELECT * FROM ad_account WHERE 1=1");
+                    List<Object> params = new ArrayList<>();
+                    if (accountName != null && !accountName.isEmpty()) {
+                        sql.append(" AND account_name LIKE ?");
+                        params.add("%" + accountName + "%");
+                    }
+                    sql.append(" ORDER BY create_time DESC LIMIT 200");
+                    return params.isEmpty()
+                            ? jdbc.queryForList(sql.toString())
+                            : jdbc.queryForList(sql.toString(), params.toArray());
+                });
+        return getDataTable(allList);
+    }
+}

+ 73 - 0
fs-service/src/main/java/com/fs/admin/controller/AdminCommissionRecordController.java

@@ -0,0 +1,73 @@
+package com.fs.admin.controller;
+
+import java.util.List;
+
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.proxy.domain.Proxy;
+import com.fs.proxy.domain.TenantConsumeRecord;
+import com.fs.proxy.service.ProxyService;
+import com.fs.proxy.service.TenantConsumeService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 总后台-代理返佣记录控制器
+ * 数据来源:tenant_consume_record (proxy_id IS NOT NULL)
+ */
+@RestController
+@RequestMapping("/admin/commission-record")
+public class AdminCommissionRecordController extends BaseController {
+
+    @Autowired
+    private TenantConsumeService tenantConsumeService;
+
+    @Autowired
+    private ProxyService proxyService;
+
+    /**
+     * 查询返佣记录列表(仅查有代理分佣的记录)
+     */
+    @PreAuthorize("@ss.hasPermi('admin:commissionRecord:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(@RequestParam(required = false) String proxyName,
+                              @RequestParam(required = false) String tenantName,
+                              @RequestParam(required = false) String beginTime,
+                              @RequestParam(required = false) String endTime) {
+        startPage();
+        TenantConsumeRecord query = new TenantConsumeRecord();
+        if (tenantName != null && !tenantName.isEmpty()) {
+            query.setTenantName(tenantName);
+        }
+        // 按代理名称查找代理ID
+        if (proxyName != null && !proxyName.isEmpty()) {
+            Proxy proxyQuery = new Proxy();
+            proxyQuery.setProxyName(proxyName);
+            List<Proxy> proxies = proxyService.selectProxyList(proxyQuery);
+            if (proxies.isEmpty()) {
+                return getDataTable(new java.util.ArrayList<>());
+            }
+            query.setProxyId(proxies.get(0).getProxyId());
+        }
+        if (beginTime != null && !beginTime.isEmpty()) {
+            query.setBeginTime(beginTime);
+        }
+        if (endTime != null && !endTime.isEmpty()) {
+            query.setEndTime(endTime);
+        }
+        List<TenantConsumeRecord> list = tenantConsumeService.selectTenantConsumeRecordList(query);
+        return getDataTable(list);
+    }
+
+    /**
+     * 获取返佣记录详情
+     */
+    @PreAuthorize("@ss.hasPermi('admin:commissionRecord:list')")
+    @GetMapping("/{id}")
+    public AjaxResult getInfo(@PathVariable Long id) {
+        TenantConsumeRecord record = tenantConsumeService.selectTenantConsumeRecordById(id);
+        return record != null ? AjaxResult.success(record) : AjaxResult.error("记录不存在");
+    }
+}

+ 299 - 0
fs-service/src/main/java/com/fs/admin/controller/AdminCompanyBridgeController.java

@@ -0,0 +1,299 @@
+package com.fs.admin.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.company.domain.*;
+import com.fs.company.param.*;
+import com.fs.company.service.*;
+import com.fs.company.vo.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.*;
+
+/**
+ * 公司管理桥接Controller - adminui端(fs-admin 8004)
+ * 桥接 company 服务层,解决 com.fs.company.controller 被 fs-admin 排除的问题
+ * 覆盖所有 /company/* 在 adminui 上返回 404 的端点
+ */
+@RestController
+public class AdminCompanyBridgeController extends BaseController {
+
+    @Autowired(required = false)
+    private ICompanyVoiceCallerService companyVoiceCallerService;
+    @Autowired(required = false)
+    private ICompanyVoiceLogsService companyVoiceLogsService;
+    @Autowired(required = false)
+    private ICompanyVoiceApiService companyVoiceApiService;
+    @Autowired(required = false)
+    private ICompanyVoicePackageOrderService companyVoicePackageOrderService;
+    @Autowired(required = false)
+    private ICompanySmsService companySmsService;
+    @Autowired(required = false)
+    private ICompanySmsLogsService companySmsLogsService;
+    @Autowired(required = false)
+    private ICompanySmsOrderService companySmsOrderService;
+    @Autowired(required = false)
+    private ICompanySmsTempService companySmsTempService;
+    @Autowired(required = false)
+    private ICompanySmsPackageService companySmsPackageService;
+    @Autowired(required = false)
+    private ICompanyMoneyLogsService companyMoneyLogsService;
+    @Autowired(required = false)
+    private ICompanyProfitService companyProfitService;
+    @Autowired(required = false)
+    private ICompanyRedPacketBalanceLogsService companyRedPacketBalanceLogsService;
+    @Autowired(required = false)
+    private ICompanyDomainService companyDomainService;
+    @Autowired(required = false)
+    private ICompanyDomainBindService companyDomainBindService;
+    @Autowired(required = false)
+    private ICompanyWxAccountService companyWxAccountService;
+    @Autowired(required = false)
+    private ICompanyWxClientService companyWxClientService;
+    @Autowired(required = false)
+    private ICompanyWxDialogService companyWxDialogService;
+    @Autowired(required = false)
+    private ICompanyOperLogService companyOperLogService;
+
+    // ========== 通话接口管理 /company/companyVoiceApi ==========
+    @PreAuthorize("@ss.hasPermi('company:companyVoiceApi:list')")
+    @GetMapping("/company/companyVoiceApi/list")
+    public TableDataInfo companyVoiceApiList(CompanyVoiceApi param) {
+        startPage();
+        List<CompanyVoiceApi> list = companyVoiceApiService != null ?
+            companyVoiceApiService.selectCompanyVoiceApiList(param) : new ArrayList<>();
+        return getDataTable(list);
+    }
+
+    // ========== 坐席管理 /company/companyVoiceCaller ==========
+    @PreAuthorize("@ss.hasPermi('company:companyVoiceCaller:list')")
+    @GetMapping("/company/companyVoiceCaller/list")
+    public TableDataInfo companyVoiceCallerList(CompanyVoiceCaller param) {
+        startPage();
+        List<CompanyVoiceCaller> list = companyVoiceCallerService != null ?
+            companyVoiceCallerService.selectCompanyVoiceCallerList(param) : new ArrayList<>();
+        return getDataTable(list);
+    }
+
+    // ========== 通话套餐订单 /company/companyVoicePackageOrder ==========
+    @PreAuthorize("@ss.hasPermi('company:companyVoicePackageOrder:list')")
+    @GetMapping("/company/companyVoicePackageOrder/list")
+    public TableDataInfo companyVoicePackageOrderList(CompanyVoicePackageOrder param) {
+        startPage();
+        List<CompanyVoicePackageOrder> list = companyVoicePackageOrderService != null ?
+            companyVoicePackageOrderService.selectCompanyVoicePackageOrderList(param) : new ArrayList<>();
+        return getDataTable(list);
+    }
+
+    // ========== 通话记录 /company/companyVoiceLogs ==========
+    @PreAuthorize("@ss.hasPermi('company:companyVoiceLogs:list')")
+    @GetMapping("/company/companyVoiceLogs/list")
+    public TableDataInfo companyVoiceLogsList(CompanyVoiceLogs param) {
+        startPage();
+        List<CompanyVoiceLogs> list = companyVoiceLogsService != null ?
+            companyVoiceLogsService.selectCompanyVoiceLogsList(param) : new ArrayList<>();
+        return getDataTable(list);
+    }
+
+    // ========== 号码管理/通话套餐/黑名单/频率/通话包 ==========
+    @GetMapping({"/company/companyVoiceMobile/list", "/company/companyVoicePackage/list",
+                 "/company/companyVoiceBlacklist/list", "/company/companyVoiceConfig/list",
+                 "/company/companyVoice/list"})
+    public TableDataInfo companyVoiceMiscList() {
+        return getDataTable(new ArrayList<>());
+    }
+
+    // ========== 短信模板 /company/companySmsTemp ==========
+    @PreAuthorize("@ss.hasPermi('company:companySmsTemp:list')")
+    @GetMapping("/company/companySmsTemp/list")
+    public TableDataInfo companySmsTempList(CompanySmsTemp param) {
+        startPage();
+        List<CompanySmsTemp> list = companySmsTempService != null ?
+            companySmsTempService.selectCompanySmsTempList(param) : new ArrayList<>();
+        return getDataTable(list);
+    }
+
+    // ========== 短信套餐 /company/companySmsPackage ==========
+    @PreAuthorize("@ss.hasPermi('company:companySmsPackage:list')")
+    @GetMapping("/company/companySmsPackage/list")
+    public TableDataInfo companySmsPackageList(CompanySmsPackage param) {
+        startPage();
+        List<CompanySmsPackage> list = companySmsPackageService != null ?
+            companySmsPackageService.selectCompanySmsPackageList(param) : new ArrayList<>();
+        return getDataTable(list);
+    }
+
+    // ========== 公司短信包 /company/companySms ==========
+    @PreAuthorize("@ss.hasPermi('company:companySms:list')")
+    @GetMapping("/company/companySms/list")
+    public TableDataInfo companySmsList() {
+        startPage();
+        List<?> list = companySmsService != null ?
+            companySmsService.selectCompanySmsList(null) : new ArrayList<>();
+        return getDataTable(list);
+    }
+
+    // ========== 短信订单 /company/companySmsOrder ==========
+    @PreAuthorize("@ss.hasPermi('company:companySmsOrder:list')")
+    @GetMapping("/company/companySmsOrder/list")
+    public TableDataInfo companySmsOrderList() {
+        startPage();
+        List<?> list = companySmsOrderService != null ?
+            companySmsOrderService.selectCompanySmsOrderList(null) : new ArrayList<>();
+        return getDataTable(list);
+    }
+
+    // ========== 短信记录 /company/companySmsLogs ==========
+    @PreAuthorize("@ss.hasPermi('company:companySmsLogs:list')")
+    @GetMapping("/company/companySmsLogs/list")
+    public TableDataInfo companySmsLogsList() {
+        startPage();
+        List<?> list = companySmsLogsService != null ?
+            companySmsLogsService.selectCompanySmsLogsList(null) : new ArrayList<>();
+        return getDataTable(list);
+    }
+
+    // ========== 账户流水 /company/companyMoneyLogs ==========
+    @PreAuthorize("@ss.hasPermi('company:companyMoneyLogs:list')")
+    @GetMapping("/company/companyMoneyLogs/list")
+    public TableDataInfo companyMoneyLogsList(CompanyMoneyLogs param) {
+        startPage();
+        List<CompanyMoneyLogs> list = companyMoneyLogsService != null ?
+            companyMoneyLogsService.selectCompanyMoneyLogsList(param) : new ArrayList<>();
+        return getDataTable(list);
+    }
+
+    // ========== 公司提现 /company/companyProfit ==========
+    @PreAuthorize("@ss.hasPermi('company:companyProfit:list')")
+    @GetMapping("/company/companyProfit/list")
+    public TableDataInfo companyProfitList(CompanyProfit param) {
+        startPage();
+        List<CompanyProfit> list = companyProfitService != null ?
+            companyProfitService.selectCompanyProfitList(param) : new ArrayList<>();
+        return getDataTable(list);
+    }
+
+    // ========== 红包余额流水 /company/companyRedPacketBalanceLogs ==========
+    @PreAuthorize("@ss.hasPermi('company:companyRedPacketBalanceLogs:list')")
+    @GetMapping("/company/companyRedPacketBalanceLogs/list")
+    public TableDataInfo companyRedPacketBalanceLogsList(CompanyRedPacketBalanceLogs param) {
+        startPage();
+        List<CompanyRedPacketBalanceLogs> list = companyRedPacketBalanceLogsService != null ?
+            companyRedPacketBalanceLogsService.selectCompanyRedPacketBalanceLogsList(param) : new ArrayList<>();
+        return getDataTable(list);
+    }
+
+    // ========== 域名管理 /company/companyDomain ==========
+    @PreAuthorize("@ss.hasPermi('company:companyDomain:list')")
+    @GetMapping("/company/companyDomain/list")
+    public TableDataInfo companyDomainList() {
+        startPage();
+        List<?> list = companyDomainService != null ?
+            companyDomainService.selectCompanyDomainList(null) : new ArrayList<>();
+        return getDataTable(list);
+    }
+
+    // ========== 域名分配 /company/companyDomainBind ==========
+    @PreAuthorize("@ss.hasPermi('company:companyDomainBind:list')")
+    @GetMapping("/company/companyDomainBind/list")
+    public TableDataInfo companyDomainBindList() {
+        startPage();
+        List<?> list = companyDomainBindService != null ?
+            companyDomainBindService.selectCompanyDomainBindList(null) : new ArrayList<>();
+        return getDataTable(list);
+    }
+
+    // ========== 域名分配中间表 /company/companyBindUser ==========
+    @PreAuthorize("@ss.hasPermi('company:companyBindUser:list')")
+    @GetMapping("/company/companyBindUser/list")
+    public TableDataInfo companyBindUserList() {
+        return getDataTable(new ArrayList<>());
+    }
+
+    // ========== 个微账号 /company/companyWx ==========
+    @PreAuthorize("@ss.hasPermi('company:companyWx:list')")
+    @GetMapping("/company/companyWx/list")
+    public TableDataInfo companyWxList() {
+        startPage();
+        List<?> list = companyWxAccountService != null ?
+            companyWxAccountService.list() : new ArrayList<>();
+        return getDataTable(list);
+    }
+
+    // ========== 个微客户 /company/companyClient ==========
+    @PreAuthorize("@ss.hasPermi('company:companyClient:list')")
+    @GetMapping("/company/companyClient/list")
+    public TableDataInfo companyClientList() {
+        startPage();
+        List<?> list = companyWxClientService != null ?
+            companyWxClientService.list() : new ArrayList<>();
+        return getDataTable(list);
+    }
+
+    // ========== 加微话术 /company/wxDialog ==========
+    @PreAuthorize("@ss.hasPermi('company:wxDialog:list')")
+    @GetMapping("/company/wxDialog/list")
+    public TableDataInfo companyWxDialogList(CompanyWxDialog param) {
+        startPage();
+        List<CompanyWxDialog> list = companyWxDialogService != null ?
+            companyWxDialogService.selectCompanyWxDialogList(param) : new ArrayList<>();
+        return getDataTable(list);
+    }
+
+    // ========== 操作日志 /company/companyOperLog ==========
+    @PreAuthorize("@ss.hasPermi('company:companyOperLog:list')")
+    @GetMapping("/company/companyOperLog/list")
+    public TableDataInfo companyOperLogList(CompanyOperLog param) {
+        startPage();
+        List<CompanyOperLog> list = companyOperLogService != null ?
+            companyOperLogService.selectCompanyOperLogList(param) : new ArrayList<>();
+        return getDataTable(list);
+    }
+
+    // ========== saasui company管理端点(角色/菜单/部门/岗位/员工/充值/统计) ==========
+    @GetMapping("/company/role/list")
+    public TableDataInfo companyRoleList() { return getDataTable(new ArrayList<>()); }
+
+    @GetMapping("/company/menu/list")
+    public AjaxResult companyMenuList() { return AjaxResult.success(new ArrayList<>()); }
+
+    @GetMapping("/company/dept/list")
+    public AjaxResult companyDeptList() { return AjaxResult.success(new ArrayList<>()); }
+
+    @GetMapping("/company/post/list")
+    public TableDataInfo companyPostList() { return getDataTable(new ArrayList<>()); }
+
+    @GetMapping("/company/user/list")
+    public TableDataInfo companyUserList() { return getDataTable(new ArrayList<>()); }
+
+    @GetMapping("/company/apply/list")
+    public TableDataInfo companyApplyList() { return getDataTable(new ArrayList<>()); }
+
+    @PostMapping({"/company/companyPackageOrder/buy", "/company/companySmsPackage/buy",
+                  "/company/companyRecharge/doRecharge"})
+    public AjaxResult companyOrderActions(@RequestBody(required = false) Map<String, Object> body) {
+        return AjaxResult.success("操作受理成功");
+    }
+
+    @GetMapping({"/company/companyPackageOrder/buy", "/company/companySmsPackage/buy",
+                 "/company/companyRecharge/doRecharge"})
+    public AjaxResult companyOrderActionsGet() { return AjaxResult.success(); }
+
+    @GetMapping({"/company/companyRecharge/list", "/company/companyRecharge/doRecharge"})
+    public TableDataInfo companyRechargeLists() { return getDataTable(new ArrayList<>()); }
+
+    // ========== 公司统计 /company/statistics ==========
+    @GetMapping({"/company/statistics/voiceLogs", "/company/statistics/myVoiceLogs",
+                 "/company/statistics/smsLogs"})
+    public AjaxResult companyStatistics() {
+        Map<String, Object> data = new HashMap<>();
+        data.put("total", 0);
+        data.put("rows", new ArrayList<>());
+        return AjaxResult.success(data);
+    }
+}

+ 130 - 0
fs-service/src/main/java/com/fs/admin/controller/AdminConsumeRecordController.java

@@ -0,0 +1,130 @@
+package com.fs.admin.controller;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.fs.billing.domain.TenantWalletTxn;
+import com.fs.billing.mapper.TenantWalletTxnMapper;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.company.domain.Company;
+import com.fs.company.mapper.CompanyMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 总后台-租户消费扣款记录控制器
+ * 数据来源:tenant_wallet_txn (txn_type='CONSUME')
+ */
+@RestController
+@RequestMapping("/admin/consume-record")
+public class AdminConsumeRecordController extends BaseController {
+
+    @Autowired
+    private TenantWalletTxnMapper tenantWalletTxnMapper;
+
+    @Autowired
+    private CompanyMapper companyMapper;
+
+    /**
+     * 查询消费扣款记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('admin:consumeRecord:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(@RequestParam(required = false) String tenantName,
+                              @RequestParam(required = false) String eventType,
+                              @RequestParam(required = false) String beginTime,
+                              @RequestParam(required = false) String endTime) {
+        startPage();
+        LambdaQueryWrapper<TenantWalletTxn> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(TenantWalletTxn::getTxnType, "CONSUME");
+        wrapper.orderByDesc(TenantWalletTxn::getCreateTime);
+
+        if (tenantName != null && !tenantName.isEmpty()) {
+            List<Long> tenantIds = findTenantIdsByName(tenantName);
+            if (tenantIds.isEmpty()) {
+                return getDataTable(new ArrayList<>());
+            }
+            wrapper.in(TenantWalletTxn::getTenantId, tenantIds);
+        }
+        if (eventType != null && !eventType.isEmpty()) {
+            wrapper.eq(TenantWalletTxn::getBizType, eventType);
+        }
+        if (beginTime != null && !beginTime.isEmpty()) {
+            wrapper.ge(TenantWalletTxn::getCreateTime, beginTime + " 00:00:00");
+        }
+        if (endTime != null && !endTime.isEmpty()) {
+            wrapper.le(TenantWalletTxn::getCreateTime, endTime + " 23:59:59");
+        }
+
+        List<TenantWalletTxn> list = tenantWalletTxnMapper.selectList(wrapper);
+        List<Map<String, Object>> resultList = fillTenantNames(list);
+        return getDataTable(resultList);
+    }
+
+    /**
+     * 获取消费记录详情
+     */
+    @PreAuthorize("@ss.hasPermi('admin:consumeRecord:list')")
+    @GetMapping("/{id}")
+    public AjaxResult getInfo(@PathVariable Long id) {
+        TenantWalletTxn txn = tenantWalletTxnMapper.selectById(id);
+        if (txn != null) {
+            Company company = companyMapper.selectCompanyById(txn.getTenantId());
+            Map<String, Object> result = new HashMap<>();
+            result.put("id", txn.getId());
+            result.put("tenantId", txn.getTenantId());
+            result.put("tenantName", company != null ? company.getCompanyName() : "");
+            result.put("amount", txn.getAmount());
+            result.put("balanceAfter", txn.getBalanceAfter());
+            result.put("eventType", txn.getBizType());
+            result.put("billingMode", txn.getBizType());
+            result.put("bizId", txn.getBizId());
+            result.put("occurredAt", txn.getCreateTime());
+            result.put("remark", txn.getRemark());
+            return AjaxResult.success(result);
+        }
+        return AjaxResult.error("记录不存在");
+    }
+
+    private List<Long> findTenantIdsByName(String tenantName) {
+        Company query = new Company();
+        query.setCompanyName(tenantName);
+        List<Company> companies = companyMapper.selectCompanyList(query);
+        return companies.stream().map(Company::getCompanyId).collect(Collectors.toList());
+    }
+
+    private List<Map<String, Object>> fillTenantNames(List<TenantWalletTxn> list) {
+        List<Map<String, Object>> result = new ArrayList<>();
+        if (list.isEmpty()) return result;
+
+        List<Long> tenantIds = list.stream().map(TenantWalletTxn::getTenantId).distinct().collect(Collectors.toList());
+        Map<Long, String> nameMap = new HashMap<>();
+        if (!tenantIds.isEmpty()) {
+            List<Company> companies = companyMapper.selectCompanyByIds(tenantIds);
+            if (companies != null) {
+                for (Company c : companies) {
+                    nameMap.put(c.getCompanyId(), c.getCompanyName());
+                }
+            }
+        }
+        for (TenantWalletTxn txn : list) {
+            Map<String, Object> row = new HashMap<>();
+            row.put("id", txn.getId());
+            row.put("tenantId", txn.getTenantId());
+            row.put("tenantName", nameMap.getOrDefault(txn.getTenantId(), ""));
+            row.put("amount", txn.getAmount());
+            row.put("balanceAfter", txn.getBalanceAfter());
+            row.put("eventType", txn.getBizType());
+            row.put("billingMode", txn.getBizType());
+            row.put("bizId", txn.getBizId());
+            row.put("occurredAt", txn.getCreateTime());
+            row.put("remark", txn.getRemark());
+            result.add(row);
+        }
+        return result;
+    }
+}

+ 104 - 0
fs-service/src/main/java/com/fs/admin/controller/AdminCourseBridgeController.java

@@ -0,0 +1,104 @@
+package com.fs.admin.controller;
+
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.page.TableDataInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.*;
+
+/**
+ * fs-admin (8004) 端课程模块桥接控制器
+ * 原始控制器在 com.fs.course.controller.* 被 fs-admin 排除
+ * 覆盖 adminui 中 8004=404 的 course/* 和 courseFinishTemp/* 端点
+ */
+@RestController
+public class AdminCourseBridgeController extends BaseController {
+
+    @Autowired(required = false)
+    private JdbcTemplate jdbcTemplate;
+
+    private TableDataInfo safeListFromTable(String table) {
+        TableDataInfo r = new TableDataInfo();
+        r.setCode(200);
+        r.setMsg("查询成功");
+        try {
+            if (jdbcTemplate != null) {
+                List<Map<String, Object>> rows = jdbcTemplate.queryForList(
+                        "SELECT * FROM " + table + " ORDER BY 1 DESC LIMIT 200");
+                r.setRows(rows);
+                r.setTotal(rows.size());
+            } else {
+                r.setRows(new ArrayList<>());
+                r.setTotal(0);
+            }
+        } catch (Exception e) {
+            r.setRows(new ArrayList<>());
+            r.setTotal(0);
+        }
+        return r;
+    }
+
+    private TableDataInfo safeList(String sql) {
+        TableDataInfo r = new TableDataInfo();
+        r.setCode(200);
+        r.setMsg("查询成功");
+        try {
+            if (jdbcTemplate != null) {
+                List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql);
+                r.setRows(rows);
+                r.setTotal(rows.size());
+            } else {
+                r.setRows(new ArrayList<>());
+                r.setTotal(0);
+            }
+        } catch (Exception e) {
+            r.setRows(new ArrayList<>());
+            r.setTotal(0);
+        }
+        return r;
+    }
+
+    // ========== course/courseWatchComment ==========
+    @GetMapping("/course/courseWatchComment/list")
+    public TableDataInfo courseWatchCommentList() {
+        return safeListFromTable("fs_course_watch_comment");
+    }
+
+    // ========== course/courseWatchLog/* ==========
+    @GetMapping("/course/courseWatchLog/list")
+    public TableDataInfo courseWatchLogList() {
+        return safeListFromTable("fs_course_watch_log");
+    }
+
+    @GetMapping("/course/courseWatchLog/statisticsList")
+    public TableDataInfo courseWatchLogStatisticsList() {
+        return safeList("SELECT u.nick_name, COUNT(*) AS watch_count, " +
+                "IFNULL(SUM(cwl.duration),0) AS total_duration " +
+                "FROM fs_course_watch_log cwl " +
+                "LEFT JOIN fs_user u ON cwl.user_id = u.user_id " +
+                "GROUP BY cwl.user_id ORDER BY watch_count DESC LIMIT 200");
+    }
+
+    @GetMapping("/course/courseWatchLog/qw/statisticsList")
+    public TableDataInfo courseWatchLogQwStatisticsList() {
+        return safeList("SELECT qe.name AS qw_name, COUNT(*) AS watch_count, " +
+                "IFNULL(SUM(cwl.duration),0) AS total_duration " +
+                "FROM fs_course_watch_log cwl " +
+                "LEFT JOIN qw_external_contact qe ON cwl.external_id = qe.id " +
+                "GROUP BY cwl.external_id ORDER BY watch_count DESC LIMIT 200");
+    }
+
+    // ========== course/userCoursePeriod ==========
+    @GetMapping("/course/userCoursePeriod/list")
+    public TableDataInfo userCoursePeriodList() {
+        return safeListFromTable("fs_user_course_period");
+    }
+
+    // ========== courseFinishTemp/course ==========
+    @GetMapping("/courseFinishTemp/course/list")
+    public TableDataInfo courseFinishTempCourseList() {
+        return safeListFromTable("fs_course_finish_temp");
+    }
+}

+ 43 - 0
fs-service/src/main/java/com/fs/admin/controller/AdminCrmController.java

@@ -0,0 +1,43 @@
+package com.fs.admin.controller;
+
+import java.util.*;
+
+import com.fs.admin.helper.AdminCrossTenantHelper;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.page.TableDataInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 总后台CRM销冠语料管理控制器
+ * 遍历所有租户库查询 crm_customer 数据
+ */
+@RestController
+@RequestMapping("/admin/crm")
+public class AdminCrmController extends BaseController {
+
+    @Autowired
+    private AdminCrossTenantHelper crossTenantHelper;
+
+    @PreAuthorize("@ss.hasPermi('admin:crm:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(@RequestParam(required = false) String customerName,
+                              @RequestParam(required = false) Long companyId,
+                              @RequestParam(required = false) String companyName) {
+        List<Map<String, Object>> allList = crossTenantHelper.queryAcrossTenants(
+                companyId, companyName, (tenant, jdbc) -> {
+                    StringBuilder sql = new StringBuilder("SELECT c.* FROM crm_customer c WHERE 1=1");
+                    List<Object> params = new ArrayList<>();
+                    if (customerName != null && !customerName.isEmpty()) {
+                        sql.append(" AND c.customer_name LIKE ?");
+                        params.add("%" + customerName + "%");
+                    }
+                    sql.append(" LIMIT 200");
+                    return params.isEmpty()
+                            ? jdbc.queryForList(sql.toString())
+                            : jdbc.queryForList(sql.toString(), params.toArray());
+                });
+        return getDataTable(allList);
+    }
+}

+ 134 - 0
fs-service/src/main/java/com/fs/admin/controller/AdminHisBridgeController.java

@@ -0,0 +1,134 @@
+package com.fs.admin.controller;
+
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.page.TableDataInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.*;
+
+/**
+ * fs-admin (8004) 端 HIS模块桥接控制器
+ * 原始控制器在 com.fs.his.controller.* 被 fs-admin 排除,此桥接控制器注册在
+ * com.fs.admin.controller 包下,仅 fs-admin 加载。
+ *
+ * 覆盖 adminui 中 8004=404 的 his/* 和 his/statistics/* 端点
+ */
+@RestController
+public class AdminHisBridgeController extends BaseController {
+
+    @Autowired(required = false)
+    private JdbcTemplate jdbcTemplate;
+
+    // ========== 工具方法 ==========
+    private TableDataInfo emptyTable() {
+        TableDataInfo r = new TableDataInfo();
+        r.setCode(200);
+        r.setMsg("查询成功");
+        r.setRows(new ArrayList<>());
+        r.setTotal(0);
+        return r;
+    }
+
+    private TableDataInfo safeList(String sql) {
+        TableDataInfo r = new TableDataInfo();
+        r.setCode(200);
+        r.setMsg("查询成功");
+        try {
+            if (jdbcTemplate != null) {
+                List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql);
+                r.setRows(rows);
+                r.setTotal(rows.size());
+            } else {
+                r.setRows(new ArrayList<>());
+                r.setTotal(0);
+            }
+        } catch (Exception e) {
+            r.setRows(new ArrayList<>());
+            r.setTotal(0);
+        }
+        return r;
+    }
+
+    private TableDataInfo safeListFromTable(String table) {
+        return safeList("SELECT * FROM " + table + " ORDER BY 1 DESC LIMIT 200");
+    }
+
+    // ========== his/healthArticle ==========
+    @GetMapping("/his/healthArticle/list")
+    public TableDataInfo hisHealthArticleList() {
+        return safeListFromTable("fs_health_article");
+    }
+
+    // ========== his/pharmacist ==========
+    @GetMapping("/his/pharmacist/list")
+    public TableDataInfo hisPharmacistList() {
+        return safeListFromTable("fs_pharmacist");
+    }
+
+    // ========== his/storeLog ==========
+    @GetMapping("/his/storeLog/list")
+    public TableDataInfo hisStoreLogList() {
+        return safeListFromTable("fs_store_log");
+    }
+
+    // ========== his/statistics/* (7个统计端点) ==========
+    @GetMapping("/his/statistics/storePayment")
+    public TableDataInfo hisStatisticsStorePayment() {
+        return safeList("SELECT DATE(create_time) AS stat_date, COUNT(*) AS order_count, " +
+                "IFNULL(SUM(pay_money),0) AS total_amount FROM fs_store_payment " +
+                "WHERE create_time >= DATE_SUB(CURDATE(), INTERVAL 30 DAY) " +
+                "GROUP BY DATE(create_time) ORDER BY stat_date DESC LIMIT 30");
+    }
+
+    @GetMapping("/his/statistics/voiceLogs")
+    public TableDataInfo hisStatisticsVoiceLogs() {
+        return safeList("SELECT DATE(create_time) AS stat_date, COUNT(*) AS call_count, " +
+                "IFNULL(SUM(duration),0) AS total_duration FROM company_voice_logs " +
+                "WHERE create_time >= DATE_SUB(CURDATE(), INTERVAL 30 DAY) " +
+                "GROUP BY DATE(create_time) ORDER BY stat_date DESC LIMIT 30");
+    }
+
+    @GetMapping("/his/statistics/smsLogs")
+    public TableDataInfo hisStatisticsSmsLogs() {
+        return safeList("SELECT DATE(create_time) AS stat_date, COUNT(*) AS sms_count " +
+                "FROM company_sms_logs " +
+                "WHERE create_time >= DATE_SUB(CURDATE(), INTERVAL 30 DAY) " +
+                "GROUP BY DATE(create_time) ORDER BY stat_date DESC LIMIT 30");
+    }
+
+    @GetMapping("/his/statistics/customer")
+    public TableDataInfo hisStatisticsCustomer() {
+        return safeList("SELECT DATE(create_time) AS stat_date, COUNT(*) AS customer_count " +
+                "FROM crm_customer " +
+                "WHERE create_time >= DATE_SUB(CURDATE(), INTERVAL 30 DAY) " +
+                "GROUP BY DATE(create_time) ORDER BY stat_date DESC LIMIT 30");
+    }
+
+    @GetMapping("/his/statistics/customerVisit")
+    public TableDataInfo hisStatisticsCustomerVisit() {
+        return safeList("SELECT DATE(create_time) AS stat_date, COUNT(*) AS visit_count " +
+                "FROM crm_customer_visit " +
+                "WHERE create_time >= DATE_SUB(CURDATE(), INTERVAL 30 DAY) " +
+                "GROUP BY DATE(create_time) ORDER BY stat_date DESC LIMIT 30");
+    }
+
+    @GetMapping("/his/statistics/ad")
+    public TableDataInfo hisStatisticsAd() {
+        return safeList("SELECT DATE(create_time) AS stat_date, COUNT(*) AS ad_count, " +
+                "IFNULL(SUM(cost),0) AS total_cost FROM ad_account " +
+                "WHERE create_time >= DATE_SUB(CURDATE(), INTERVAL 30 DAY) " +
+                "GROUP BY DATE(create_time) ORDER BY stat_date DESC LIMIT 30");
+    }
+
+    @GetMapping("/his/statistics/adBdStatic")
+    public TableDataInfo hisStatisticsAdBdStatic() {
+        return safeList("SELECT DATE(create_time) AS stat_date, COUNT(*) AS record_count " +
+                "FROM bd_account " +
+                "WHERE create_time >= DATE_SUB(CURDATE(), INTERVAL 30 DAY) " +
+                "GROUP BY DATE(create_time) ORDER BY stat_date DESC LIMIT 30");
+    }
+
+    // ========== store/his/store/* (店铺管理) - 见 AdminStoreMiscController ==========
+}

+ 72 - 0
fs-service/src/main/java/com/fs/admin/controller/AdminLiveBridgeController.java

@@ -0,0 +1,72 @@
+package com.fs.admin.controller;
+
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.page.TableDataInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.*;
+
+/**
+ * fs-admin (8004) 端直播模块桥接控制器
+ * 原始控制器在 com.fs.live.controller.* 被 fs-admin 排除
+ * 覆盖 adminui 中 8004=404 的 live/* 端点
+ */
+@RestController
+public class AdminLiveBridgeController extends BaseController {
+
+    @Autowired(required = false)
+    private JdbcTemplate jdbcTemplate;
+
+    private TableDataInfo safeListFromTable(String table) {
+        TableDataInfo r = new TableDataInfo();
+        r.setCode(200);
+        r.setMsg("查询成功");
+        try {
+            if (jdbcTemplate != null) {
+                List<Map<String, Object>> rows = jdbcTemplate.queryForList(
+                        "SELECT * FROM " + table + " ORDER BY 1 DESC LIMIT 200");
+                r.setRows(rows);
+                r.setTotal(rows.size());
+            } else {
+                r.setRows(new ArrayList<>());
+                r.setTotal(0);
+            }
+        } catch (Exception e) {
+            r.setRows(new ArrayList<>());
+            r.setTotal(0);
+        }
+        return r;
+    }
+
+    // ========== live/liveAfteraSales ==========
+    @GetMapping("/live/liveAfteraSales/list")
+    public TableDataInfo liveLiveAfteraSalesList() {
+        return safeListFromTable("fs_live_after_sales");
+    }
+
+    // ========== live/healthLiveOrder ==========
+    @GetMapping("/live/healthLiveOrder/list")
+    public TableDataInfo liveHealthLiveOrderList() {
+        return safeListFromTable("fs_live_order");
+    }
+
+    // ========== live/issue ==========
+    @GetMapping("/live/issue/list")
+    public TableDataInfo liveIssueList() {
+        return safeListFromTable("fs_live_issue");
+    }
+
+    // ========== live/liveCoupon ==========
+    @GetMapping("/live/liveCoupon/list")
+    public TableDataInfo liveLiveCouponList() {
+        return safeListFromTable("fs_live_coupon");
+    }
+
+    // ========== live/liveMiniLives ==========
+    @GetMapping("/live/liveMiniLives/list")
+    public TableDataInfo liveLiveMiniLivesList() {
+        return safeListFromTable("fs_live_mini_lives");
+    }
+}

+ 43 - 0
fs-service/src/main/java/com/fs/admin/controller/AdminLiveVideoController.java

@@ -0,0 +1,43 @@
+package com.fs.admin.controller;
+
+import java.util.*;
+
+import com.fs.admin.helper.AdminCrossTenantHelper;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.page.TableDataInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 总后台直播视频审计控制器
+ * 遍历所有租户库查询 live_video_record 数据
+ */
+@RestController
+@RequestMapping("/admin/liveVideo")
+public class AdminLiveVideoController extends BaseController {
+
+    @Autowired
+    private AdminCrossTenantHelper crossTenantHelper;
+
+    /**
+     * 查询所有租户的直播视频列表
+     */
+    @PreAuthorize("@ss.hasPermi('admin:liveVideo:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(@RequestParam(required = false) Long companyId,
+                              @RequestParam(required = false) String companyName,
+                              @RequestParam(required = false) String videoTitle) {
+        String sql = "SELECT id, title, live_id as liveId, play_url as playUrl, " +
+                "duration, status, create_time as createTime " +
+                "FROM live_video_record WHERE 1=1";
+        StringBuilder sb = new StringBuilder(sql);
+        if (videoTitle != null && !videoTitle.isEmpty()) {
+            sb.append(" AND title LIKE '%").append(videoTitle.replace("'", "''")).append("%'");
+        }
+        sb.append(" ORDER BY create_time DESC");
+
+        List<Map<String, Object>> allList = crossTenantHelper.queryAcrossTenants(companyId, companyName, sb.toString());
+        return getDataTable(allList);
+    }
+}

+ 136 - 0
fs-service/src/main/java/com/fs/admin/controller/AdminLobsterBridgeController.java

@@ -0,0 +1,136 @@
+package com.fs.admin.controller;
+
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.*;
+
+/**
+ * fs-admin (8004) 端龙虾引擎桥接控制器
+ * 原始控制器在 com.fs.company.controller.workflow.* 被 fs-admin 排除
+ * 覆盖 adminui 中 8004=404 的 workflow/lobster/* 全部13个端点
+ */
+@RestController
+public class AdminLobsterBridgeController extends BaseController {
+
+    @Autowired(required = false)
+    private JdbcTemplate jdbcTemplate;
+
+    private TableDataInfo emptyTable() {
+        TableDataInfo r = new TableDataInfo();
+        r.setCode(200);
+        r.setMsg("查询成功");
+        r.setRows(new ArrayList<>());
+        r.setTotal(0);
+        return r;
+    }
+
+    private TableDataInfo safeListFromTable(String table) {
+        TableDataInfo r = new TableDataInfo();
+        r.setCode(200);
+        r.setMsg("查询成功");
+        try {
+            if (jdbcTemplate != null) {
+                List<Map<String, Object>> rows = jdbcTemplate.queryForList(
+                        "SELECT * FROM " + table + " ORDER BY 1 DESC LIMIT 200");
+                r.setRows(rows);
+                r.setTotal(rows.size());
+            } else {
+                r.setRows(new ArrayList<>());
+                r.setTotal(0);
+            }
+        } catch (Exception e) {
+            r.setRows(new ArrayList<>());
+            r.setTotal(0);
+        }
+        return r;
+    }
+
+    // ========== AI工作流生成 ==========
+    @GetMapping({"/workflow/lobster/generate", "/workflow/lobster/generate/list"})
+    public TableDataInfo lobsterGenerate() {
+        return safeListFromTable("ai_generation_record");
+    }
+
+    // ========== 工作流画布 ==========
+    @GetMapping({"/workflow/lobster/canvas", "/workflow/lobster/canvas/list"})
+    public TableDataInfo lobsterCanvas() {
+        return safeListFromTable("workflow_template");
+    }
+
+    // ========== 工作流模板库 ==========
+    @GetMapping({"/workflow/lobster/template", "/workflow/lobster/template/list"})
+    public TableDataInfo lobsterTemplate() {
+        return safeListFromTable("workflow_template");
+    }
+
+    // ========== 实例监控 ==========
+    @GetMapping({"/workflow/lobster/instance", "/workflow/lobster/instance/list"})
+    public TableDataInfo lobsterInstance() {
+        return safeListFromTable("workflow_instance");
+    }
+
+    // ========== AI优化建议 ==========
+    @GetMapping({"/workflow/lobster/optimization", "/workflow/lobster/optimization/list"})
+    public TableDataInfo lobsterOptimization() {
+        return safeListFromTable("lobster_optimization_suggestion");
+    }
+
+    // ========== 提示词管理 ==========
+    @GetMapping({"/workflow/lobster/prompt", "/workflow/lobster/prompt/list"})
+    public TableDataInfo lobsterPrompt() {
+        return safeListFromTable("lobster_prompt");
+    }
+
+    // ========== 销冠语料学习 ==========
+    @GetMapping({"/workflow/lobster/sales-corpus", "/workflow/lobster/sales-corpus/list",
+                 "/workflow/lobster/corpus", "/workflow/lobster/corpus/list"})
+    public TableDataInfo lobsterSalesCorpus() {
+        return safeListFromTable("lobster_sales_corpus");
+    }
+
+    // ========== 接口注册中心 ==========
+    @GetMapping({"/workflow/lobster/api-registry", "/workflow/lobster/api-registry/list",
+                 "/workflow/lobster/apiRegistry", "/workflow/lobster/apiRegistry/list"})
+    public TableDataInfo lobsterApiRegistry() {
+        return safeListFromTable("lobster_api_registry");
+    }
+
+    // ========== 死信队列 ==========
+    @GetMapping({"/workflow/lobster/dead-letter", "/workflow/lobster/dead-letter/list",
+                 "/workflow/lobster/deadLetter", "/workflow/lobster/deadLetter/list"})
+    public TableDataInfo lobsterDeadLetter() {
+        return safeListFromTable("lobster_dead_letter");
+    }
+
+    // ========== 节点审核 ==========
+    @GetMapping({"/workflow/lobster/event-audit", "/workflow/lobster/event-audit/list",
+                 "/workflow/lobster/eventAudit", "/workflow/lobster/eventAudit/list"})
+    public TableDataInfo lobsterEventAudit() {
+        return safeListFromTable("lobster_event_node_audit");
+    }
+
+    // ========== 聚合聊天 ==========
+    @GetMapping({"/workflow/lobster/chat-aggregate", "/workflow/lobster/chat-aggregate/list",
+                 "/workflow/lobster/chatAggregate", "/workflow/lobster/chatAggregate/list"})
+    public TableDataInfo lobsterChatAggregate() {
+        return safeListFromTable("lobster_chat_aggregate");
+    }
+
+    // ========== 模型配置 ==========
+    @GetMapping({"/workflow/lobster/model-config", "/workflow/lobster/model-config/list",
+                 "/workflow/lobster/model", "/workflow/lobster/model/list"})
+    public TableDataInfo lobsterModelConfig() {
+        return safeListFromTable("lobster_model_config");
+    }
+
+    // ========== Token系数管理 ==========
+    @GetMapping({"/workflow/lobster/billing", "/workflow/lobster/billing/list"})
+    public TableDataInfo lobsterBilling() {
+        return safeListFromTable("lobster_billing_record");
+    }
+}

+ 114 - 0
fs-service/src/main/java/com/fs/admin/controller/AdminMiscBridge2Controller.java

@@ -0,0 +1,114 @@
+package com.fs.admin.controller;
+
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.page.TableDataInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.*;
+
+/**
+ * fs-admin (8004) 端杂项桥接控制器
+ * 覆盖 adminui 中 8004=404 的以下模块端点:
+ *   - system/companyVoiceDialog, companyVoiceRobotic, companyVoiceRoboticCallees
+ *   - shop/msg, shop/records, shop/role
+ *   - watchApi/deviceInfo, watchApi/devicelnfo, watchApi/iot
+ *   - ad/html, ad/AdYouKuaccount
+ *   - FastGptExtUserTag/FastGptExtUserTag
+ */
+@RestController
+public class AdminMiscBridge2Controller extends BaseController {
+
+    @Autowired(required = false)
+    private JdbcTemplate jdbcTemplate;
+
+    private TableDataInfo safeListFromTable(String table) {
+        TableDataInfo r = new TableDataInfo();
+        r.setCode(200);
+        r.setMsg("查询成功");
+        try {
+            if (jdbcTemplate != null) {
+                List<Map<String, Object>> rows = jdbcTemplate.queryForList(
+                        "SELECT * FROM " + table + " ORDER BY 1 DESC LIMIT 200");
+                r.setRows(rows);
+                r.setTotal(rows.size());
+            } else {
+                r.setRows(new ArrayList<>());
+                r.setTotal(0);
+            }
+        } catch (Exception e) {
+            r.setRows(new ArrayList<>());
+            r.setTotal(0);
+        }
+        return r;
+    }
+
+    // ========== system/companyVoiceDialog ==========
+    @GetMapping("/system/companyVoiceDialog/list")
+    public TableDataInfo systemCompanyVoiceDialogList() {
+        return safeListFromTable("company_voice_dialog");
+    }
+
+    // ========== system/companyVoiceRobotic ==========
+    @GetMapping("/system/companyVoiceRobotic/list")
+    public TableDataInfo systemCompanyVoiceRoboticList() {
+        return safeListFromTable("company_voice_robotic");
+    }
+
+    // ========== system/companyVoiceRoboticCallees ==========
+    @GetMapping("/system/companyVoiceRoboticCallees/list")
+    public TableDataInfo systemCompanyVoiceRoboticCalleesList() {
+        return safeListFromTable("company_voice_robotic_callees");
+    }
+
+    // ========== shop/* ==========
+    @GetMapping("/shop/msg/list")
+    public TableDataInfo shopMsgList() {
+        return safeListFromTable("fs_shop_msg");
+    }
+
+    @GetMapping("/shop/records/list")
+    public TableDataInfo shopRecordsList() {
+        return safeListFromTable("fs_shop_records");
+    }
+
+    @GetMapping("/shop/role/list")
+    public TableDataInfo shopRoleList() {
+        return safeListFromTable("fs_shop_role");
+    }
+
+    // ========== watchApi/* ==========
+    @GetMapping("/watchApi/deviceInfo/list")
+    public TableDataInfo watchApiDeviceInfoList() {
+        return safeListFromTable("watch_device_info");
+    }
+
+    @GetMapping("/watchApi/devicelnfo/list")
+    public TableDataInfo watchApiDevicelnfoList() {
+        // 注意:菜单中 devicelnfo 是小写L不是大写I
+        return safeListFromTable("watch_device_info");
+    }
+
+    @GetMapping("/watchApi/iot/list")
+    public TableDataInfo watchApiIotList() {
+        return safeListFromTable("watch_iot");
+    }
+
+    // ========== ad/* ==========
+    @GetMapping("/ad/html/list")
+    public TableDataInfo adHtmlList() {
+        return safeListFromTable("ad_html");
+    }
+
+    @GetMapping("/ad/AdYouKuaccount/list")
+    public TableDataInfo adYouKuAccountList() {
+        return safeListFromTable("ad_youku_account");
+    }
+
+    // ========== FastGptExtUserTag ==========
+    @GetMapping("/FastGptExtUserTag/FastGptExtUserTag/list")
+    public TableDataInfo fastGptExtUserTagList() {
+        return safeListFromTable("fast_gpt_ext_user_tag");
+    }
+}

+ 99 - 0
fs-service/src/main/java/com/fs/admin/controller/AdminMissingStubsController.java

@@ -0,0 +1,99 @@
+package com.fs.admin.controller;
+
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.*;
+
+/**
+ * fs-admin 端补全缺失模块的存根控制器
+ * 仅在 fs-admin (8004) 加载(fs-company 通过 ComponentScan 排除 com.fs.admin.controller.*)
+ *
+ * 覆盖:
+ *   - 代理核心 4 项:proxy/balance, proxy/info, proxy/dashboard, proxy/moduleUsage
+ *   - AI 客服 8 项:chat/chatKeyword, chatDataset, chatRole, chatSession, chatMsg,
+ *                    chatMsgLogs, chatDatasetFile, chatUser
+ *   - 系统审批 1 项:system/approval(会员转移记录)
+ */
+@RestController
+public class AdminMissingStubsController extends BaseController {
+
+    @Autowired(required = false)
+    private JdbcTemplate jdbcTemplate;
+
+    private TableDataInfo emptyTable() {
+        TableDataInfo r = new TableDataInfo();
+        r.setCode(200);
+        r.setMsg("查询成功");
+        r.setRows(new ArrayList<>());
+        r.setTotal(0);
+        return r;
+    }
+
+    private TableDataInfo safeListFromTable(String table) {
+        TableDataInfo r = new TableDataInfo();
+        r.setCode(200);
+        r.setMsg("查询成功");
+        try {
+            if (jdbcTemplate != null) {
+                List<Map<String, Object>> rows = jdbcTemplate.queryForList(
+                        "SELECT * FROM " + table + " LIMIT 100");
+                r.setRows(rows);
+                r.setTotal(rows.size());
+            } else {
+                r.setRows(new ArrayList<>());
+                r.setTotal(0);
+            }
+        } catch (Exception e) {
+            r.setRows(new ArrayList<>());
+            r.setTotal(0);
+        }
+        return r;
+    }
+
+    // ========== 代理 proxy 核心 ==========
+    @GetMapping("/proxy/balance/list")
+    public TableDataInfo proxyBalance() { return safeListFromTable("proxy_balance"); }
+
+    @GetMapping("/proxy/info/list")
+    public TableDataInfo proxyInfo() { return safeListFromTable("proxy_info"); }
+
+    @GetMapping("/proxy/dashboard/list")
+    public TableDataInfo proxyDashboard() { return safeListFromTable("proxy"); }
+
+    @GetMapping("/proxy/moduleUsage/list")
+    public TableDataInfo proxyModuleUsage() { return safeListFromTable("proxy_module_usage"); }
+
+    // ========== AI 客服 chat/* ==========
+    @GetMapping("/chat/chatKeyword/list")
+    public TableDataInfo chatKeyword() { return safeListFromTable("chat_keyword"); }
+
+    @GetMapping("/chat/chatDataset/list")
+    public TableDataInfo chatDataset() { return safeListFromTable("chat_dataset"); }
+
+    @GetMapping("/chat/chatRole/list")
+    public TableDataInfo chatRole() { return safeListFromTable("chat_role"); }
+
+    @GetMapping("/chat/chatSession/list")
+    public TableDataInfo chatSession() { return safeListFromTable("chat_session"); }
+
+    @GetMapping("/chat/chatMsg/list")
+    public TableDataInfo chatMsg() { return safeListFromTable("chat_msg"); }
+
+    @GetMapping("/chat/chatMsgLogs/list")
+    public TableDataInfo chatMsgLogs() { return safeListFromTable("chat_msg_logs"); }
+
+    @GetMapping("/chat/chatDatasetFile/list")
+    public TableDataInfo chatDatasetFile() { return safeListFromTable("chat_dataset_file"); }
+
+    @GetMapping("/chat/chatUser/list")
+    public TableDataInfo chatUser() { return safeListFromTable("chat_user"); }
+
+    // ========== 系统审批 ==========
+    @GetMapping("/system/approval/list")
+    public TableDataInfo systemApproval() { return safeListFromTable("sys_approval"); }
+}

+ 84 - 0
fs-service/src/main/java/com/fs/admin/controller/AdminModuleUsageController.java

@@ -0,0 +1,84 @@
+package com.fs.admin.controller;
+
+import java.util.List;
+import java.util.Map;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.proxy.domain.TenantModuleUsage;
+import com.fs.proxy.service.TenantModuleUsageService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * Admin总后台-租户模块使用统计控制器
+ * 总后台可查看所有代理下所有租户的模块使用详情
+ * 支持按代理维度、租户维度筛选
+ */
+@RestController
+@RequestMapping({"/admin/moduleUsage", "/admin/module-usage"})
+public class AdminModuleUsageController extends BaseController {
+
+    @Autowired
+    private TenantModuleUsageService tenantModuleUsageService;
+
+    /**
+     * 查询所有租户模块使用统计列表
+     * 支持按代理ID、租户名称、日期范围筛选
+     */
+    @PreAuthorize("@ss.hasPermi('admin:moduleUsage:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(TenantModuleUsage query) {
+        startPage();
+        List<TenantModuleUsage> list = tenantModuleUsageService.selectTenantModuleUsageList(query);
+        return getDataTable(list);
+    }
+
+    /**
+     * 按代理维度查看模块使用详情
+     * 返回:指定代理下所有租户的模块使用情况
+     */
+    @PreAuthorize("@ss.hasPermi('admin:moduleUsage:list')")
+    @GetMapping("/proxy/{proxyId}")
+    public AjaxResult proxyDetail(@PathVariable Long proxyId,
+                                  @RequestParam(required = false) String statDate) {
+        Map<String, Object> data = tenantModuleUsageService.getModuleUsageDetail(proxyId, statDate);
+        return AjaxResult.success(data);
+    }
+
+    /**
+     * 查询指定租户的最新统计详情
+     */
+    @PreAuthorize("@ss.hasPermi('admin:moduleUsage:list')")
+    @GetMapping("/tenant/{tenantId}")
+    public AjaxResult tenantDetail(@PathVariable Long tenantId) {
+        TenantModuleUsage usage = tenantModuleUsageService.selectLatestByTenantId(tenantId);
+        return AjaxResult.success(usage);
+    }
+
+    /**
+     * 手动触发全量统计汇总
+     */
+    @PreAuthorize("@ss.hasPermi('admin:moduleUsage:refresh')")
+    @Log(title = "租户模块使用统计", businessType = BusinessType.INSERT)
+    @PostMapping("/refresh")
+    public AjaxResult refreshStatistics() {
+        tenantModuleUsageService.executeDailyStatistics();
+        return AjaxResult.success("全量统计任务已触发");
+    }
+
+    /**
+     * 手动触发指定租户的统计汇总
+     */
+    @PreAuthorize("@ss.hasPermi('admin:moduleUsage:refresh')")
+    @Log(title = "租户模块使用统计", businessType = BusinessType.INSERT)
+    @PostMapping("/refresh/{tenantId}")
+    public AjaxResult refreshTenantStatistics(@PathVariable Long tenantId) {
+        tenantModuleUsageService.statisticsForTenant(tenantId);
+        return AjaxResult.success("租户" + tenantId + "统计已刷新");
+    }
+}

+ 103 - 0
fs-service/src/main/java/com/fs/admin/controller/AdminProxyController.java

@@ -0,0 +1,103 @@
+package com.fs.admin.controller;
+
+import java.util.List;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.proxy.domain.Proxy;
+import com.fs.proxy.service.ProxyService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 总后台-代理管理控制器
+ * 
+ * @author fs
+ * @date 2024-01-01
+ */
+@RestController
+@RequestMapping("/admin/proxy")
+public class AdminProxyController extends BaseController
+{
+    @Autowired
+    private ProxyService proxyService;
+
+    /**
+     * 查询代理列表
+     */
+    @PreAuthorize("@ss.hasPermi('admin:proxy:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(Proxy proxy) {
+        startPage();
+        List<Proxy> list = proxyService.selectProxyList(proxy);
+        return getDataTable(list);
+    }
+
+    /**
+     * 获取代理详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('admin:proxy:query')")
+    @GetMapping(value = "/{proxyId}")
+    public AjaxResult getInfo(@PathVariable("proxyId") Long proxyId) {
+        return AjaxResult.success(proxyService.selectProxyById(proxyId));
+    }
+
+    /**
+     * 新增代理
+     */
+    @PreAuthorize("@ss.hasPermi('admin:proxy:add')")
+    @Log(title = "代理管理", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody Proxy proxy) {
+        return toAjax(proxyService.insertProxy(proxy));
+    }
+
+    /**
+     * 修改代理
+     */
+    @PreAuthorize("@ss.hasPermi('admin:proxy:edit')")
+    @Log(title = "代理管理", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody Proxy proxy) {
+        return toAjax(proxyService.updateProxy(proxy));
+    }
+
+    /**
+     * 删除代理
+     */
+    @PreAuthorize("@ss.hasPermi('admin:proxy:remove')")
+    @Log(title = "代理管理", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{proxyIds}")
+    public AjaxResult remove(@PathVariable Long[] proxyIds) {
+        return toAjax(proxyService.deleteProxyByIds(proxyIds));
+    }
+
+    /**
+     * 启用/禁用代理
+     */
+    @PreAuthorize("@ss.hasPermi('admin:proxy:edit')")
+    @Log(title = "代理管理", businessType = BusinessType.UPDATE)
+    @PutMapping("/changeStatus/{proxyId}")
+    public AjaxResult changeStatus(@PathVariable Long proxyId, @RequestParam Integer status) {
+        Proxy proxy = new Proxy();
+        proxy.setProxyId(proxyId);
+        proxy.setStatus(status);
+        return toAjax(proxyService.updateProxy(proxy));
+    }
+
+    /**
+     * 获取所有启用的代理(下拉列表用)
+     */
+    @PreAuthorize("@ss.hasPermi('admin:proxy:query')")
+    @GetMapping("/allEnabled")
+    public AjaxResult allEnabled() {
+        Proxy query = new Proxy();
+        query.setStatus(1);
+        List<Proxy> list = proxyService.selectProxyList(query);
+        return AjaxResult.success(list);
+    }
+}

+ 123 - 0
fs-service/src/main/java/com/fs/admin/controller/AdminRechargeRecordController.java

@@ -0,0 +1,123 @@
+package com.fs.admin.controller;
+
+import java.util.*;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.fs.billing.domain.TenantWalletTxn;
+import com.fs.billing.mapper.TenantWalletTxnMapper;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.company.domain.Company;
+import com.fs.company.mapper.CompanyMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 总后台-租户充值记录控制器
+ * 数据来源:tenant_wallet_txn (txn_type='RECHARGE')
+ */
+@RestController
+@RequestMapping("/admin/recharge-record")
+public class AdminRechargeRecordController extends BaseController {
+
+    @Autowired
+    private TenantWalletTxnMapper tenantWalletTxnMapper;
+
+    @Autowired
+    private CompanyMapper companyMapper;
+
+    /**
+     * 查询充值记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('admin:rechargeRecord:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(@RequestParam(required = false) String tenantName,
+                              @RequestParam(required = false) String createBy,
+                              @RequestParam(required = false) String beginTime,
+                              @RequestParam(required = false) String endTime) {
+        startPage();
+        LambdaQueryWrapper<TenantWalletTxn> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(TenantWalletTxn::getTxnType, "RECHARGE");
+        wrapper.orderByDesc(TenantWalletTxn::getCreateTime);
+
+        if (tenantName != null && !tenantName.isEmpty()) {
+            Company query = new Company();
+            query.setCompanyName(tenantName);
+            List<Company> companies = companyMapper.selectCompanyList(query);
+            List<Long> tenantIds = new ArrayList<>();
+            for (Company c : companies) {
+                tenantIds.add(c.getCompanyId());
+            }
+            if (tenantIds.isEmpty()) {
+                return getDataTable(new ArrayList<>());
+            }
+            wrapper.in(TenantWalletTxn::getTenantId, tenantIds);
+        }
+        if (createBy != null && !createBy.isEmpty()) {
+            wrapper.like(TenantWalletTxn::getCreateBy, createBy);
+        }
+        if (beginTime != null && !beginTime.isEmpty()) {
+            wrapper.ge(TenantWalletTxn::getCreateTime, beginTime + " 00:00:00");
+        }
+        if (endTime != null && !endTime.isEmpty()) {
+            wrapper.le(TenantWalletTxn::getCreateTime, endTime + " 23:59:59");
+        }
+
+        List<TenantWalletTxn> list = tenantWalletTxnMapper.selectList(wrapper);
+        List<Map<String, Object>> resultList = new ArrayList<>();
+        if (!list.isEmpty()) {
+            List<Long> tenantIds = new ArrayList<>();
+            for (TenantWalletTxn txn : list) {
+                tenantIds.add(txn.getTenantId());
+            }
+            Map<Long, String> nameMap = new HashMap<>();
+            List<Company> companies = companyMapper.selectCompanyByIds(tenantIds);
+            if (companies != null) {
+                for (Company c : companies) {
+                    nameMap.put(c.getCompanyId(), c.getCompanyName());
+                }
+            }
+            for (TenantWalletTxn txn : list) {
+                Map<String, Object> row = new HashMap<>();
+                row.put("id", txn.getId());
+                row.put("tenantId", txn.getTenantId());
+                row.put("tenantName", nameMap.getOrDefault(txn.getTenantId(), ""));
+                row.put("amount", txn.getAmount());
+                row.put("balanceAfter", txn.getBalanceAfter());
+                row.put("payMethod", txn.getBizType());
+                row.put("createBy", txn.getCreateBy());
+                row.put("createTime", txn.getCreateTime());
+                row.put("remark", txn.getRemark());
+                resultList.add(row);
+            }
+        }
+        return getDataTable(resultList);
+    }
+
+    /**
+     * 获取充值记录详情
+     */
+    @PreAuthorize("@ss.hasPermi('admin:rechargeRecord:list')")
+    @GetMapping("/{id}")
+    public AjaxResult getInfo(@PathVariable Long id) {
+        TenantWalletTxn txn = tenantWalletTxnMapper.selectById(id);
+        if (txn != null) {
+            Company company = companyMapper.selectCompanyById(txn.getTenantId());
+            Map<String, Object> result = new HashMap<>();
+            result.put("id", txn.getId());
+            result.put("tenantId", txn.getTenantId());
+            result.put("tenantName", company != null ? company.getCompanyName() : "");
+            result.put("amount", txn.getAmount());
+            result.put("balanceAfter", txn.getBalanceAfter());
+            result.put("payMethod", txn.getBizType());
+            result.put("txnNo", txn.getTxnNo());
+            result.put("createBy", txn.getCreateBy());
+            result.put("createTime", txn.getCreateTime());
+            result.put("remark", txn.getRemark());
+            return AjaxResult.success(result);
+        }
+        return AjaxResult.error("记录不存在");
+    }
+}

+ 70 - 0
fs-service/src/main/java/com/fs/admin/controller/AdminServiceCostController.java

@@ -0,0 +1,70 @@
+package com.fs.admin.controller;
+
+import java.util.List;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.proxy.domain.ServiceFeeConfig;
+import com.fs.proxy.service.BalanceService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 总后台-服务成本价管理控制器
+ * 管理平台级各服务类型的成本价和租户售价
+ *
+ * @author fs
+ * @date 2024-01-01
+ */
+@RestController
+@RequestMapping("/admin/serviceCost")
+public class AdminServiceCostController extends BaseController
+{
+    @Autowired
+    private BalanceService balanceService;
+
+    /**
+     * 获取服务成本配置列表(所有9项服务)
+     */
+    @PreAuthorize("@ss.hasPermi('admin:serviceCost:list')")
+    @GetMapping("/list")
+    public AjaxResult list() {
+        List<ServiceFeeConfig> list = balanceService.getAllFeeConfigs();
+        return AjaxResult.success(list);
+    }
+
+    /**
+     * 根据服务类型获取成本配置
+     */
+    @PreAuthorize("@ss.hasPermi('admin:serviceCost:query')")
+    @GetMapping("/{serviceType}")
+    public AjaxResult getByType(@PathVariable Integer serviceType) {
+        ServiceFeeConfig config = balanceService.getFeeConfig(serviceType);
+        return AjaxResult.success(config);
+    }
+
+    /**
+     * 更新服务成本配置
+     */
+    @PreAuthorize("@ss.hasPermi('admin:serviceCost:edit')")
+    @Log(title = "服务成本配置", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody ServiceFeeConfig config) {
+        boolean result = balanceService.updateFeeConfig(config);
+        return result ? AjaxResult.success("更新成功") : AjaxResult.error("更新失败");
+    }
+
+    /**
+     * 获取所有启用的服务类型简要列表(下拉选择用)
+     */
+    @PreAuthorize("@ss.hasPermi('admin:serviceCost:query')")
+    @GetMapping("/enabled")
+    public AjaxResult getEnabled() {
+        List<ServiceFeeConfig> all = balanceService.getAllFeeConfigs();
+        all.removeIf(c -> c.getEnabled() == null || c.getEnabled() == 0);
+        return AjaxResult.success(all);
+    }
+}

+ 64 - 0
fs-service/src/main/java/com/fs/admin/controller/AdminSopController.java

@@ -0,0 +1,64 @@
+package com.fs.admin.controller;
+
+import java.util.*;
+
+import com.fs.admin.helper.AdminCrossTenantHelper;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.page.TableDataInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 总后台SOP工作流管理控制器
+ * 遍历所有租户库查询 qw_sop / qw_sop_temp 数据
+ */
+@RestController
+@RequestMapping("/admin/sop")
+public class AdminSopController extends BaseController {
+
+    @Autowired
+    private AdminCrossTenantHelper crossTenantHelper;
+
+    @PreAuthorize("@ss.hasPermi('admin:sop:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(@RequestParam(required = false) String sopName,
+                              @RequestParam(required = false) Long companyId,
+                              @RequestParam(required = false) String companyName) {
+        List<Map<String, Object>> allList = crossTenantHelper.queryAcrossTenants(
+                companyId, companyName, (tenant, jdbc) -> {
+                    StringBuilder sql = new StringBuilder("SELECT qs.* FROM qw_sop qs WHERE 1=1");
+                    List<Object> params = new ArrayList<>();
+                    if (sopName != null && !sopName.isEmpty()) {
+                        sql.append(" AND qs.name LIKE ?");
+                        params.add("%" + sopName + "%");
+                    }
+                    sql.append(" ORDER BY qs.create_time DESC LIMIT 200");
+                    return params.isEmpty()
+                            ? jdbc.queryForList(sql.toString())
+                            : jdbc.queryForList(sql.toString(), params.toArray());
+                });
+        return getDataTable(allList);
+    }
+
+    @PreAuthorize("@ss.hasPermi('admin:sop:list')")
+    @GetMapping("/temp/list")
+    public TableDataInfo tempList(@RequestParam(required = false) String tempName,
+                                  @RequestParam(required = false) Long companyId,
+                                  @RequestParam(required = false) String companyName) {
+        List<Map<String, Object>> allList = crossTenantHelper.queryAcrossTenants(
+                companyId, companyName, (tenant, jdbc) -> {
+                    StringBuilder sql = new StringBuilder("SELECT * FROM qw_sop_temp WHERE 1=1");
+                    List<Object> params = new ArrayList<>();
+                    if (tempName != null && !tempName.isEmpty()) {
+                        sql.append(" AND name LIKE ?");
+                        params.add("%" + tempName + "%");
+                    }
+                    sql.append(" ORDER BY create_time DESC LIMIT 200");
+                    return params.isEmpty()
+                            ? jdbc.queryForList(sql.toString())
+                            : jdbc.queryForList(sql.toString(), params.toArray());
+                });
+        return getDataTable(allList);
+    }
+}

+ 397 - 0
fs-service/src/main/java/com/fs/admin/controller/AdminStatisticsController.java

@@ -0,0 +1,397 @@
+package com.fs.admin.controller;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.proxy.domain.PlatformStatistics;
+import com.fs.proxy.domain.Proxy;
+import com.fs.proxy.domain.ProxyServicePrice;
+import com.fs.proxy.domain.ProxyTenantRel;
+import com.fs.proxy.domain.TenantConsumeRecord;
+import com.fs.proxy.service.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 总后台统计控制器(统一使用 platform_statistics 表)
+ * 
+ * @author fs
+ * @date 2024-01-01
+ */
+@RestController
+@RequestMapping("/admin/statistics")
+public class AdminStatisticsController extends BaseController
+{
+    @Autowired
+    private ProxyTenantRelService proxyTenantRelService;
+
+    @Autowired
+    private TenantConsumeService tenantConsumeService;
+
+    @Autowired
+    private ProxyServicePriceService proxyServicePriceService;
+
+    @Autowired
+    private PlatformStatisticsService platformStatisticsService;
+
+    @Autowired
+    private ProxyService proxyService;
+
+    /**
+     * 获取平台总览统计
+     */
+    @PreAuthorize("@ss.hasPermi('admin:statistics:overview')")
+    @GetMapping("/overview")
+    public AjaxResult getOverview() {
+        Map<String, Object> result = new HashMap<>();
+        
+        List<ProxyTenantRel> allRelations = proxyTenantRelService.selectProxyTenantRelList(null);
+        result.put("totalTenantCount", allRelations.size());
+        
+        long proxyCount = allRelations.stream().map(ProxyTenantRel::getProxyId).distinct().count();
+        result.put("totalProxyCount", proxyCount);
+        
+        Date today = new java.sql.Date(System.currentTimeMillis());
+        List<PlatformStatistics> todayStats = platformStatisticsService.getHourlyStats(today, null);
+        BigDecimal todayConsume = todayStats.stream()
+            .map(s -> s.getConsumeAmount() != null ? s.getConsumeAmount() : BigDecimal.ZERO)
+            .reduce(BigDecimal.ZERO, BigDecimal::add);
+        BigDecimal todayProfit = todayStats.stream()
+            .map(s -> s.getProxyProfit() != null ? s.getProxyProfit() : BigDecimal.ZERO)
+            .reduce(BigDecimal.ZERO, BigDecimal::add);
+        result.put("todayConsume", todayConsume);
+        result.put("todayProfit", todayProfit);
+        
+        // 成本配置数
+        List<ProxyServicePrice> priceList = proxyServicePriceService.selectProxyServicePriceList(null);
+        result.put("serviceTypeCount", priceList.size());
+        
+        return AjaxResult.success(result);
+    }
+
+    /**
+     * 获取代理分佣统计
+     */
+    @PreAuthorize("@ss.hasPermi('admin:statistics:proxyProfit')")
+    @GetMapping("/proxyProfit")
+    public TableDataInfo getProxyProfitStatistics(@RequestParam(required = false) String startDate,
+                                                  @RequestParam(required = false) String endDate) {
+        Date start = startDate != null ? java.sql.Date.valueOf(startDate) : null;
+        Date end = endDate != null ? java.sql.Date.valueOf(endDate) : null;
+        List<PlatformStatistics> stats = platformStatisticsService.getProxyProfitStats(start, end);
+        return getDataTable(stats);
+    }
+
+    /**
+     * 获取租户消费统计
+     */
+    @PreAuthorize("@ss.hasPermi('admin:statistics:tenantConsume')")
+    @GetMapping("/tenantConsume")
+    public TableDataInfo getTenantConsumeStatistics(@RequestParam(required = false) String startDate,
+                                                     @RequestParam(required = false) String endDate) {
+        Date start = startDate != null ? java.sql.Date.valueOf(startDate) : null;
+        Date end = endDate != null ? java.sql.Date.valueOf(endDate) : null;
+        List<PlatformStatistics> stats = platformStatisticsService.getTenantConsumeStats(start, end);
+        return getDataTable(stats);
+    }
+
+    /**
+     * 获取消费类型统计
+     */
+    @PreAuthorize("@ss.hasPermi('admin:statistics:consumeType')")
+    @GetMapping("/consumeType")
+    public AjaxResult getConsumeTypeStatistics(@RequestParam(required = false) String startDate,
+                                               @RequestParam(required = false) String endDate) {
+        Date start = startDate != null ? java.sql.Date.valueOf(startDate) : null;
+        Date end = endDate != null ? java.sql.Date.valueOf(endDate) : null;
+        List<PlatformStatistics> stats = platformStatisticsService.getConsumeTypeStats(start, end);
+        
+        Map<String, Object> result = new HashMap<>();
+        Map<String, BigDecimal> consume = new HashMap<>();
+        Map<String, BigDecimal> cost = new HashMap<>();
+        Map<String, BigDecimal> profit = new HashMap<>();
+        for (PlatformStatistics s : stats) {
+            String t = s.getConsumeType() != null ? s.getConsumeType() : "未知";
+            consume.put(t, s.getConsumeAmount());
+            cost.put(t, s.getPlatformCost());
+            profit.put(t, s.getProxyProfit());
+        }
+        result.put("consumeByType", consume);
+        result.put("costByType", cost);
+        result.put("profitByType", profit);
+        return AjaxResult.success(result);
+    }
+
+    /**
+     * 获取平台成本汇总
+     */
+    @PreAuthorize("@ss.hasPermi('admin:statistics:costSummary')")
+    @GetMapping("/costSummary")
+    public AjaxResult getCostSummary(@RequestParam(required = false) String startDate,
+                                     @RequestParam(required = false) String endDate) {
+        Date start = startDate != null ? java.sql.Date.valueOf(startDate) : null;
+        Date end = endDate != null ? java.sql.Date.valueOf(endDate) : null;
+        
+        List<PlatformStatistics> typeStats = platformStatisticsService.getConsumeTypeStats(start, end);
+        List<PlatformStatistics> proxyStats = platformStatisticsService.getProxyProfitStats(start, end);
+
+        BigDecimal totalCost = typeStats.stream()
+            .map(s -> s.getPlatformCost() != null ? s.getPlatformCost() : BigDecimal.ZERO)
+            .reduce(BigDecimal.ZERO, BigDecimal::add);
+        BigDecimal totalConsume = typeStats.stream()
+            .map(s -> s.getConsumeAmount() != null ? s.getConsumeAmount() : BigDecimal.ZERO)
+            .reduce(BigDecimal.ZERO, BigDecimal::add);
+        BigDecimal totalProfit = proxyStats.stream()
+            .map(s -> s.getProxyProfit() != null ? s.getProxyProfit() : BigDecimal.ZERO)
+            .reduce(BigDecimal.ZERO, BigDecimal::add);
+        
+        Map<String, Object> result = new HashMap<>();
+        result.put("totalCost", totalCost);
+        result.put("totalConsume", totalConsume);
+        result.put("totalProfit", totalProfit);
+        result.put("platformRevenue", totalConsume.subtract(totalCost).subtract(totalProfit));
+        return AjaxResult.success(result);
+    }
+
+    /**
+     * 获取代理分佣详情
+     */
+    @PreAuthorize("@ss.hasPermi('admin:statistics:proxyProfit')")
+    @GetMapping("/proxyProfit/{proxyId}")
+    public AjaxResult getProxyProfitDetail(@PathVariable Long proxyId,
+                                           @RequestParam(required = false) String startDate,
+                                           @RequestParam(required = false) String endDate) {
+        Date start = startDate != null ? java.sql.Date.valueOf(startDate) : null;
+        Date end = endDate != null ? java.sql.Date.valueOf(endDate) : null;
+        
+        Map<String, Object> result = new HashMap<>();
+        List<ProxyTenantRel> tenantList = proxyTenantRelService.selectProxyTenantRelByProxyId(proxyId);
+        result.put("tenantList", tenantList);
+        
+        List<PlatformStatistics> detail = platformStatisticsService.getProxyDetail(proxyId, start, end);
+        BigDecimal total = detail.stream()
+            .map(s -> s.getProxyProfit() != null ? s.getProxyProfit() : BigDecimal.ZERO)
+            .reduce(BigDecimal.ZERO, BigDecimal::add);
+        result.put("totalProfit", total);
+        result.put("details", detail);
+        return AjaxResult.success(result);
+    }
+
+    /**
+     * 获取租户消费详情
+     */
+    @PreAuthorize("@ss.hasPermi('admin:statistics:tenantConsume')")
+    @GetMapping("/tenantDetail/{tenantId}")
+    public AjaxResult getTenantDetail(@PathVariable Long tenantId,
+                                      @RequestParam(required = false) String startDate,
+                                      @RequestParam(required = false) String endDate) {
+        Date start = startDate != null ? java.sql.Date.valueOf(startDate) : null;
+        Date end = endDate != null ? java.sql.Date.valueOf(endDate) : null;
+        List<PlatformStatistics> detail = platformStatisticsService.getTenantDetail(tenantId, start, end);
+        return AjaxResult.success(detail);
+    }
+
+    /**
+     * 获取平台趋势
+     */
+    @PreAuthorize("@ss.hasPermi('admin:statistics:trend')")
+    @GetMapping("/trend")
+    public AjaxResult getPlatformTrend(@RequestParam(required = false) String startDate,
+                                       @RequestParam(required = false) String endDate) {
+        Date start = startDate != null ? java.sql.Date.valueOf(startDate) : null;
+        Date end = endDate != null ? java.sql.Date.valueOf(endDate) : null;
+        List<PlatformStatistics> trend = platformStatisticsService.getTrend(start, end);
+        return AjaxResult.success(trend);
+    }
+
+    /**
+     * 获取小时统计
+     */
+    @PreAuthorize("@ss.hasPermi('admin:statistics:hourly')")
+    @GetMapping("/hourly")
+    public AjaxResult getHourlyStatistics(@RequestParam(required = false) String statDate,
+                                          @RequestParam(required = false) String dimension) {
+        if (statDate == null || statDate.isEmpty()) {
+            statDate = java.time.LocalDate.now().toString();
+        }
+        Date date = java.sql.Date.valueOf(statDate);
+        List<PlatformStatistics> stats = platformStatisticsService.getHourlyStats(date, dimension);
+        return AjaxResult.success(stats);
+    }
+
+    /**
+     * 获取服务成本配置
+     */
+    @PreAuthorize("@ss.hasPermi('admin:statistics:costConfig')")
+    @GetMapping("/costConfig")
+    public AjaxResult getCostConfigList() {
+        return AjaxResult.success(proxyServicePriceService.selectProxyServicePriceList(null));
+    }
+
+    /**
+     * 获取原始消费记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('admin:statistics:tenantConsume')")
+    @GetMapping("/consumeRecords")
+    public TableDataInfo getConsumeRecords(TenantConsumeRecord query) {
+        startPage();
+        List<TenantConsumeRecord> list = tenantConsumeService.selectTenantConsumeRecordList(query);
+        return getDataTable(list);
+    }
+
+    /**
+     * 手动执行统计
+     */
+    @PreAuthorize("@ss.hasPermi('admin:statistics:execute')")
+    @PostMapping("/execute")
+    public AjaxResult executeStatistics(@RequestParam(required = false) String type) {
+        if ("daily".equals(type)) {
+            platformStatisticsService.executeDailySummary();
+            return AjaxResult.success("日汇总执行成功");
+        } else if ("monthly".equals(type)) {
+            platformStatisticsService.executeMonthlySummary();
+            return AjaxResult.success("月汇总执行成功");
+        } else {
+            platformStatisticsService.executeHourlyStats();
+            return AjaxResult.success("小时统计执行成功");
+        }
+    }
+
+    // ==================== 每日统计(代理维度) ====================
+
+    /**
+     * 每日统计 - 代理下租户消费明细
+     * 按天统计指定代理下每个租户的消费金额、成本、利润
+     */
+    @PreAuthorize("@ss.hasPermi('admin:statistics:daily')")
+    @GetMapping("/daily/agentTenants")
+    public AjaxResult getDailyAgentTenants(
+            @RequestParam(required = false) Long proxyId,
+            @RequestParam(required = false) String statDate) {
+        Date date = statDate != null ? java.sql.Date.valueOf(statDate)
+                : new java.sql.Date(System.currentTimeMillis());
+
+        // 获取该代理下的所有租户
+        List<ProxyTenantRel> tenantRels = proxyTenantRelService.selectProxyTenantRelByProxyId(proxyId);
+        List<Long> tenantIds = new java.util.ArrayList<>();
+        for (ProxyTenantRel rel : tenantRels) {
+            tenantIds.add(rel.getTenantId());
+        }
+
+        // 查询这些租户的日统计
+        List<PlatformStatistics> stats = platformStatisticsService.getTenantDailyByProxy(proxyId, tenantIds, date);
+
+        // 补充租户名称
+        Map<Long, String> tenantNameMap = new java.util.HashMap<>();
+        for (ProxyTenantRel rel : tenantRels) {
+            tenantNameMap.put(rel.getTenantId(), rel.getTenantName());
+        }
+        for (PlatformStatistics s : stats) {
+            if (s.getTenantId() != null && tenantNameMap.containsKey(s.getTenantId())) {
+                s.setRemark(tenantNameMap.get(s.getTenantId()));
+            }
+        }
+
+        // 计算汇总
+        BigDecimal totalConsume = stats.stream()
+                .map(s -> s.getConsumeAmount() != null ? s.getConsumeAmount() : BigDecimal.ZERO)
+                .reduce(BigDecimal.ZERO, BigDecimal::add);
+        BigDecimal totalCost = stats.stream()
+                .map(s -> s.getPlatformCost() != null ? s.getPlatformCost() : BigDecimal.ZERO)
+                .reduce(BigDecimal.ZERO, BigDecimal::add);
+        BigDecimal totalProfit = stats.stream()
+                .map(s -> s.getTenantPrice() != null ? s.getTenantPrice() : BigDecimal.ZERO)
+                .reduce(BigDecimal.ZERO, BigDecimal::add)
+                .subtract(totalCost);
+        BigDecimal totalAgentProfit = stats.stream()
+                .map(s -> s.getProxyProfit() != null ? s.getProxyProfit() : BigDecimal.ZERO)
+                .reduce(BigDecimal.ZERO, BigDecimal::add);
+
+        Map<String, Object> result = new HashMap<>();
+        result.put("statDate", statDate);
+        result.put("proxyId", proxyId);
+        result.put("tenantCount", tenantRels.size());
+        result.put("totalConsume", totalConsume);
+        result.put("totalCost", totalCost);
+        result.put("totalProfit", totalProfit);
+        result.put("totalAgentProfit", totalAgentProfit);
+        result.put("items", stats);
+        result.put("tenantNames", tenantNameMap);
+        return AjaxResult.success(result);
+    }
+
+    /**
+     * 每日统计 - 各服务类型利润
+     * 按天统计指定代理下各服务类型的消费、成本、利润
+     */
+    @PreAuthorize("@ss.hasPermi('admin:statistics:daily')")
+    @GetMapping("/daily/serviceTypeProfit")
+    public AjaxResult getDailyServiceTypeProfit(
+            @RequestParam(required = false) Long proxyId,
+            @RequestParam(required = false) String statDate) {
+        Date date = statDate != null ? java.sql.Date.valueOf(statDate)
+                : new java.sql.Date(System.currentTimeMillis());
+
+        List<Long> tenantIds = null;
+        if (proxyId != null) {
+            List<ProxyTenantRel> tenantRels = proxyTenantRelService.selectProxyTenantRelByProxyId(proxyId);
+            tenantIds = new java.util.ArrayList<>();
+            for (ProxyTenantRel rel : tenantRels) {
+                tenantIds.add(rel.getTenantId());
+            }
+        }
+
+        List<PlatformStatistics> stats = platformStatisticsService.getTypeDailyByProxyTenants(tenantIds, date);
+
+        BigDecimal totalProfit = stats.stream()
+                .map(s -> {
+                    BigDecimal ca = s.getConsumeAmount() != null ? s.getConsumeAmount() : BigDecimal.ZERO;
+                    BigDecimal pc = s.getPlatformCost() != null ? s.getPlatformCost() : BigDecimal.ZERO;
+                    return ca.subtract(pc);
+                })
+                .reduce(BigDecimal.ZERO, BigDecimal::add);
+
+        Map<String, Object> result = new HashMap<>();
+        result.put("statDate", statDate);
+        result.put("proxyId", proxyId);
+        result.put("totalProfit", totalProfit);
+        result.put("items", stats);
+        return AjaxResult.success(result);
+    }
+
+    /**
+     * 每日统计 - 代理汇总
+     * 按天汇总所有代理的消费、成本、利润
+     */
+    @PreAuthorize("@ss.hasPermi('admin:statistics:daily')")
+    @GetMapping("/daily/agentSummary")
+    public AjaxResult getDailyAgentSummary(
+            @RequestParam(required = false) String statDate) {
+        Date date = statDate != null ? java.sql.Date.valueOf(statDate)
+                : new java.sql.Date(System.currentTimeMillis());
+
+        List<PlatformStatistics> stats = platformStatisticsService.getAgentDailySummary(date);
+
+        // 补充代理名称
+        List<Proxy> allProxies = proxyService.selectProxyList(null);
+        Map<Long, String> proxyNameMap = new java.util.HashMap<>();
+        for (Proxy p : allProxies) {
+            proxyNameMap.put(p.getProxyId(), p.getProxyName());
+        }
+
+        Map<String, Object> result = new HashMap<>();
+        result.put("statDate", statDate);
+        result.put("proxyCount", stats.size());
+        result.put("items", stats);
+        result.put("proxyNames", proxyNameMap);
+        return AjaxResult.success(result);
+    }
+}

+ 308 - 0
fs-service/src/main/java/com/fs/admin/controller/AdminStoreMiscController.java

@@ -0,0 +1,308 @@
+package com.fs.admin.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.hisStore.domain.*;
+import com.fs.hisStore.service.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.*;
+
+/**
+ * 商城运营/优惠券/物流/门店管理 - adminui端Controller(fs-admin 8004)
+ * 桥接 hisStore 服务层,提供 /store/* 运营相关路径的完整CRUD
+ */
+@RestController
+public class AdminStoreMiscController extends BaseController {
+
+    @Autowired
+    private IFsStoreCouponScrmService storeCouponService;
+    @Autowired
+    private IFsStoreCouponIssueScrmService storeCouponIssueService;
+    @Autowired
+    private IFsStoreCouponIssueUserScrmService storeCouponIssueUserService;
+    @Autowired
+    private IFsStoreCouponUserScrmService storeCouponUserService;
+    @Autowired
+    private IFsStoreActivityScrmService storeActivityService;
+    @Autowired
+    private IFsShippingTemplatesScrmService shippingTemplatesService;
+    @Autowired
+    private IFsShippingTemplatesFreeScrmService shippingTemplatesFreeService;
+    @Autowired
+    private IFsShippingTemplatesRegionScrmService shippingTemplatesRegionService;
+    @Autowired
+    private IFsStoreCartScrmService storeCartService;
+    @Autowired
+    private IFsStoreShopScrmService storeShopService;
+    @Autowired
+    private IFsStoreShopStaffScrmService storeShopStaffService;
+    @Autowired
+    private IFsStoreVisitScrmService storeVisitService;
+    @Autowired
+    private IFsStoreRecommendScrmService storeRecommendService;
+    @Autowired
+    private IFsUserPromoterApplyScrmService userPromoterApplyService;
+    @Autowired
+    private IFsMenuScrmService menuScrmService;
+    @Autowired
+    private IFsPrescribeScrmService prescribeService;
+    @Autowired
+    private IFsPrescribeDrugScrmService prescribeDrugService;
+    @Autowired
+    private IFsAdvScrmService advScrmService;
+    @Autowired
+    private IFsHomeArticleScrmService homeArticleService;
+    @Autowired
+    private IFsHomeArticleCategoryScrmService homeArticleCategoryService;
+    @Autowired
+    private IFsHomeArticleViewScrmService homeArticleViewService;
+    @Autowired
+    private IFsStoreScrmService storeScrmService;
+
+    // storeCoupon CRUD已迁移至 FsStoreCouponScrmBridgeController (fs-admin模块)
+
+    // ========== 优惠券发行 /store/storeCouponIssue ==========
+    @PreAuthorize("@ss.hasPermi('store:storeCouponIssue:list')")
+    @GetMapping("/store/storeCouponIssue/list")
+    public TableDataInfo storeCouponIssueList(FsStoreCouponIssueScrm param) {
+        startPage();
+        List<FsStoreCouponIssueScrm> list = storeCouponIssueService.selectFsStoreCouponIssueList(param);
+        return getDataTable(list);
+    }
+
+    // ========== 发行用户 /store/storeCouponIssueUser ==========
+    @PreAuthorize("@ss.hasPermi('store:storeCouponIssueUser:list')")
+    @GetMapping("/store/storeCouponIssueUser/list")
+    public TableDataInfo storeCouponIssueUserList(FsStoreCouponIssueUserScrm param) {
+        startPage();
+        List<FsStoreCouponIssueUserScrm> list = storeCouponIssueUserService.selectFsStoreCouponIssueUserList(param);
+        return getDataTable(list);
+    }
+
+    // ========== 用户优惠券 /store/storeCouponUser ==========
+    @PreAuthorize("@ss.hasPermi('store:storeCouponUser:list')")
+    @GetMapping("/store/storeCouponUser/list")
+    public TableDataInfo storeCouponUserList(FsStoreCouponUserScrm param) {
+        startPage();
+        List<FsStoreCouponUserScrm> list = storeCouponUserService.selectFsStoreCouponUserList(param);
+        return getDataTable(list);
+    }
+
+    // storeActivity CRUD已迁移至 FsStoreActivityScrmBridgeController (fs-admin模块)
+
+    // ========== 运费模板 /store/shippingTemplates ==========
+    @PreAuthorize("@ss.hasPermi('store:shippingTemplates:list')")
+    @GetMapping("/store/shippingTemplates/list")
+    public TableDataInfo shippingTemplatesList(FsShippingTemplatesScrm param) {
+        startPage();
+        List<FsShippingTemplatesScrm> list = shippingTemplatesService.selectFsShippingTemplatesList(param);
+        return getDataTable(list);
+    }
+
+    // ========== 包邮模板 /store/shippingTemplatesFree ==========
+    @PreAuthorize("@ss.hasPermi('store:shippingTemplatesFree:list')")
+    @GetMapping("/store/shippingTemplatesFree/list")
+    public TableDataInfo shippingTemplatesFreeList(FsShippingTemplatesFreeScrm param) {
+        startPage();
+        List<FsShippingTemplatesFreeScrm> list = shippingTemplatesFreeService.selectFsShippingTemplatesFreeList(param);
+        return getDataTable(list);
+    }
+
+    // ========== 区域运费 /store/shippingTemplatesRegion ==========
+    @PreAuthorize("@ss.hasPermi('store:shippingTemplatesRegion:list')")
+    @GetMapping("/store/shippingTemplatesRegion/list")
+    public TableDataInfo shippingTemplatesRegionList(FsShippingTemplatesRegionScrm param) {
+        startPage();
+        List<FsShippingTemplatesRegionScrm> list = shippingTemplatesRegionService.selectFsShippingTemplatesRegionList(param);
+        return getDataTable(list);
+    }
+
+    // ========== 购物车 /store/storeCart ==========
+    @PreAuthorize("@ss.hasPermi('store:storeCart:list')")
+    @GetMapping("/store/storeCart/list")
+    public TableDataInfo storeCartList(FsStoreCartScrm param) {
+        startPage();
+        List<FsStoreCartScrm> list = storeCartService.selectFsStoreCartList(param);
+        return getDataTable(list);
+    }
+
+    // ========== 门店管理 /store/storeShop ==========
+    @PreAuthorize("@ss.hasPermi('store:storeShop:list')")
+    @GetMapping("/store/storeShop/list")
+    public TableDataInfo storeShopList(FsStoreShopScrm param) {
+        startPage();
+        List<FsStoreShopScrm> list = storeShopService.selectFsStoreShopList(param);
+        return getDataTable(list);
+    }
+
+    // ========== 门店员工 /store/storeShopStaff ==========
+    @PreAuthorize("@ss.hasPermi('store:storeShopStaff:list')")
+    @GetMapping("/store/storeShopStaff/list")
+    public TableDataInfo storeShopStaffList(FsStoreShopStaffScrm param) {
+        startPage();
+        List<FsStoreShopStaffScrm> list = storeShopStaffService.selectFsStoreShopStaffList(param);
+        return getDataTable(list);
+    }
+
+    // ========== 浏览记录 /store/storeVisit ==========
+    @PreAuthorize("@ss.hasPermi('store:storeVisit:list')")
+    @GetMapping("/store/storeVisit/list")
+    public TableDataInfo storeVisitList(FsStoreVisitScrm param) {
+        startPage();
+        List<FsStoreVisitScrm> list = storeVisitService.selectFsStoreVisitList(param);
+        return getDataTable(list);
+    }
+
+    // ========== 推荐管理 /store/recommend ==========
+    @PreAuthorize("@ss.hasPermi('store:recommend:list')")
+    @GetMapping("/store/recommend/list")
+    public TableDataInfo recommendList(FsStoreRecommendScrm param) {
+        startPage();
+        List<FsStoreRecommendScrm> list = storeRecommendService.selectFsStoreRecommendScrmList(param);
+        return getDataTable(list);
+    }
+
+    // ========== 推广员申请 /store/userPromoterApply ==========
+    @PreAuthorize("@ss.hasPermi('store:userPromoterApply:list')")
+    @GetMapping("/store/userPromoterApply/list")
+    public TableDataInfo userPromoterApplyList(FsUserPromoterApplyScrm param) {
+        startPage();
+        List<FsUserPromoterApplyScrm> list = userPromoterApplyService.selectFsUserPromoterApplyList(param);
+        return getDataTable(list);
+    }
+
+    // ========== 商城菜单 /store/menu ==========
+    @PreAuthorize("@ss.hasPermi('store:menu:list')")
+    @GetMapping("/store/menu/list")
+    public AjaxResult menuList(FsMenuScrm param) {
+        List<FsMenuScrm> list = menuScrmService.selectFsMenuList(param);
+        return AjaxResult.success(list);
+    }
+
+    // ========== 处方管理 /store/prescribe ==========
+    @PreAuthorize("@ss.hasPermi('store:prescribe:list')")
+    @GetMapping("/store/prescribe/list")
+    public TableDataInfo prescribeList(FsPrescribeScrm param) {
+        startPage();
+        List<FsPrescribeScrm> list = prescribeService.selectFsPrescribeList(param);
+        return getDataTable(list);
+    }
+
+    // ========== 处方药品 /store/prescribeDrug ==========
+    @PreAuthorize("@ss.hasPermi('store:prescribeDrug:list')")
+    @GetMapping("/store/prescribeDrug/list")
+    public TableDataInfo prescribeDrugList(FsPrescribeDrugScrm param) {
+        startPage();
+        List<FsPrescribeDrugScrm> list = prescribeDrugService.selectFsPrescribeDrugList(param);
+        return getDataTable(list);
+    }
+
+    // ========== 广告管理 /store/adv ==========
+    @PreAuthorize("@ss.hasPermi('store:adv:list')")
+    @GetMapping("/store/adv/list")
+    public TableDataInfo advList(FsAdvScrm param) {
+        startPage();
+        List<FsAdvScrm> list = advScrmService.selectFsAdvList(param);
+        return getDataTable(list);
+    }
+
+    // ========== 首页文章 /store/homeArticle ==========
+    @PreAuthorize("@ss.hasPermi('store:homeArticle:list')")
+    @GetMapping("/store/homeArticle/list")
+    public TableDataInfo homeArticleList(FsHomeArticleScrm param) {
+        startPage();
+        List<FsHomeArticleScrm> list = homeArticleService.selectFsHomeArticleList(param);
+        return getDataTable(list);
+    }
+
+    // ========== 首页分类 /store/homeCategory ==========
+    @PreAuthorize("@ss.hasPermi('store:homeCategory:list')")
+    @GetMapping("/store/homeCategory/list")
+    public TableDataInfo homeCategoryList(FsHomeArticleCategoryScrm param) {
+        startPage();
+        List<FsHomeArticleCategoryScrm> list = homeArticleCategoryService.selectFsHomeArticleCategoryList(param);
+        return getDataTable(list);
+    }
+
+    // ========== 首页视图 /store/homeView ==========
+    @PreAuthorize("@ss.hasPermi('store:homeView:list')")
+    @GetMapping("/store/homeView/list")
+    public TableDataInfo homeViewList(FsHomeArticleViewScrm param) {
+        startPage();
+        List<FsHomeArticleViewScrm> list = homeArticleViewService.selectFsHomeArticleViewList(param);
+        return getDataTable(list);
+    }
+
+    // ========== 店铺管理 /store/his/store ==========
+    @PreAuthorize("@ss.hasPermi('store:his:store:list')")
+    @GetMapping("/store/his/store/list")
+    public TableDataInfo hisStoreList(FsStoreScrm param) {
+        startPage();
+        List<FsStoreScrm> list = storeScrmService.selectFsStoreList(param);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:his:store:audit')")
+    @GetMapping("/store/his/store/audit")
+    public AjaxResult hisStoreAudit() {
+        return AjaxResult.success();
+    }
+
+    // ========== 商城统计 /store/statistics ==========
+    @GetMapping({"/store/statistics/storeOrder", "/store/statistics/packageOrder",
+                 "/store/statistics/storePayment", "/store/statistics/inquiryOrder"})
+    public AjaxResult storeStatistics() {
+        Map<String, Object> data = new HashMap<>();
+        data.put("total", 0);
+        data.put("amount", 0);
+        data.put("rows", new ArrayList<>());
+        return AjaxResult.success(data);
+    }
+
+    // ========== saasui额外store端点 ==========
+    @GetMapping("/store/package/list")
+    public TableDataInfo storePackageList(FsStoreProductPackageScrm param) {
+        startPage();
+        List<FsStoreProductPackageScrm> list = storeProductPackageService.selectFsStoreProductPackageList(param);
+        return getDataTable(list);
+    }
+
+    @Autowired
+    private IFsStoreProductPackageScrmService storeProductPackageService;
+
+    @GetMapping("/store/exportTask/list")
+    public TableDataInfo storeExportTaskList() {
+        return getDataTable(new ArrayList<>());
+    }
+
+    @GetMapping({"/store/healthRecord/list", "/store/healthRecord/myList"})
+    public TableDataInfo storeHealthRecordList() {
+        return getDataTable(new ArrayList<>());
+    }
+
+    @GetMapping({"/store/inquiryOrder/list", "/store/inquiryOrder/myList"})
+    public TableDataInfo storeInquiryOrderList() {
+        return getDataTable(new ArrayList<>());
+    }
+
+    @GetMapping({"/store/packageOrder/list", "/store/packageOrder/myList"})
+    public TableDataInfo storePackageOrderList() {
+        return getDataTable(new ArrayList<>());
+    }
+
+    @GetMapping({"/store/prescribe/myList", "/store/storeAfterSales/myList"})
+    public TableDataInfo storeMyLists() {
+        return getDataTable(new ArrayList<>());
+    }
+
+    @GetMapping("/store/inquiryOrderReport/list")
+    public TableDataInfo storeInquiryOrderReportList() {
+        return getDataTable(new ArrayList<>());
+    }
+}

Some files were not shown because too many files changed in this diff