Browse Source

Merge remote-tracking branch 'origin/master'

zyp 3 days ago
parent
commit
363b6627a3
100 changed files with 6305 additions and 111 deletions
  1. 0 1
      fs-admin/src/main/java/com/fs/FSApplication.java
  2. 2 2
      fs-admin/src/main/java/com/fs/api/controller/IndexStatisticsController.java
  3. 2 2
      fs-admin/src/main/java/com/fs/course/controller/FsUserWatchCourseStatisticsController.java
  4. 146 0
      fs-admin/src/main/java/com/fs/his/controller/FoodRecordController.java
  5. 106 0
      fs-admin/src/main/java/com/fs/his/controller/FsComplaintCategoryController.java
  6. 93 0
      fs-admin/src/main/java/com/fs/his/controller/FsComplaintController.java
  7. 103 0
      fs-admin/src/main/java/com/fs/his/controller/FsHfpayConfigController.java
  8. 1 1
      fs-admin/src/main/java/com/fs/his/controller/FsStoreOrderController.java
  9. 120 0
      fs-admin/src/main/java/com/fs/his/controller/FsTodoItemsController.java
  10. 3 0
      fs-admin/src/main/java/com/fs/his/controller/FsUserController.java
  11. 102 0
      fs-admin/src/main/java/com/fs/his/controller/RechargeTemplateController.java
  12. 17 0
      fs-admin/src/main/java/com/fs/his/task/FsUserTask.java
  13. 134 0
      fs-admin/src/main/java/com/fs/hisStore/FsStoreSCRMController.java
  14. 4 3
      fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreProductScrmController.java
  15. 155 0
      fs-admin/src/main/java/com/fs/medical/MeasurementUnitController.java
  16. 157 0
      fs-admin/src/main/java/com/fs/medical/MedicalIndicatorController.java
  17. 160 0
      fs-admin/src/main/java/com/fs/medical/PhysicalExamReportController.java
  18. 190 0
      fs-admin/src/main/java/com/fs/medical/ReportIndicatorResultController.java
  19. 82 0
      fs-admin/src/main/java/com/fs/saler/CompetitorInfoController.java
  20. 73 0
      fs-admin/src/main/java/com/fs/saler/FsServiceGoodsController.java
  21. 42 0
      fs-common/src/main/java/com/fs/common/utils/DateUtils.java
  22. 3 0
      fs-common/src/main/java/com/fs/common/utils/DictUtils.java
  23. 205 0
      fs-common/src/main/java/com/fs/common/utils/FileNameExtractor.java
  24. 155 0
      fs-company-app/src/main/java/com/fs/app/controller/FsUserHealthDataController.java
  25. 139 0
      fs-company-app/src/main/java/com/fs/app/controller/FsUserHealthProfileController.java
  26. 111 0
      fs-company-app/src/main/java/com/fs/app/controller/FsUserInfoController.java
  27. 96 0
      fs-company-app/src/main/java/com/fs/app/controller/FsUserPayCompetitorsRecordController.java
  28. 96 0
      fs-company-app/src/main/java/com/fs/app/controller/FsUserPayRecordController.java
  29. 13 0
      fs-company-app/src/main/java/com/fs/app/exception/FSExceptionHandler.java
  30. 21 2
      fs-company/src/main/java/com/fs/company/controller/company/CompanyUserController.java
  31. 26 4
      fs-company/src/main/java/com/fs/company/controller/company/FsDoctorController.java
  32. 99 8
      fs-company/src/main/java/com/fs/company/controller/qw/QwSopLogsController.java
  33. 69 13
      fs-company/src/main/java/com/fs/company/controller/qw/QwSopTempController.java
  34. 53 6
      fs-company/src/main/java/com/fs/company/controller/qw/SopUserLogsController.java
  35. 134 32
      fs-company/src/main/java/com/fs/company/controller/qw/SopUserLogsInfoController.java
  36. 1 1
      fs-company/src/main/java/com/fs/company/controller/store/FsUserController.java
  37. 1 1
      fs-company/src/main/java/com/fs/hisStore/controller/FsStoreProductScrmController.java
  38. 0 3
      fs-framework/src/main/java/com/fs/framework/config/LogInterceptor.java
  39. 72 0
      fs-qwhook/src/main/java/com/fs/app/controller/ApisQwUserController.java
  40. 0 4
      fs-qwhook/src/main/java/com/fs/app/controller/QwUserController.java
  41. 0 4
      fs-qwhook/src/main/java/com/fs/app/params/LoginBindCompanyParam.java
  42. 3 0
      fs-service/src/main/java/com/fs/company/domain/CompanyUser.java
  43. 3 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyUserMapper.java
  44. 4 0
      fs-service/src/main/java/com/fs/company/service/ICompanyUserService.java
  45. 41 13
      fs-service/src/main/java/com/fs/company/service/impl/CompanyUserServiceImpl.java
  46. 65 0
      fs-service/src/main/java/com/fs/complaint/domain/FsComplaint.java
  47. 51 0
      fs-service/src/main/java/com/fs/complaint/domain/FsComplaintAttachment.java
  48. 55 0
      fs-service/src/main/java/com/fs/complaint/domain/FsComplaintCategory.java
  49. 20 0
      fs-service/src/main/java/com/fs/complaint/dto/ComplaintQueryDTO.java
  50. 29 0
      fs-service/src/main/java/com/fs/complaint/dto/SubmitComplaintDTO.java
  51. 16 0
      fs-service/src/main/java/com/fs/complaint/dto/UpdateComplaintDTO.java
  52. 59 0
      fs-service/src/main/java/com/fs/complaint/mapper/FsComplaintAttachmentMapper.java
  53. 66 0
      fs-service/src/main/java/com/fs/complaint/mapper/FsComplaintCategoryMapper.java
  54. 135 0
      fs-service/src/main/java/com/fs/complaint/mapper/FsComplaintMapper.java
  55. 28 0
      fs-service/src/main/java/com/fs/complaint/param/FsComplaintCategoryParam.java
  56. 52 0
      fs-service/src/main/java/com/fs/complaint/service/FsComplaintCategoryService.java
  57. 43 0
      fs-service/src/main/java/com/fs/complaint/service/FsComplaintService.java
  58. 68 0
      fs-service/src/main/java/com/fs/complaint/service/impl/FsComplaintCategoryServiceImpl.java
  59. 195 0
      fs-service/src/main/java/com/fs/complaint/service/impl/FsComplaintServiceImpl.java
  60. 22 0
      fs-service/src/main/java/com/fs/complaint/vo/ComplaintVO.java
  61. 50 0
      fs-service/src/main/java/com/fs/complaint/vo/FsComplaintCategoryListVO.java
  62. 8 2
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCoursePeriodServiceImpl.java
  63. 59 0
      fs-service/src/main/java/com/fs/foods/domain/FsFoodRecord.java
  64. 73 0
      fs-service/src/main/java/com/fs/foods/mapper/FoodRecordMapper.java
  65. 47 0
      fs-service/src/main/java/com/fs/foods/param/FoodRecordAddParam.java
  66. 48 0
      fs-service/src/main/java/com/fs/foods/param/FoodRecordEditParam.java
  67. 57 0
      fs-service/src/main/java/com/fs/foods/param/FoodRecordQueryParam.java
  68. 90 0
      fs-service/src/main/java/com/fs/foods/service/IFsFoodRecordService.java
  69. 179 0
      fs-service/src/main/java/com/fs/foods/service/impl/FsFoodRecordServiceImpl.java
  70. 66 0
      fs-service/src/main/java/com/fs/his/config/HealthIndicatorConfig.java
  71. 55 0
      fs-service/src/main/java/com/fs/his/domain/FsAttachment.java
  72. 63 0
      fs-service/src/main/java/com/fs/his/domain/FsHfpayConfig.java
  73. 4 7
      fs-service/src/main/java/com/fs/his/domain/FsUser.java
  74. 74 0
      fs-service/src/main/java/com/fs/his/domain/FsUserHealthData.java
  75. 98 0
      fs-service/src/main/java/com/fs/his/domain/FsUserHealthProfile.java
  76. 225 0
      fs-service/src/main/java/com/fs/his/domain/FsUserInfo.java
  77. 53 0
      fs-service/src/main/java/com/fs/his/domain/FsUserItinerary.java
  78. 55 0
      fs-service/src/main/java/com/fs/his/domain/FsUserPayCompetitorsRecord.java
  79. 62 0
      fs-service/src/main/java/com/fs/his/domain/FsUserPayRecord.java
  80. 55 0
      fs-service/src/main/java/com/fs/his/dto/FsUserHealthInfoDTO.java
  81. 36 0
      fs-service/src/main/java/com/fs/his/enums/HealthDataLevelEnum.java
  82. 45 0
      fs-service/src/main/java/com/fs/his/enums/HealthDataTypeEnum.java
  83. 69 0
      fs-service/src/main/java/com/fs/his/mapper/FsAttachmentMapper.java
  84. 7 0
      fs-service/src/main/java/com/fs/his/mapper/FsDoctorMapper.java
  85. 61 0
      fs-service/src/main/java/com/fs/his/mapper/FsHfpayConfigMapper.java
  86. 74 0
      fs-service/src/main/java/com/fs/his/mapper/FsUserHealthDataMapper.java
  87. 46 0
      fs-service/src/main/java/com/fs/his/mapper/FsUserHealthProfileMapper.java
  88. 54 0
      fs-service/src/main/java/com/fs/his/mapper/FsUserInfoMapper.java
  89. 61 0
      fs-service/src/main/java/com/fs/his/mapper/FsUserItineraryMapper.java
  90. 10 1
      fs-service/src/main/java/com/fs/his/mapper/FsUserMapper.java
  91. 54 0
      fs-service/src/main/java/com/fs/his/mapper/FsUserPayCompetitorsRecordMapper.java
  92. 54 0
      fs-service/src/main/java/com/fs/his/mapper/FsUserPayRecordMapper.java
  93. 38 0
      fs-service/src/main/java/com/fs/his/param/FsAttachmentPageParam.java
  94. 1 1
      fs-service/src/main/java/com/fs/his/param/FsPackageOrderDoPayParam.java
  95. 70 0
      fs-service/src/main/java/com/fs/his/service/IFsAttachmentService.java
  96. 2 0
      fs-service/src/main/java/com/fs/his/service/IFsDoctorService.java
  97. 61 0
      fs-service/src/main/java/com/fs/his/service/IFsHfpayConfigService.java
  98. 104 0
      fs-service/src/main/java/com/fs/his/service/IFsUserHealthDataService.java
  99. 45 0
      fs-service/src/main/java/com/fs/his/service/IFsUserHealthProfileService.java
  100. 51 0
      fs-service/src/main/java/com/fs/his/service/IFsUserInfoService.java

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

@@ -14,7 +14,6 @@ import org.springframework.transaction.annotation.Transactional;
  * 启动程序
  */
 @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
-@Transactional
 @EnableAsync
 @EnableScheduling
 public class FSApplication

+ 2 - 2
fs-admin/src/main/java/com/fs/api/controller/IndexStatisticsController.java

@@ -64,10 +64,10 @@ public class IndexStatisticsController {
     @GetMapping("/trafficLog")
     public R getTrafficLog(){
         TrafficLogDTO trafficLogDTO = redisCache.getCacheObject(DATA_OVERVIEW_TRAFFIC_LOG);
-        if(trafficLogDTO == null) {
+        SysConfig sysConfig = sysConfigService.selectConfigByConfigKey("redPacket.Traffic.config");
+        if(trafficLogDTO == null || sysConfig == null) {
             return null;
         }
-        SysConfig sysConfig = sysConfigService.selectConfigByConfigKey("redPacket.Traffic.config");
         String configValue = sysConfig.getConfigValue();
         trafficLogDTO.setTraffic(configValue);
         return R.ok().put("data",trafficLogDTO);

+ 2 - 2
fs-admin/src/main/java/com/fs/course/controller/FsUserWatchCourseStatisticsController.java

@@ -118,9 +118,9 @@ public class FsUserWatchCourseStatisticsController extends BaseController
     }
 
     /**
-     * 导出会员看课统计-按课程汇总统计列表
+     * 导出会员观看数据明细汇总
      */
-    @Log(title = "会员看课统计-按课程汇总统计", businessType = BusinessType.EXPORT)
+    @Log(title = "会员观看数据明细汇总", businessType = BusinessType.EXPORT)
     @GetMapping("/exportTotal")
     public AjaxResult exportTotal(FsUserWatchCourseStatistics fsUserWatchCourseStatistics)
     {

+ 146 - 0
fs-admin/src/main/java/com/fs/his/controller/FoodRecordController.java

@@ -0,0 +1,146 @@
+package com.fs.his.controller;
+
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.utils.StringUtils;
+import com.fs.foods.domain.FsFoodRecord;
+import com.fs.foods.param.FoodRecordAddParam;
+import com.fs.foods.param.FoodRecordEditParam;
+import com.fs.foods.param.FoodRecordQueryParam;
+import com.fs.foods.service.IFsFoodRecordService;
+import com.fs.his.mapper.FsUserMapper;
+import com.fs.store.service.cache.IFsUserCacheService;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.validation.Valid;
+import java.util.List;
+
+/**
+ * 饮食记录控制器
+ */
+@Api("饮食记录管理")
+@RestController
+@Slf4j
+@RequestMapping(value = "/food-record")
+public class FoodRecordController extends BaseController {
+
+    @Autowired
+    private IFsFoodRecordService foodRecordService;
+
+    /**
+     * 获取用户饮食记录详情
+     */
+    @ApiOperation("获取饮食记录详情")
+    @GetMapping("/getRecordInfo/{id}")
+    public R getRecordInfo(@PathVariable Long id, HttpServletRequest request) {
+        FsFoodRecord record = foodRecordService.selectFsFoodRecordById(id);
+        return R.ok().put("data",record);
+    }
+
+
+    /**
+     * 获取用户饮食记录分页列表
+     */
+    @ApiOperation("获取用户饮食记录列表")
+    @GetMapping("/getMyRecordList")
+    public R getMyRecordList(FoodRecordQueryParam param, HttpServletRequest request) {
+        try {
+            PageHelper.startPage(param.getPageNum(), param.getPageSize());
+            List<FsFoodRecord> list = foodRecordService.selectFoodRecordList(param);
+            PageInfo<FsFoodRecord> listPageInfo = new PageInfo<>(list);
+            return R.ok().put("data", listPageInfo);
+        } catch (Exception e) {
+            log.error("获取饮食记录列表异常:", e);
+            return R.error("操作异常");
+        }
+    }
+
+    /**
+     * 新增饮食记录
+     */
+    @ApiOperation("新增饮食记录")
+    @PostMapping("/addRecord")
+    public R addRecord(@RequestBody @Valid FoodRecordAddParam param, HttpServletRequest request) {
+        try {
+            log.info("【新增饮食记录】:{}", param);
+
+            if (StringUtils.isEmpty(param.getMealDescription())) {
+                return R.error("用餐描述不能为空");
+            }
+
+            FsFoodRecord record = new FsFoodRecord();
+            BeanUtils.copyProperties(param, record);
+
+            if (foodRecordService.insertFsFoodRecord(record) > 0) {
+                return R.ok("添加成功");
+            } else {
+                return R.error("添加失败");
+            }
+        } catch (Exception e) {
+            log.error("新增饮食记录异常:", e);
+            return R.error("操作异常");
+        }
+    }
+
+    /**
+     * 修改饮食记录
+     */
+    @ApiOperation("修改饮食记录")
+    @PostMapping("/editRecord")
+    public R editRecord(@RequestBody @Valid FoodRecordEditParam param, HttpServletRequest request) {
+        try {
+            log.info("【修改饮食记录】:{}", param);
+
+            FsFoodRecord record = new FsFoodRecord();
+            BeanUtils.copyProperties(param, record);
+
+            if (foodRecordService.updateFsFoodRecord(record) > 0) {
+                return R.ok("修改成功");
+            } else {
+                return R.error("修改失败");
+            }
+        } catch (Exception e) {
+            log.error("修改饮食记录异常:", e);
+            return R.error("操作异常");
+        }
+    }
+
+    /**
+     * 删除饮食记录
+     */
+    @ApiOperation("删除饮食记录")
+    @PostMapping("/deleteRecord/{id}")
+    public R deleteRecord(@PathVariable("id") Long id, HttpServletRequest request) {
+        foodRecordService.deleteFsFoodRecordById(id);
+        return R.ok();
+    }
+
+
+    @Autowired
+    private IFsUserCacheService fsUserCacheService;
+    /**
+     * 管理端查询饮食记录列表
+     */
+    @ApiOperation("管理端查询饮食记录")
+    @GetMapping("/admin/list")
+    public TableDataInfo adminList(FoodRecordQueryParam param) {
+        startPage();
+        List<FsFoodRecord> list = foodRecordService.selectFoodRecordList(param);
+        for (FsFoodRecord fsFoodRecord : list) {
+            String fsUserName = fsUserCacheService.selectUserNameById(fsFoodRecord.getUserId());
+            if(StringUtils.isNotEmpty(fsUserName)){
+                fsFoodRecord.setUsername(fsUserName);
+            }
+        }
+        return getDataTable(list);
+    }
+}

+ 106 - 0
fs-admin/src/main/java/com/fs/his/controller/FsComplaintCategoryController.java

@@ -0,0 +1,106 @@
+package com.fs.his.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.complaint.domain.FsComplaintCategory;
+import com.fs.complaint.mapper.FsComplaintCategoryMapper;
+import com.fs.complaint.param.FsComplaintCategoryParam;
+import com.fs.complaint.service.FsComplaintCategoryService;
+import com.fs.complaint.vo.FsComplaintCategoryListVO;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@Slf4j
+@Api("投诉接口")
+@RestController
+@RequestMapping(value="/complaint")
+public class FsComplaintCategoryController extends BaseController {
+
+    @Autowired
+    private FsComplaintCategoryMapper fsComplaintCategoryMapper;
+
+    @Autowired
+    private FsComplaintCategoryService fsComplaintCategoryService;
+
+
+    /**
+     * 查询投诉分类列表
+     */
+    @ApiOperation("查询投诉分类列表")
+    @PreAuthorize("@ss.hasPermi('complaint:category:list')")
+    @GetMapping("/category/list")
+    public TableDataInfo list(FsComplaintCategoryParam param)
+    {
+        startPage();
+        List<FsComplaintCategoryListVO> list = fsComplaintCategoryMapper.selectFsComplaintCategoryListVO(param);
+        return getDataTable(list);
+    }
+    /**
+     * 根据ID查询投诉分类详情
+     */
+    @ApiOperation("查询投诉分类详情")
+    @PreAuthorize("@ss.hasPermi('complaint:category:query')")
+    @GetMapping("/category/{id}")
+    public R getInfo(@PathVariable("id") Long id)
+    {
+        return R.ok().put("data",fsComplaintCategoryService.selectFsComplaintCategoryById(id));
+    }
+
+    /**
+     * 新增投诉分类
+     */
+    @ApiOperation("新增投诉分类")
+    @PreAuthorize("@ss.hasPermi('complaint:category:add')")
+    @Log(title = "投诉分类", businessType = BusinessType.INSERT)
+    @PostMapping("/category")
+    public R add(@RequestBody FsComplaintCategory fsComplaintCategory)
+    {
+        fsComplaintCategoryService.insertFsComplaintCategory(fsComplaintCategory);
+        return R.ok();
+    }
+    @ApiOperation("修改投诉分类")
+    @PreAuthorize("@ss.hasPermi('complaint:category:edit')")
+    @Log(title = "投诉分类", businessType = BusinessType.UPDATE)
+    @PutMapping("/category")
+    public R edit(@RequestBody FsComplaintCategory fsComplaintCategory)
+    {
+        log.info("修改投诉分类 参数:{}",fsComplaintCategory);
+        fsComplaintCategoryService.updateFsComplaintCategory(fsComplaintCategory);
+        return R.ok();
+    }
+    /**
+     * 删除投诉分类
+     */
+    @ApiOperation("删除投诉分类")
+    @PreAuthorize("@ss.hasPermi('complaint:category:remove')")
+    @Log(title = "投诉分类", businessType = BusinessType.DELETE)
+    @DeleteMapping("/category/{ids}")
+    public R remove(@PathVariable Long[] ids)
+    {
+        fsComplaintCategoryService.deleteFsComplaintCategoryByIds(ids);
+        return R.ok();
+    }
+    /**
+     * 修改投诉分类状态
+     */
+    @ApiOperation("修改投诉分类状态")
+    @PreAuthorize("@ss.hasPermi('complaint:category:edit')")
+    @Log(title = "投诉分类状态", businessType = BusinessType.UPDATE)
+    @PutMapping("/category/status")
+    public R changeStatus(@RequestBody FsComplaintCategory fsComplaintCategory)
+    {
+        log.info("投诉分类状态 参数:{}",fsComplaintCategory);
+        fsComplaintCategoryService.updateFsComplaintCategoryStatus(fsComplaintCategory);
+        return R.ok();
+    }
+
+}

+ 93 - 0
fs-admin/src/main/java/com/fs/his/controller/FsComplaintController.java

@@ -0,0 +1,93 @@
+package com.fs.his.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.complaint.domain.FsComplaint;
+import com.fs.complaint.domain.FsComplaintCategory;
+import com.fs.complaint.dto.ComplaintQueryDTO;
+import com.fs.complaint.dto.SubmitComplaintDTO;
+import com.fs.complaint.dto.UpdateComplaintDTO;
+import com.fs.complaint.mapper.FsComplaintCategoryMapper;
+import com.fs.complaint.mapper.FsComplaintMapper;
+import com.fs.complaint.param.FsComplaintCategoryParam;
+import com.fs.complaint.service.FsComplaintCategoryService;
+import com.fs.complaint.service.FsComplaintService;
+import com.fs.complaint.vo.ComplaintVO;
+import com.fs.complaint.vo.FsComplaintCategoryListVO;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+import shade.kotlin.Result;
+
+import javax.validation.Valid;
+import java.util.List;
+
+@Slf4j
+@Api("投诉接口")
+@RestController
+@RequestMapping(value="/complaint")
+public class FsComplaintController extends BaseController {
+
+    @Autowired
+    private FsComplaintService fsComplaintService;
+    @Autowired
+    private FsComplaintCategoryService fsComplaintCategoryService;
+
+    /**
+     * 查询所有投诉分类
+     * @return R
+     */
+    @PostMapping("/queryAllCategory")
+    public R queryAllCategory(){
+        List<FsComplaintCategory> categoryList = fsComplaintCategoryService.queryAllCategory();
+        return R.ok().put("data",categoryList);
+    }
+
+    @ApiOperation("提交投诉")
+    @PostMapping
+    public R submitComplaint(@Valid @RequestBody SubmitComplaintDTO dto) {
+        fsComplaintService.submitComplaint(dto);
+        return R.ok();
+    }
+
+    @ApiOperation("根据ID查询投诉详情")
+    @GetMapping("/{id}")
+    public R getComplaintById(@PathVariable Long id) {
+        ComplaintVO complaintVO = fsComplaintService.getComplaintById(id);
+        return R.ok().put("data", complaintVO);
+    }
+    @ApiOperation("根据投诉单号查询投诉详情")
+    @GetMapping("/no/{complaintNo}")
+    public R getComplaintByNo(@PathVariable String complaintNo) {
+        ComplaintVO complaintVO = fsComplaintService.getComplaintByNo(complaintNo);
+        return R.ok().put("data", complaintVO);
+    }
+    @ApiOperation("分页查询投诉列表")
+    @PostMapping("/list")
+    public TableDataInfo getComplaintPage(@RequestBody ComplaintQueryDTO queryDTO) {
+        startPage();
+
+        List<FsComplaint> result = fsComplaintService.getComplaintPage(queryDTO);
+
+        return getDataTable(result);
+    }
+    @ApiOperation("更新投诉信息")
+    @PutMapping("/{id}")
+    public R updateComplaint(@PathVariable Long id, @Valid @RequestBody UpdateComplaintDTO dto) {
+        fsComplaintService.updateComplaint(id, dto);
+        return R.ok();
+    }
+    @ApiOperation("删除投诉")
+    @DeleteMapping("/{id}")
+    public R deleteComplaint(@PathVariable Long id) {
+        fsComplaintService.deleteComplaint(id);
+        return R.ok();
+    }
+
+}

+ 103 - 0
fs-admin/src/main/java/com/fs/his/controller/FsHfpayConfigController.java

@@ -0,0 +1,103 @@
+package com.fs.his.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.his.domain.FsHfpayConfig;
+import com.fs.his.service.IFsHfpayConfigService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 汇付多支付配置Controller
+ * 
+ * @author fs
+ * @date 2025-09-10
+ */
+@RestController
+@RequestMapping("/his/hfpayConfig")
+public class FsHfpayConfigController extends BaseController
+{
+    @Autowired
+    private IFsHfpayConfigService fsHfpayConfigService;
+
+    /**
+     * 查询汇付多支付配置列表
+     */
+    @PreAuthorize("@ss.hasPermi('his:hfpayConfig:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsHfpayConfig fsHfpayConfig)
+    {
+        startPage();
+        List<FsHfpayConfig> list = fsHfpayConfigService.selectFsHfpayConfigList(fsHfpayConfig);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出汇付多支付配置列表
+     */
+    @PreAuthorize("@ss.hasPermi('his:hfpayConfig:export')")
+    @Log(title = "汇付多支付配置", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsHfpayConfig fsHfpayConfig)
+    {
+        List<FsHfpayConfig> list = fsHfpayConfigService.selectFsHfpayConfigList(fsHfpayConfig);
+        ExcelUtil<FsHfpayConfig> util = new ExcelUtil<FsHfpayConfig>(FsHfpayConfig.class);
+        return util.exportExcel(list, "汇付多支付配置数据");
+    }
+
+    /**
+     * 获取汇付多支付配置详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('his:hfpayConfig:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsHfpayConfigService.selectFsHfpayConfigById(id));
+    }
+
+    /**
+     * 新增汇付多支付配置
+     */
+    @PreAuthorize("@ss.hasPermi('his:hfpayConfig:add')")
+    @Log(title = "汇付多支付配置", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsHfpayConfig fsHfpayConfig)
+    {
+        return toAjax(fsHfpayConfigService.insertFsHfpayConfig(fsHfpayConfig));
+    }
+
+    /**
+     * 修改汇付多支付配置
+     */
+    @PreAuthorize("@ss.hasPermi('his:hfpayConfig:edit')")
+    @Log(title = "汇付多支付配置", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsHfpayConfig fsHfpayConfig)
+    {
+        return toAjax(fsHfpayConfigService.updateFsHfpayConfig(fsHfpayConfig));
+    }
+
+    /**
+     * 删除汇付多支付配置
+     */
+    @PreAuthorize("@ss.hasPermi('his:hfpayConfig:remove')")
+    @Log(title = "汇付多支付配置", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsHfpayConfigService.deleteFsHfpayConfigByIds(ids));
+    }
+}

+ 1 - 1
fs-admin/src/main/java/com/fs/his/controller/FsStoreOrderController.java

@@ -656,7 +656,7 @@ public class FsStoreOrderController extends BaseController
             if (param.getUserPhoneMk() != null && !param.getUserPhoneMk().isEmpty()) {
                 param.setUserPhone(encryptPhone(param.getUserPhoneMk()));
             }
-            List<FsStoreOrderListVO> list = fsStoreOrderService.selectFsStoreOrderListVO(param);
+            List<FsStoreOrderListVO> list = fsStoreOrderService.selectFsStoreOrderListVOByErpAccount(param);
             orderIds = list.stream().map(FsStoreOrderListVO::getOrderId).collect(Collectors.toList());
         }
         if (orderIds.isEmpty()){

+ 120 - 0
fs-admin/src/main/java/com/fs/his/controller/FsTodoItemsController.java

@@ -0,0 +1,120 @@
+package com.fs.his.controller;
+
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.R;
+import com.fs.common.utils.SecurityUtils;
+import com.fs.common.utils.ServletUtils;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.service.ICompanyUserService;
+import com.fs.todo.domain.FsTodoItems;
+import com.fs.todo.dto.TodoCategoryStatisticsDTO;
+import com.fs.todo.param.AssignExecutorParam;
+import com.fs.todo.param.GetUserListParam;
+import com.fs.todo.param.QueryTodoItemsParam;
+import com.fs.todo.service.FsTodoItemsService;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Map;
+
+@Api("待办")
+@RestController
+@RequestMapping(value="/todoItems")
+public class FsTodoItemsController extends BaseController {
+
+    @Autowired
+    private FsTodoItemsService fsTodoItemsService;
+
+    @Autowired
+    private ICompanyUserService companyUserService;
+
+    @ApiOperation("查看待办列表")
+    @PostMapping("/listPage")
+    public R listPage(@RequestBody QueryTodoItemsParam param)
+    {
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        List<FsTodoItems> fsTodoItems = fsTodoItemsService.listPage(param);
+        PageInfo<FsTodoItems> listPageInfo=new PageInfo<>(fsTodoItems);
+        return R.ok().put("data",listPageInfo);
+    }
+
+    @ApiOperation("查看详情")
+    @PostMapping("/findById")
+    public R findById(@RequestBody QueryTodoItemsParam param)
+    {
+        if(ObjectUtils.isNull(param.getId())){
+            throw new IllegalArgumentException("待办事项id不能为空!");
+        }
+        FsTodoItems byId = fsTodoItemsService.getById(param.getId());
+        return R.ok().put("data",byId);
+    }
+
+
+    @ApiOperation("更新待办事项状态")
+    @PostMapping("/updateStatusById")
+    public R updateStatusById(@RequestBody QueryTodoItemsParam param)
+    {
+        if(ObjectUtils.isNull(param.getId())){
+            throw new IllegalArgumentException("待办事项id不能为空!");
+        }
+        fsTodoItemsService.updateStatus(param.getId(),param.getStatus());
+        return R.ok();
+    }
+    @ApiOperation("更新待办事项")
+    @PostMapping("/updateById")
+    public R updateById(@RequestBody FsTodoItems param)
+    {
+        if(ObjectUtils.isNull(param.getId())){
+            throw new IllegalArgumentException("待办事项id不能为空!");
+        }
+        fsTodoItemsService.updateById(param);
+        return R.ok();
+    }
+
+
+    @ApiOperation("删除待办事项")
+    @PostMapping("/removeById")
+    public R removeById(@RequestBody QueryTodoItemsParam param){
+        fsTodoItemsService.removeById(param.getId());
+        return R.ok();
+    }
+
+    @ApiOperation("添加待办事项")
+    @PostMapping("/add")
+    public R addTodoItems(@RequestBody FsTodoItems param){
+        param.setCreateTime(LocalDateTime.now());
+        param.setUpdateTime(LocalDateTime.now());
+        param.setCreatorId(getUserId());
+        fsTodoItemsService.save(param);
+        return R.ok();
+    }
+
+    @ApiOperation("添加待办事项")
+    @PostMapping("/assignExecutor")
+    public R assignExecutor(@RequestBody AssignExecutorParam param){
+        param.setAssigneeId(SecurityUtils.getUserId());
+
+        fsTodoItemsService.assignExecutor(param);
+        return R.ok();
+    }
+
+    @PostMapping("/getUserList")
+    public R getUserList(@RequestBody GetUserListParam param)
+    {
+
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+
+        CompanyUser map=new CompanyUser();
+        map.setCompanyId(param.getCompanyId());
+        List<CompanyUser> list = companyUserService.selectCompanyUserList(map);
+        return  R.ok().put("data",list);
+    }
+
+}

+ 3 - 0
fs-admin/src/main/java/com/fs/his/controller/FsUserController.java

@@ -139,6 +139,9 @@ public class FsUserController extends BaseController
     public TableDataInfo listProject(FsUser fsUser)
     {
         startPage();
+        if(StringUtils.isNotEmpty(fsUser.getPhone())){
+            fsUser.setPhone(encryptPhone(fsUser.getPhone()));
+        }
         List<FsUserVO> list = fsUserService.selectFsUserVOListByProject(fsUser);
         boolean checkPhone = isCheckPhone();
         for (FsUserVO fsUserVO : list) {

+ 102 - 0
fs-admin/src/main/java/com/fs/his/controller/RechargeTemplateController.java

@@ -0,0 +1,102 @@
+package com.fs.his.controller;
+
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.core.redis.RedisCache;
+import com.fs.his.param.FsCouponListUParam;
+import com.fs.his.service.IFsCouponService;
+import com.fs.his.service.IFsUserCouponService;
+import com.fs.his.vo.FsCouponListUVO;
+import com.fs.recharge.domain.RechargeTemplate;
+import com.fs.recharge.param.RechargeParam;
+import com.fs.recharge.param.RechargeTemplateQuery;
+import com.fs.recharge.service.RechargeTemplateService;
+import com.fs.recharge.vo.RechargeTemplateVO;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 充值模板控制器
+ */
+@Slf4j
+@Api(tags = "充值模板管理")
+@RestController
+@RequestMapping("/recharge-templates")
+public class RechargeTemplateController extends BaseController {
+
+    @Autowired
+    private RechargeTemplateService rechargeTemplateService;
+    @Autowired
+    private IFsCouponService couponService;
+
+    @ApiOperation("获取可用的充值模板列表")
+    @PostMapping("/list")
+    public TableDataInfo getValidTemplates(@RequestBody RechargeTemplateQuery query) {
+        log.info("获取可用的充值模板列表 参数 query: {}",query);
+
+        Integer pageNum = query.getPageNum();
+        Integer pageSize = query.getPageSize();
+
+        PageHelper.startPage(pageNum, pageSize);
+
+        List<RechargeTemplateVO> templates = rechargeTemplateService.queryList(query);
+        return getDataTable(templates);
+    }
+
+    @ApiOperation("获取充值模板详情")
+    @GetMapping("/{id}")
+    public R getTemplateDetail(
+            @ApiParam(value = "模板ID", required = true) @PathVariable Long id) {
+        RechargeTemplateVO template = rechargeTemplateService.getTemplateDetail(id);
+        if (template == null) {
+            return R.error("模板不存在");
+        }
+        return R.ok().put("data",template);
+    }
+
+    @ApiOperation("创建充值模板")
+    @PostMapping
+    public R createTemplate(@RequestBody RechargeTemplate template) {
+        boolean success = rechargeTemplateService.createTemplate(template);
+        return R.ok();
+    }
+
+    @ApiOperation("更新充值模板")
+    @PutMapping("/{id}")
+    public R updateTemplate(
+            @ApiParam(value = "模板ID", required = true) @PathVariable Long id,
+            @RequestBody RechargeTemplate template) {
+        template.setId(id);
+        boolean success = rechargeTemplateService.updateTemplate(template);
+        return R.ok();
+    }
+
+    @ApiOperation("启用或禁用充值模板")
+    @PutMapping("/{id}/status")
+    public R updateStatus(
+            @ApiParam(value = "模板ID", required = true) @PathVariable Long id,
+            @ApiParam(value = "状态:0-禁用,1-启用", required = true) @RequestParam Integer status) {
+        boolean success = rechargeTemplateService.updateStatus(id, status);
+        return R.ok();
+    }
+
+
+    @ApiOperation("获取优惠券列表")
+    @GetMapping("/getCouponList")
+    public R getCouponList(FsCouponListUParam param)
+    {
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        List<FsCouponListUVO> list=couponService.selectFsCouponListUVO(param);
+        PageInfo<FsCouponListUVO> listPageInfo=new PageInfo<>(list);
+        return R.ok().put("data",listPageInfo);
+    }
+}

+ 17 - 0
fs-admin/src/main/java/com/fs/his/task/FsUserTask.java

@@ -0,0 +1,17 @@
+package com.fs.his.task;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+@Slf4j
+@Service("fsUserTask")
+public class FsUserTask {
+
+    /**
+     * 推广员自动升级
+     */
+    public void promoterAutoUpgrade(){
+
+    }
+
+}

+ 134 - 0
fs-admin/src/main/java/com/fs/hisStore/FsStoreSCRMController.java

@@ -0,0 +1,134 @@
+package com.fs.hisStore;
+
+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.his.domain.FsStore;
+import com.fs.his.param.FsStoreAuditParam;
+import com.fs.his.service.IFsStoreService;
+import com.fs.hisStore.domain.FsStoreScrm;
+import com.fs.hisStore.service.IFsStoreScrmService;
+import com.fs.hisStore.vo.FsStoreScrmVO;
+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 2023-06-15
+ */
+@RestController
+@RequestMapping("/store/store")
+public class FsStoreSCRMController extends BaseController
+{
+    @Autowired
+    private IFsStoreScrmService fsStoreService;
+
+    /**
+     * 查询店铺管理列表
+     */
+    @PreAuthorize("@ss.hasPermi('store:store:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsStoreScrm fsStore)
+    {
+        startPage();
+        List<FsStoreScrm> list = fsStoreService.selectFsStoreList(fsStore);
+        for (FsStoreScrm store : list) {
+            store.setPhone(ParseUtils.parsePhone(store.getPhone()));
+        }
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出店铺管理列表
+     */
+    @PreAuthorize("@ss.hasPermi('store:store:export')")
+    @Log(title = "店铺管理", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsStoreScrm fsStore)
+    {
+        List<FsStoreScrm> list = fsStoreService.selectFsStoreList(fsStore);
+        for (FsStoreScrm store : list) {
+            store.setPhone(ParseUtils.parsePhone(store.getPhone()));
+        }
+        ExcelUtil<FsStoreScrm> util = new ExcelUtil<FsStoreScrm>(FsStoreScrm.class);
+        return util.exportExcel(list, "店铺管理数据");
+    }
+
+    /**
+     * 获取店铺管理详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('store:store:query')")
+    @GetMapping(value = "/{storeId}")
+    public AjaxResult getInfo(@PathVariable("storeId") Long storeId)
+    {
+        FsStoreScrm fsStore = fsStoreService.selectFsStoreByStoreId(storeId);
+        fsStore.setPhone(ParseUtils.parsePhone(fsStore.getPhone()));
+        return AjaxResult.success(fsStore);
+    }
+
+    /**
+     * 新增店铺管理
+     */
+    @PreAuthorize("@ss.hasPermi('store:store:add')")
+    @Log(title = "店铺管理", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsStoreScrm fsStore)
+    {
+        return toAjax(fsStoreService.insertFsStore(fsStore));
+    }
+
+    /**
+     * 修改店铺管理
+     */
+    @PreAuthorize("@ss.hasPermi('store:store:edit')")
+    @Log(title = "店铺管理", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsStoreScrm fsStore)
+    {
+
+        if (fsStore.getPhone()!=null&&fsStore.getPhone().contains("*")){
+            fsStore.setPhone(null);
+        }
+        return toAjax(fsStoreService.updateFsStore(fsStore));
+    }
+
+    /**
+     * 删除店铺管理
+     */
+    @PreAuthorize("@ss.hasPermi('store:store:remove')")
+    @Log(title = "店铺管理", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{storeIds}")
+    public AjaxResult remove(@PathVariable Long[] storeIds)
+    {
+        return toAjax(fsStoreService.deleteFsStoreByStoreIds(storeIds));
+    }
+
+    /**
+     * 店铺审核
+     */
+    @PreAuthorize("@ss.hasPermi('store:store:audit')")
+    @Log(title = "店铺管理", businessType = BusinessType.UPDATE)
+    @PutMapping("/audit")
+    public AjaxResult audit(@RequestBody FsStoreAuditParam fsStore)
+    {
+        return toAjax(fsStoreService.updateFsStoreAudit(fsStore));
+    }
+
+    @GetMapping("/storeList")
+    public R storeList(){
+        List<FsStoreScrmVO> list = fsStoreService.selectAllStore();
+        return R.ok().put("data",list);
+    }
+
+
+}

+ 4 - 3
fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreProductScrmController.java

@@ -8,6 +8,7 @@ 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.param.FormatAttrParam;
 import com.fs.hisStore.vo.FsStoreProductAttrValueVO;
 import com.fs.hisStore.vo.FsStoreProductExportVO;
 import com.fs.hisStore.vo.FsStoreProductListVO;
@@ -72,7 +73,7 @@ public class FsStoreProductScrmController extends BaseController
     /**
      * 查询商品列表
      */
-    @PreAuthorize("@ss.hasPermi('store:storeProduct:list')")
+//    @PreAuthorize("@ss.hasPermi('store:storeProduct:list')")
     @GetMapping("/list")
     public TableDataInfo list(FsStoreProductScrm fsStoreProduct)
     {
@@ -169,8 +170,8 @@ public class FsStoreProductScrmController extends BaseController
 
     @ApiOperation(value = "生成属性")
     @PostMapping(value = "/genFormatAttr/{productId}")
-    public ResponseEntity genFormatAttr(@PathVariable Long productId, @RequestBody String jsonStr){
-        return new ResponseEntity<>(fsStoreProductService.getFormatAttr(productId,jsonStr), HttpStatus.OK);
+    public ResponseEntity genFormatAttr(@PathVariable Long productId,@RequestBody FormatAttrParam param){
+        return new ResponseEntity<>(fsStoreProductService.getFormatAttr(productId,param.getAttrs(),param.getStores()), HttpStatus.OK);
     }
 
 

+ 155 - 0
fs-admin/src/main/java/com/fs/medical/MeasurementUnitController.java

@@ -0,0 +1,155 @@
+package com.fs.medical;
+
+import com.fs.common.annotation.RepeatSubmit;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.R;
+import com.fs.medical.domain.MeasurementUnit;
+import com.fs.medical.param.MeasurementUnitQueryDto;
+import com.fs.medical.service.MeasurementUnitService;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 计量单位Controller
+ *
+ * @author fs
+ * @date 2024
+ */
+@Api("计量单位")
+@RestController
+@RequestMapping("/admin/medical/unit")
+public class MeasurementUnitController extends BaseController {
+    private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+    @Autowired
+    private MeasurementUnitService measurementUnitService;
+
+    /**
+     * 查询所有计量单位
+     */
+    @ApiOperation("查询所有计量单位")
+    @GetMapping("/listAll")
+    public R listAll() {
+        try {
+            List<MeasurementUnit> list = measurementUnitService.listAll();
+            return R.ok().put("data",list);
+        } catch (Exception e) {
+            logger.error("查询计量单位失败", e);
+            return R.error("查询失败");
+        }
+    }
+
+    /**
+     * 分页查询计量单位列表(带筛选)
+     */
+    @ApiOperation("分页查询计量单位列表")
+    @GetMapping("/page")
+    public R page(MeasurementUnitQueryDto queryDto) {
+        try {
+            PageHelper.startPage(queryDto.getPageNum(), queryDto.getPageSize());
+            List<MeasurementUnit> list = measurementUnitService.selectPageList(queryDto);
+            PageInfo<MeasurementUnit> pageInfo = new PageInfo<>(list);
+            return R.ok().put("data", pageInfo);
+        } catch (Exception e) {
+            logger.error("分页查询计量单位失败", e);
+            return R.error("查询失败");
+        }
+    }
+
+    /**
+     * 根据单位类型查询计量单位
+     */
+    @ApiOperation("根据单位类型查询计量单位")
+    @GetMapping("/listByType")
+    public R listByType(@RequestParam String unitType) {
+        try {
+            List<MeasurementUnit> list = measurementUnitService.listByType(unitType);
+            return R.ok().put("data",list);
+        } catch (Exception e) {
+            logger.error("根据类型查询计量单位失败", e);
+            return R.error("查询失败");
+        }
+    }
+
+    /**
+     * 根据ID查询计量单位详情
+     */
+    @ApiOperation("根据ID查询计量单位详情")
+    @GetMapping("/{unitId}")
+    public R getById(@PathVariable("unitId") Long unitId) {
+        try {
+            MeasurementUnit unit = measurementUnitService.getById(unitId);
+            return R.ok().put("data",unit);
+        } catch (Exception e) {
+            logger.error("查询计量单位详情失败", e);
+            return R.error("查询失败");
+        }
+    }
+
+    /**
+     * 新增计量单位
+     */
+    @RepeatSubmit
+    @ApiOperation("新增计量单位")
+    @PostMapping("/add")
+    public R add(@RequestBody MeasurementUnit unit) {
+        try {
+            boolean result = measurementUnitService.save(unit);
+            if (result) {
+                return R.ok("新增成功");
+            } else {
+                return R.error("新增失败");
+            }
+        } catch (Exception e) {
+            logger.error("新增计量单位失败", e);
+            return R.error("新增失败");
+        }
+    }
+
+    /**
+     * 更新计量单位
+     */
+    @RepeatSubmit
+    @ApiOperation("更新计量单位")
+    @PutMapping("/update")
+    public R update(@RequestBody MeasurementUnit unit) {
+        try {
+            boolean result = measurementUnitService.update(unit);
+            if (result) {
+                return R.ok("更新成功");
+            } else {
+                return R.error("更新失败");
+            }
+        } catch (Exception e) {
+            logger.error("更新计量单位失败", e);
+            return R.error("更新失败");
+        }
+    }
+
+    /**
+     * 删除计量单位
+     */
+    @ApiOperation("删除计量单位")
+    @DeleteMapping("/{unitId}")
+    public R delete(@PathVariable("unitId") Long unitId) {
+        try {
+            boolean result = measurementUnitService.deleteById(unitId);
+            if (result) {
+                return R.ok("删除成功");
+            } else {
+                return R.error("删除失败");
+            }
+        } catch (Exception e) {
+            logger.error("删除计量单位失败", e);
+            return R.error("删除失败");
+        }
+    }
+}

+ 157 - 0
fs-admin/src/main/java/com/fs/medical/MedicalIndicatorController.java

@@ -0,0 +1,157 @@
+package com.fs.medical;
+
+import com.fs.common.annotation.RepeatSubmit;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.R;
+import com.fs.medical.domain.MedicalIndicator;
+import com.fs.medical.param.MedicalIndicatorQueryDto;
+import com.fs.medical.service.MedicalIndicatorService;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 医疗指标Controller
+ *
+ * @author fs
+ * @date 2024
+ */
+@Slf4j
+@Api("医疗指标")
+@RestController
+@RequestMapping("/admin/medical/indicator")
+public class MedicalIndicatorController extends BaseController {
+    private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+    @Autowired
+    private MedicalIndicatorService medicalIndicatorService;
+
+    /**
+     * 查询所有启用的指标
+     */
+    @ApiOperation("查询所有启用的指标")
+    @GetMapping("/listEnabled")
+    public R listAllEnabled() {
+        try {
+            List<MedicalIndicator> list = medicalIndicatorService.listAllEnabled();
+            return R.ok().put("data",list);
+        } catch (Exception e) {
+            logger.error("查询启用指标失败", e);
+            return R.error("查询失败");
+        }
+    }
+
+    /**
+     * 分页查询医疗指标列表(带筛选)
+     */
+    @ApiOperation("分页查询医疗指标列表")
+    @GetMapping("/page")
+    public R page(MedicalIndicatorQueryDto queryDto) {
+        try {
+            PageHelper.startPage(queryDto.getPageNum(), queryDto.getPageSize());
+            List<MedicalIndicator> list = medicalIndicatorService.selectPageList(queryDto);
+            PageInfo<MedicalIndicator> pageInfo = new PageInfo<>(list);
+            return R.ok().put("data", pageInfo);
+        } catch (Exception e) {
+            logger.error("分页查询医疗指标失败", e);
+            return R.error("查询失败");
+        }
+    }
+
+    /**
+     * 根据分类查询指标
+     */
+    @ApiOperation("根据分类查询指标")
+    @GetMapping("/listByCategory")
+    public R listByCategory(@RequestParam String category) {
+        try {
+            List<MedicalIndicator> list = medicalIndicatorService.listByCategory(category);
+            return R.ok().put("data",list);
+        } catch (Exception e) {
+            logger.error("根据分类查询指标失败", e);
+            return R.error("查询失败");
+        }
+    }
+
+    /**
+     * 根据ID查询指标详情
+     */
+    @ApiOperation("根据ID查询指标详情")
+    @GetMapping("/{indicatorId}")
+    public R getById(@PathVariable("indicatorId") Long indicatorId) {
+        try {
+            MedicalIndicator indicator = medicalIndicatorService.getById(indicatorId);
+            return R.ok().put("data",indicator);
+        } catch (Exception e) {
+            logger.error("查询指标详情失败", e);
+            return R.error("查询失败");
+        }
+    }
+
+    /**
+     * 新增指标
+     */
+    @RepeatSubmit
+    @ApiOperation("新增指标")
+    @PostMapping("/add")
+    public R add(@RequestBody MedicalIndicator indicator) {
+        try {
+            boolean result = medicalIndicatorService.save(indicator);
+            if (result) {
+                return R.ok("新增成功");
+            } else {
+                return R.error("新增失败");
+            }
+        } catch (Exception e) {
+            logger.error("新增指标失败", e);
+            return R.error("新增失败");
+        }
+    }
+
+    /**
+     * 更新指标
+     */
+    @RepeatSubmit
+    @ApiOperation("更新指标")
+    @PutMapping("/update")
+    public R update(@RequestBody MedicalIndicator indicator) {
+        try {
+            boolean result = medicalIndicatorService.update(indicator);
+            if (result) {
+                return R.ok("更新成功");
+            } else {
+                return R.error("更新失败");
+            }
+        } catch (Exception e) {
+            logger.error("更新指标失败", e);
+            return R.error("更新失败");
+        }
+    }
+
+    /**
+     * 删除指标
+     */
+    @ApiOperation("删除指标")
+    @DeleteMapping("/{indicatorId}")
+    public R delete(@PathVariable("indicatorId") Long indicatorId) {
+        try {
+            boolean result = medicalIndicatorService.deleteById(indicatorId);
+            if (result) {
+                return R.ok("删除成功");
+            } else {
+                return R.error("删除失败");
+            }
+        } catch (Exception e) {
+            logger.error("删除指标失败", e);
+            return R.error("删除失败");
+        }
+    }
+}

+ 160 - 0
fs-admin/src/main/java/com/fs/medical/PhysicalExamReportController.java

@@ -0,0 +1,160 @@
+package com.fs.medical;
+
+import com.fs.common.annotation.RepeatSubmit;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.R;
+import com.fs.medical.domain.PhysicalExamReport;
+import com.fs.medical.param.PhysicalExamReportCompareDto;
+import com.fs.medical.param.PhysicalExamReportQueryDto;
+import com.fs.medical.service.PhysicalExamReportService;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.format.annotation.DateTimeFormat;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 体检报告Controller
+ *
+ * @author fs
+ * @date 2024
+ */
+@Api("体检报告")
+@RestController
+@RequestMapping("/admin/medical/report")
+public class PhysicalExamReportController extends BaseController {
+    private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+    @Autowired
+    private PhysicalExamReportService physicalExamReportService;
+
+    /**
+     * 根据用户ID查询体检报告列表
+     */
+    @ApiOperation("查询用户体检报告列表")
+    @GetMapping("/listByUser/{userId}")
+    public R listByUserId(@PathVariable("userId") Long userId) {
+        try {
+            List<PhysicalExamReport> list = physicalExamReportService.listByUserId(userId);
+            return R.ok().put("data",list);
+        } catch (Exception e) {
+            logger.error("查询用户体检报告失败", e);
+            return R.error("查询失败");
+        }
+    }
+
+    /**
+     * 分页查询体检报告列表(带筛选)
+     */
+    @ApiOperation("分页查询体检报告列表")
+    @GetMapping("/page")
+    public R page(PhysicalExamReportQueryDto queryDto) {
+        try {
+            PageHelper.startPage(queryDto.getPageNum(), queryDto.getPageSize());
+            List<PhysicalExamReport> list = physicalExamReportService.selectPageList(queryDto);
+            PageInfo<PhysicalExamReport> pageInfo = new PageInfo<>(list);
+            return R.ok().put("data", pageInfo);
+        } catch (Exception e) {
+            logger.error("分页查询体检报告失败", e);
+            return R.error("查询失败");
+        }
+    }
+
+    /**
+     * 根据用户ID和体检日期查询体检报告
+     */
+    @ApiOperation("根据用户ID和体检日期查询体检报告")
+    @GetMapping("/getByUserAndDate")
+    public R getByUserIdAndDate(
+            @RequestParam Long userId,
+            @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") Date examDate) {
+        try {
+            PhysicalExamReport report = physicalExamReportService.getByUserIdAndDate(userId, examDate);
+            return R.ok().put("data",report);
+        } catch (Exception e) {
+            logger.error("根据用户ID和日期查询体检报告失败", e);
+            return R.error("查询失败");
+        }
+    }
+
+    /**
+     * 根据ID查询体检报告详情
+     */
+    @ApiOperation("查询体检报告详情")
+    @GetMapping("/{reportId}")
+    public R getById(@PathVariable("reportId") Long reportId) {
+        try {
+            PhysicalExamReport report = physicalExamReportService.getById(reportId);
+            return R.ok().put("data",report);
+        } catch (Exception e) {
+            logger.error("查询体检报告详情失败", e);
+            return R.error("查询失败");
+        }
+    }
+
+    /**
+     * 新增体检报告
+     */
+    @RepeatSubmit
+    @ApiOperation("新增体检报告")
+    @PostMapping("/add")
+    public R add(@RequestBody PhysicalExamReport report) {
+        try {
+            boolean result = physicalExamReportService.save(report);
+            if (result) {
+                return R.ok("新增成功");
+            } else {
+                return R.error("新增失败");
+            }
+        } catch (Exception e) {
+            logger.error("新增体检报告失败", e);
+            return R.error("新增失败");
+        }
+    }
+
+    /**
+     * 更新体检报告
+     */
+    @RepeatSubmit
+    @ApiOperation("更新体检报告")
+    @PutMapping("/update")
+    public R update(@RequestBody PhysicalExamReport report) {
+        try {
+            boolean result = physicalExamReportService.update(report);
+            if (result) {
+                return R.ok("更新成功");
+            } else {
+                return R.error("更新失败");
+            }
+        } catch (Exception e) {
+            logger.error("更新体检报告失败", e);
+            return R.error("更新失败");
+        }
+    }
+
+    /**
+     * 删除体检报告
+     */
+    @ApiOperation("删除体检报告")
+    @DeleteMapping("/{reportId}")
+    public R delete(@PathVariable("reportId") Long reportId) {
+        try {
+            boolean result = physicalExamReportService.deleteById(reportId);
+            if (result) {
+                return R.ok("删除成功");
+            } else {
+                return R.error("删除失败");
+            }
+        } catch (Exception e) {
+            logger.error("删除体检报告失败", e);
+            return R.error("删除失败");
+        }
+    }
+}

+ 190 - 0
fs-admin/src/main/java/com/fs/medical/ReportIndicatorResultController.java

@@ -0,0 +1,190 @@
+package com.fs.medical;
+
+import com.fs.common.annotation.RepeatSubmit;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.R;
+import com.fs.medical.domain.ReportIndicatorResult;
+import com.fs.medical.dto.ReportAllIndicatorCateDTO;
+import com.fs.medical.param.ReportIndicatorResultQueryDto;
+import com.fs.medical.service.ReportIndicatorResultService;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 报告指标检查Controller
+ *
+ * @author fs
+ * @date 2024
+ */
+@Api("报告指标检查")
+@RestController
+@RequestMapping("/admin/medical/result")
+public class ReportIndicatorResultController extends BaseController {
+    private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+    @Autowired
+    private ReportIndicatorResultService reportIndicatorResultService;
+
+    /**
+     * 根据报告ID查询所有指标结果
+     */
+    @ApiOperation("根据报告ID查询所有指标结果")
+    @GetMapping("/listByReport/{reportId}")
+    public R listByReportId(@PathVariable("reportId") Long reportId) {
+        try {
+            List<ReportIndicatorResult> list = reportIndicatorResultService.listByReportId(reportId);
+            return R.ok().put("data",list);
+        } catch (Exception e) {
+            logger.error("根据报告ID查询指标结果失败", e);
+            return R.error("查询失败");
+        }
+    }
+
+    @ApiOperation("获取指定报告的指标分类")
+    @GetMapping("/getAllCateByReportId")
+    public R getAllIndicatorByReportId(@RequestParam("reportId") Long reportId) {
+        List<ReportAllIndicatorCateDTO> allIndicatorByReportId = reportIndicatorResultService.getAllIndicatorByReportId(reportId);
+        return R.ok().put("data",allIndicatorByReportId);
+    }
+
+    /**
+     * 分页查询报告指标检查结果列表(带筛选)
+     */
+    @ApiOperation("分页查询报告指标检查结果列表")
+    @GetMapping("/page")
+    public R page(ReportIndicatorResultQueryDto queryDto) {
+        try {
+            PageHelper.startPage(queryDto.getPageNum(), queryDto.getPageSize());
+            List<ReportIndicatorResult> list = reportIndicatorResultService.selectPageList(queryDto);
+            PageInfo<ReportIndicatorResult> pageInfo = new PageInfo<>(list);
+            return R.ok().put("data", pageInfo);
+        } catch (Exception e) {
+            logger.error("分页查询报告指标检查结果失败", e);
+            return R.error("查询失败");
+        }
+    }
+
+    /**
+     * 根据指标ID查询所有结果
+     */
+    @ApiOperation("根据指标ID查询所有结果")
+    @GetMapping("/listByIndicator/{indicatorId}")
+    public R listByIndicatorId(@PathVariable("indicatorId") Long indicatorId) {
+        try {
+            List<ReportIndicatorResult> list = reportIndicatorResultService.listByIndicatorId(indicatorId);
+            return R.ok().put("data",list);
+        } catch (Exception e) {
+            logger.error("根据指标ID查询结果失败", e);
+            return R.error("查询失败");
+        }
+    }
+
+    /**
+     * 根据ID查询检查结果详情
+     */
+    @ApiOperation("查询检查结果详情")
+    @GetMapping("/{resultId}")
+    public R getById(@PathVariable("resultId") Long resultId) {
+        try {
+            ReportIndicatorResult result = reportIndicatorResultService.getById(resultId);
+            return R.ok().put("data",result);
+        } catch (Exception e) {
+            logger.error("查询检查结果详情失败", e);
+            return R.error("查询失败");
+        }
+    }
+
+    /**
+     * 新增检查结果
+     */
+    @RepeatSubmit
+    @ApiOperation("新增检查结果")
+    @PostMapping("/add")
+    public R add(@RequestBody ReportIndicatorResult result) {
+        try {
+            boolean success = reportIndicatorResultService.save(result);
+            if (success) {
+                return R.ok("新增成功");
+            } else {
+                return R.error("新增失败");
+            }
+        } catch (Exception e) {
+            logger.error("新增检查结果失败", e);
+            return R.error("新增失败");
+        }
+    }
+
+    /**
+     * 批量新增检查结果
+     */
+    @RepeatSubmit
+    @ApiOperation("批量新增检查结果")
+    @PostMapping("/batchAdd")
+    public R batchAdd(@RequestBody List<ReportIndicatorResult> results) {
+        try {
+            int successCount = 0;
+            for (ReportIndicatorResult result : results) {
+                if (reportIndicatorResultService.save(result)) {
+                    successCount++;
+                }
+            }
+            if (successCount == results.size()) {
+                return R.ok("批量新增成功");
+            } else {
+                return R.ok("部分新增成功,成功" + successCount + "条");
+            }
+        } catch (Exception e) {
+            logger.error("批量新增检查结果失败", e);
+            return R.error("批量新增失败"
+
+            );
+        }
+    }
+
+    /**
+     * 更新检查结果
+     */
+    @RepeatSubmit
+    @ApiOperation("更新检查结果")
+    @PutMapping("/update")
+    public R update(@RequestBody ReportIndicatorResult result) {
+        try {
+            boolean success = reportIndicatorResultService.update(result);
+            if (success) {
+                return R.ok("更新成功");
+            } else {
+                return R.error("更新失败");
+            }
+        } catch (Exception e) {
+            logger.error("更新检查结果失败", e);
+            return R.error("更新失败");
+        }
+    }
+
+    /**
+     * 删除检查结果
+     */
+    @ApiOperation("删除检查结果")
+    @DeleteMapping("/{resultId}")
+    public R delete(@PathVariable("resultId") Long resultId) {
+        try {
+            boolean success = reportIndicatorResultService.deleteById(resultId);
+            if (success) {
+                return R.ok("删除成功");
+            } else {
+                return R.error("删除失败");
+            }
+        } catch (Exception e) {
+            logger.error("删除检查结果失败", e);
+            return R.error("删除失败");
+        }
+    }
+}

+ 82 - 0
fs-admin/src/main/java/com/fs/saler/CompetitorInfoController.java

@@ -0,0 +1,82 @@
+package com.fs.saler;
+
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.R;
+import com.fs.saler.domain.FsCompetitorInfo;
+import com.fs.saler.param.FsCompetitorInfoParam;
+import com.fs.saler.service.FsCompetitorInfoService;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * 竞品信息控制器
+ */
+@Api("竞品信息")
+@RestController
+@RequestMapping(value="/saler/competitorInfo")
+public class CompetitorInfoController extends BaseController {
+
+    @Autowired
+    private FsCompetitorInfoService competitorInfoService;
+
+    /**
+     * 分页查询竞品列表
+     */
+    @ApiOperation("查看竞品列表")
+    @PostMapping("/listPage")
+    public R listPage(@RequestBody FsCompetitorInfoParam param) {
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        List<FsCompetitorInfo> list = competitorInfoService.getAll(param);
+        PageInfo<FsCompetitorInfo> pageInfo = new PageInfo<>(list);
+        return R.ok().put("data", pageInfo);
+    }
+
+    /**
+     * 查看竞品详情
+     */
+    @ApiOperation("查看竞品详情")
+    @PostMapping("/findById")
+    public R findById(@RequestBody FsCompetitorInfoParam param) {
+        FsCompetitorInfo competitorInfo = competitorInfoService.getById(param.getId());
+        return R.ok().put("data", competitorInfo);
+    }
+
+    /**
+     * 新增竞品
+     */
+    @ApiOperation("新增竞品")
+    @PostMapping("/save")
+    public R save(@RequestBody FsCompetitorInfo competitorInfo) {
+        boolean result = competitorInfoService.save(competitorInfo);
+        return result ? R.ok() : R.error("新增竞品失败");
+    }
+
+    /**
+     * 更新竞品信息
+     */
+    @ApiOperation("更新竞品信息")
+    @PostMapping("/updateById")
+    public R updateById(@RequestBody FsCompetitorInfo competitorInfo) {
+        boolean result = competitorInfoService.update(competitorInfo);
+        return result ? R.ok() : R.error("更新竞品信息失败");
+    }
+
+    /**
+     * 删除竞品
+     */
+    @ApiOperation("删除竞品")
+    @PostMapping("/deleteById")
+    public R deleteById(@RequestBody FsCompetitorInfoParam param) {
+        boolean result = competitorInfoService.removeById(param.getId());
+        return result ? R.ok() : R.error("删除竞品失败");
+    }
+}

+ 73 - 0
fs-admin/src/main/java/com/fs/saler/FsServiceGoodsController.java

@@ -0,0 +1,73 @@
+package com.fs.saler;
+
+import com.fs.common.core.domain.R;
+import com.fs.saler.domain.FsProductInfo;
+import com.fs.saler.param.ProductInfoListPageParam;
+import com.fs.saler.service.FsProductInfoService;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@Api("商品信息")
+@RestController
+@RequestMapping(value="/saler/serviceGoods")
+public class FsServiceGoodsController {
+    @Autowired
+    private FsProductInfoService fsProductInfoService;
+
+    /**
+     * 分页查询商品列表
+     */
+    @ApiOperation("查看商品列表")
+    @PostMapping("/listPage")
+    public R listPage(@RequestBody ProductInfoListPageParam param) {
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        List<FsProductInfo> list = fsProductInfoService.getAll(param);
+        PageInfo<FsProductInfo> pageInfo = new PageInfo<>(list);
+        return R.ok().put("data", pageInfo);
+    }
+    /**
+     * 查看商品详情
+     */
+    @ApiOperation("查看商品详情")
+    @PostMapping("/findById")
+    public R findById(@RequestBody ProductInfoListPageParam param) {
+        FsProductInfo productInfo = fsProductInfoService.getById(param.getId());
+        return R.ok().put("data", productInfo);
+    }
+    /**
+     * 新增商品
+     */
+    @ApiOperation("新增商品")
+    @PostMapping("/save")
+    public R save(@RequestBody FsProductInfo productInfo) {
+        boolean result = fsProductInfoService.save(productInfo);
+        return result ? R.ok() : R.error("新增商品失败");
+    }
+    /**
+     * 更新商品信息
+     */
+    @ApiOperation("更新商品信息")
+    @PostMapping("/updateById")
+    public R updateById(@RequestBody FsProductInfo productInfo) {
+        boolean result = fsProductInfoService.update(productInfo);
+        return result ? R.ok() : R.error("更新商品信息失败");
+    }
+    /**
+     * 删除商品
+     */
+    @ApiOperation("删除商品")
+    @PostMapping("/deleteById")
+    public R deleteById(@RequestBody ProductInfoListPageParam param) {
+        boolean result = fsProductInfoService.removeById(param.getId());
+        return result ? R.ok() : R.error("删除商品失败");
+    }
+}

+ 42 - 0
fs-common/src/main/java/com/fs/common/utils/DateUtils.java

@@ -271,4 +271,46 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
         return new SimpleDateFormat("yyyy-MM-dd").format(cal.getTime());
     }
 
+    /**
+     * @Description: yyyy-MM 获取当月的第一天
+     * @Param:
+     * @Return:
+     * @Author xgb
+     * @Date 2025/9/1 14:30
+     */
+    public static Date getStartOfMonth(Date date) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(date);
+        calendar.set(Calendar.DAY_OF_MONTH, 1);
+        return calendar.getTime();
+    }
+
+    /**
+     * @Description: yyyy-MM 获取当月的最后一天
+     * @Param:
+     * @Return:
+     * @Author xgb
+     * @Date 2025/9/1 14:31
+     */
+
+    public static Date getEndOfMonth(Date date) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(date);
+        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
+        return calendar.getTime();
+    }
+
+    /**
+     * @Description: 根据日期获取星期 1-星期一 2-星期二 。。。6-星期六 0-星期日
+     * @Param:
+     * @Return:
+     * @Author xgb
+     * @Date 2025/9/5 14:04
+     */
+
+    public static int getWeek(Date date) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(date);
+        return calendar.get(Calendar.DAY_OF_WEEK)-1;
+    }
 }

+ 3 - 0
fs-common/src/main/java/com/fs/common/utils/DictUtils.java

@@ -6,12 +6,14 @@ import com.fs.common.constant.Constants;
 import com.fs.common.core.domain.entity.SysDictData;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.utils.spring.SpringUtils;
+import lombok.extern.slf4j.Slf4j;
 
 /**
  * 字典工具类
  *
 
  */
+@Slf4j
 public class DictUtils
 {
     /**
@@ -42,6 +44,7 @@ public class DictUtils
         if (StringUtils.isNotNull(cacheObj))
         {
             List<SysDictData> dictDatas = StringUtils.cast(cacheObj);
+            log.info("获取缓存 key: {} values: {}",key,dictDatas);
             return dictDatas;
         }
         return null;

+ 205 - 0
fs-common/src/main/java/com/fs/common/utils/FileNameExtractor.java

@@ -0,0 +1,205 @@
+package com.fs.common.utils;
+
+import org.apache.commons.io.FilenameUtils;
+import java.net.URL;
+import java.net.MalformedURLException;
+
+public class FileNameExtractor {
+
+    /**
+     * 使用Apache Commons IO获取文件名
+     * @param urlString URL字符串
+     * @return 文件名
+     */
+    public static String getFileNameFromUrl(String urlString) {
+        if (urlString == null || urlString.trim().isEmpty()) {
+            return null;
+        }
+
+        try {
+            URL url = new URL(urlString);
+            String path = url.getPath();
+            return FilenameUtils.getName(path);
+        } catch (MalformedURLException e) {
+            // 作为普通路径处理
+            return FilenameUtils.getName(urlString);
+        }
+    }
+
+    /**
+     * 获取不带扩展名的文件名
+     * @param urlString URL字符串
+     * @return 不带扩展名的文件名
+     */
+    public static String getBaseNameFromUrl(String urlString) {
+        if (urlString == null || urlString.trim().isEmpty()) {
+            return null;
+        }
+
+        try {
+            URL url = new URL(urlString);
+            String path = url.getPath();
+            return FilenameUtils.getBaseName(path);
+        } catch (MalformedURLException e) {
+            return FilenameUtils.getBaseName(urlString);
+        }
+    }
+
+    /**
+     * 获取文件扩展名
+     * @param urlString URL字符串
+     * @return 文件扩展名
+     */
+    public static String getExtensionFromUrl(String urlString) {
+        if (urlString == null || urlString.trim().isEmpty()) {
+            return null;
+        }
+
+        try {
+            URL url = new URL(urlString);
+            String path = url.getPath();
+            return FilenameUtils.getExtension(path);
+        } catch (MalformedURLException e) {
+            return FilenameUtils.getExtension(urlString);
+        }
+    }
+
+    /**
+     * 从URL或文件路径中获取扩展名
+     * @param urlOrPath URL字符串或文件路径
+     * @return 扩展名(不包含点号),如果没有扩展名则返回null
+     */
+    public static String getExtension(String urlOrPath) {
+        if (urlOrPath == null || urlOrPath.trim().isEmpty()) {
+            return null;
+        }
+
+        String fileName = getFileNameFromUrlOrPath(urlOrPath);
+        if (fileName == null || fileName.isEmpty()) {
+            return null;
+        }
+
+        // 查找最后一个点的位置
+        int lastDotIndex = fileName.lastIndexOf('.');
+
+        // 如果没有点,或者点在开头(隐藏文件),或者点在结尾,则没有扩展名
+        if (lastDotIndex <= 0 || lastDotIndex == fileName.length() - 1) {
+            return null;
+        }
+
+        return fileName.substring(lastDotIndex + 1).toLowerCase();
+    }
+
+    /**
+     * 从URL或文件路径中获取扩展名(包含点号)
+     * @param urlOrPath URL字符串或文件路径
+     * @return 扩展名(包含点号),如果没有扩展名则返回null
+     */
+    public static String getExtensionWithDot(String urlOrPath) {
+        String extension = getExtension(urlOrPath);
+        return extension != null ? "." + extension : null;
+    }
+
+    /**
+     * 检查文件是否具有指定的扩展名
+     * @param urlOrPath URL字符串或文件路径
+     * @param expectedExtension 期望的扩展名(可以带点号也可以不带)
+     * @return 是否匹配
+     */
+    public static boolean hasExtension(String urlOrPath, String expectedExtension) {
+        if (expectedExtension == null) {
+            return false;
+        }
+
+        String actualExtension = getExtension(urlOrPath);
+        if (actualExtension == null) {
+            return false;
+        }
+
+        // 处理期望扩展名可能带点号的情况
+        String cleanExpectedExtension = expectedExtension.startsWith(".") ?
+                expectedExtension.substring(1) : expectedExtension;
+
+        return actualExtension.equalsIgnoreCase(cleanExpectedExtension);
+    }
+
+    /**
+     * 检查文件是否是图片类型
+     * @param urlOrPath URL字符串或文件路径
+     * @return 是否是图片文件
+     */
+    public static boolean isImageFile(String urlOrPath) {
+        String extension = getExtension(urlOrPath);
+        if (extension == null) {
+            return false;
+        }
+
+        String[] imageExtensions = {"jpg", "jpeg", "png", "gif", "bmp", "webp", "svg", "ico"};
+        for (String imgExt : imageExtensions) {
+            if (extension.equalsIgnoreCase(imgExt)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 检查文件是否是文档类型
+     * @param urlOrPath URL字符串或文件路径
+     * @return 是否是文档文件
+     */
+    public static boolean isDocumentFile(String urlOrPath) {
+        String extension = getExtension(urlOrPath);
+        if (extension == null) {
+            return false;
+        }
+
+        String[] docExtensions = {"pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx", "txt", "rtf"};
+        for (String docExt : docExtensions) {
+            if (extension.equalsIgnoreCase(docExt)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 从URL或路径中提取文件名的辅助方法
+     */
+    private static String getFileNameFromUrlOrPath(String urlOrPath) {
+        try {
+            java.net.URL url = new java.net.URL(urlOrPath);
+            String path = url.getPath();
+
+            // 处理查询参数,移除?后面的内容
+            int queryIndex = path.indexOf('?');
+            if (queryIndex > 0) {
+                path = path.substring(0, queryIndex);
+            }
+
+            if (path.endsWith("/")) {
+                path = path.substring(0, path.length() - 1);
+            }
+
+            int lastSlashIndex = path.lastIndexOf('/');
+            return lastSlashIndex >= 0 ? path.substring(lastSlashIndex + 1) : path;
+
+        } catch (java.net.MalformedURLException e) {
+            // 作为普通路径处理
+            String path = urlOrPath.trim();
+
+            // 处理查询参数
+            int queryIndex = path.indexOf('?');
+            if (queryIndex > 0) {
+                path = path.substring(0, queryIndex);
+            }
+
+            if (path.endsWith("/") || path.endsWith("\\")) {
+                path = path.substring(0, path.length() - 1);
+            }
+
+            int lastSlashIndex = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\'));
+            return lastSlashIndex >= 0 ? path.substring(lastSlashIndex + 1) : path;
+        }
+    }
+}

+ 155 - 0
fs-company-app/src/main/java/com/fs/app/controller/FsUserHealthDataController.java

@@ -0,0 +1,155 @@
+package com.fs.app.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.fs.app.annotation.Login;
+import com.fs.common.core.domain.R;
+import com.fs.common.utils.DateUtils;
+import com.fs.common.utils.StringUtils;
+import com.fs.his.config.HealthIndicatorConfig;
+import com.fs.his.domain.FsUserHealthData;
+import com.fs.his.service.IFsUserHealthDataService;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 用户身体检测数据Controller
+ *
+ * @author fs
+ * @date 2025-08-27
+ */
+@RestController
+@RequestMapping("/app/fs/health/data")
+@Api(tags = "用户身体检测数据血糖,尿酸,血压等")
+public class FsUserHealthDataController extends AppBaseController {
+    @Autowired
+    private IFsUserHealthDataService fsUserHealthDataService;
+
+
+    /**
+     * 查询用户身体检测数据列表
+     */
+    @Login
+    @GetMapping("/list")
+    @ApiOperation("获取用户列表信息")
+    public R list(FsUserHealthData fsUserHealthData,
+                  @RequestParam(required = false, defaultValue = "1") Integer pageNum,
+                  @RequestParam(required = false, defaultValue = "1000") Integer pageSize
+    ) {
+        return R.ok(fsUserHealthDataService.selectFsUserHealthDataListInfo(fsUserHealthData, pageNum, pageSize));
+    }
+
+
+    /**
+     * 查询用户身体检测数据列表 最新数据  如果查询时间为周或者月的话 每天只返回最新的数据
+     */
+    @Login
+    @GetMapping("/latest/list")
+    @ApiOperation("获取用户列表信息")
+    public R listByLatest(FsUserHealthData fsUserHealthData,
+                  @RequestParam(required = false, defaultValue = "1") Integer pageNum,
+                  @RequestParam(required = false, defaultValue = "1000") Integer pageSize
+    ) {
+        return R.ok(fsUserHealthDataService.selectFsUserHealthDataListInfoLatest(fsUserHealthData, pageNum, pageSize));
+    }
+
+    /**
+     * 根据检测类型获取 检测指标
+     */
+    @Login
+    @GetMapping("/flag")
+    @ApiOperation(" 根据检测类型获取 检测指标")
+    public R getInfo(@RequestParam("measurementType") Integer measurementType) {
+        // 获取检测指标 (0-腰围,1-臀围,2-血糖,3-血压,4-尿酸 5-BMI)
+        Map<String, Object> data = new HashMap<>();
+        // 血糖 尿酸 需要
+        HealthIndicatorConfig healthIndicatorConfig = fsUserHealthDataService.parseHealthIndicator();
+        if (measurementType == 2) { // 血糖
+            if (healthIndicatorConfig != null) {
+                String[] key = {"fasting", "post1Hour", "post2Hour"}; // 正常 餐后1小时 餐后2小时
+                for (int i = 0; i < key.length; i++) {
+                    String value = fsUserHealthDataService.getHealthIndicatorValue(healthIndicatorConfig, "bloodGlucose", key[i], "normal");
+                    // value json串转Map对象
+                    data.put(key[i], value);
+                }
+            }
+        } else if (measurementType == 4) {
+            String[] key = new String[]{"male", "female"};
+            for (int i = 0; i < key.length; i++) {
+                String value = fsUserHealthDataService.getHealthIndicatorValue(healthIndicatorConfig, "uricAcid", key[i], "normal");
+                data.put(key[i], value);
+            }
+        }
+        return R.ok().put("data", data);
+    }
+
+
+    /**
+     * 根据用户ID 查询用户身体检测最新数据
+     */
+    @Login
+    @GetMapping("/latest/info")
+    @ApiOperation("根据用户ID 获取用户身体检测最新数据")
+    public R getInfo(@RequestParam("userId") Long userId, @RequestParam("measurementType") Integer measurementType) {
+        FsUserHealthData fsUserHealthData = new FsUserHealthData();
+        fsUserHealthData.setUserId(userId);
+        fsUserHealthData.setMeasurementType(measurementType);
+        fsUserHealthData = fsUserHealthDataService.selectFsUserHealthDataByUserId(fsUserHealthData);
+        return R.ok().put("data", fsUserHealthData);
+    }
+
+    /**
+     * 根据ID 查询用户身体检测最新数据
+     */
+    @Login
+    @GetMapping("/info")
+    @ApiOperation("根据ID 获取用户身体检测最新数据")
+    public R getInfoById(@RequestParam("id") Long id) {
+        FsUserHealthData fsUserHealthData = fsUserHealthDataService.selectFsUserHealthDataById(id);
+        return R.ok().put("data", fsUserHealthData);
+    }
+
+    /**
+     * 新增用户身体检测数据
+     */
+    @Login
+    @PostMapping("/add")
+    @ApiOperation("新增用户身体检测数据")
+    public R add(@RequestBody FsUserHealthData fsUserHealthData) {
+        // 登记检测数据信息
+        fsUserHealthDataService.addHealthData(fsUserHealthData);
+        return R.ok();
+    }
+
+    /**
+     * 修改用户身体检测数据
+     */
+    @Login
+    @PostMapping("/update")
+    @ApiOperation("修改用户身体检测数据")
+    public R edit(@RequestBody FsUserHealthData fsUserHealthData) {
+        // 修改检测数据信息
+        fsUserHealthDataService.updateFsUserHealthDataAndLevel(fsUserHealthData);
+        return R.ok();
+    }
+
+    /**
+     * 删除用户身体检测数据
+     */
+    @Login
+    @GetMapping("/delete")
+    @ApiOperation("删除用户身体检测数据")
+    public R remove(@RequestParam Long id) {
+        if (fsUserHealthDataService.deleteFsUserHealthDataById(id) <= 0) {
+            return R.error("用户身体检测数据删除失败");
+        }
+        return R.ok();
+    }
+}

+ 139 - 0
fs-company-app/src/main/java/com/fs/app/controller/FsUserHealthProfileController.java

@@ -0,0 +1,139 @@
+package com.fs.app.controller;
+
+import com.fs.app.annotation.Login;
+import com.fs.common.core.domain.R;
+import com.fs.common.utils.DateUtils;
+import com.fs.his.domain.FsUserHealthData;
+import com.fs.his.domain.FsUserHealthProfile;
+import com.fs.his.domain.FsUserInfo;
+import com.fs.his.dto.FsUserHealthInfoDTO;
+import com.fs.his.service.IFsUserHealthDataService;
+import com.fs.his.service.IFsUserHealthProfileService;
+import com.fs.his.service.IFsUserInfoService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 用户健康档案Controller
+ *
+ * @author fs
+ * @date 2025-08-27
+ */
+@RestController
+@RequestMapping("/app/fs/health/profile")
+@Api(tags = "用户健康档案")
+public class FsUserHealthProfileController extends AppBaseController {
+    @Autowired
+    private IFsUserHealthProfileService fsUserHealthProfileService;
+    @Autowired
+    private IFsUserHealthDataService fsUserHealthDataService;
+    @Autowired
+    private IFsUserInfoService fsUserInfoService;
+
+
+    /**
+     * 获取用户健康档案详细信息
+     */
+    @Login
+    @GetMapping(value = "/info")
+    @ApiOperation("获取用户健康档案详细信息")
+    public R getInfo(@RequestParam("userId") Long userId) {
+        FsUserHealthProfile profile = fsUserHealthProfileService.selectFsUserHealthProfileByUserId(userId);
+        return R.ok().put("data", profile);
+    }
+
+
+    /**
+     * 获取用户健康档案主页信息
+     */
+    @Login
+    @GetMapping(value = "/home/info")
+    @ApiOperation("获取用户健康档案主页信息")
+    public R getHomeInfo(@RequestParam("userId") Long userId) {
+        FsUserHealthInfoDTO infoDTO = new FsUserHealthInfoDTO();
+        // 查询用户信息
+        FsUserInfo userInfo = fsUserInfoService.selectFsUserInfoById(userId);
+        if (userInfo == null) {
+            return R.error("用户不存在");
+        }
+        infoDTO.setUserId(userId);
+        infoDTO.setUsername(userInfo.getUsername());
+        infoDTO.setAvatar(userInfo.getAvatar());
+        infoDTO.setSex(userInfo.getSex());
+        // 根据生日获取年龄
+        if(userInfo.getBirthdate()!=null){
+            infoDTO.setAge(DateUtils.getAge(userInfo.getBirthdate()));
+        }
+
+        // 查询各指标 数据 测量类型(0-腰围,1-臀围,2-血糖,3-血压,4-尿酸 5-BMI)
+        FsUserHealthData query = new FsUserHealthData();
+        query.setUserId(userId);
+        Map<String, Object> dataMap = new HashMap<>();
+        for (int i = 0; i < 6; i++) {
+            query.setMeasurementType(i);
+            FsUserHealthData healthData = fsUserHealthDataService.selectFsUserHealthDataByUserId(query);
+            dataMap.put(String.valueOf(i), healthData);
+        }
+        infoDTO.setDataMap(dataMap);
+
+        // 查询健康档案
+        FsUserHealthProfile profile = fsUserHealthProfileService.selectFsUserHealthProfileByUserId(userId);
+        if (profile != null) {
+            infoDTO.setSymptomHistory(profile.getSymptomHistory());
+            infoDTO.setOtherMedicalHistory(profile.getOtherMedicalHistory());
+        }
+
+        return R.ok().put("data", infoDTO);
+    }
+
+
+    /**
+     * 新增用户健康档案
+     */
+    @Login
+    @PostMapping("/add")
+    @ApiOperation("新增用户健康档案")
+    @Transactional
+    public R add(@RequestBody FsUserHealthProfile fsUserHealthProfile) {
+
+        if (fsUserHealthProfileService.insertFsUserHealthProfile(fsUserHealthProfile) <= 0) {
+            return R.error("新增用户健康档案失败");
+        }
+
+        // 登记身体检测数据 FsUserHealthData
+        fsUserHealthDataService.initHealthData(fsUserHealthProfile);
+
+        return R.ok();
+    }
+
+    /**
+     * 修改用户健康档案
+     */
+    @Login
+    @PostMapping("/update")
+    @ApiOperation("修改用户健康档案")
+    public R edit(@RequestBody FsUserHealthProfile fsUserHealthProfile) {
+        if (fsUserHealthProfileService.updateFsUserHealthProfile(fsUserHealthProfile) <= 0) {
+            return R.error("用户健康档案修改失败");
+        }
+        return R.ok();
+    }
+
+    /**
+     * 删除用户健康档案
+     */
+    @Login
+    @GetMapping("/delete")
+    public R remove(@RequestParam Long userId) {
+        if (fsUserHealthProfileService.deleteFsUserHealthProfileByUserId(userId) <= 0) {
+            return R.error("用户健康档案删除失败");
+        }
+        return R.ok();
+    }
+}

+ 111 - 0
fs-company-app/src/main/java/com/fs/app/controller/FsUserInfoController.java

@@ -0,0 +1,111 @@
+package com.fs.app.controller;
+
+import com.fs.app.annotation.Login;
+import com.fs.common.core.domain.R;
+import com.fs.common.utils.DateUtils;
+import com.fs.common.utils.StringUtils;
+import com.fs.his.domain.FsUser;
+import com.fs.his.domain.FsUserInfo;
+import com.fs.his.service.IFsUserInfoService;
+import com.fs.his.service.IFsUserService;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 用户信息Controller
+ *
+ * @author fs
+ * @date 2025-08-25
+ */
+@RestController
+@RequestMapping("/app/fs/userinfo")
+@Api(tags = "用户信息")
+public class FsUserInfoController extends AppBaseController {
+    @Autowired
+    private IFsUserInfoService fsUserInfoService;
+
+    @Autowired
+    private IFsUserService fsUserService;
+
+    /**
+     * 查询用户信息列表
+     */
+    @Login
+    @GetMapping("/list")
+    @ApiOperation("获取用户列表信息")
+    public R list(FsUserInfo fsUserInfo,
+                  @RequestParam(required = false, defaultValue = "1") Integer pageNum,
+                  @RequestParam(required = false, defaultValue = "10") Integer pageSize) {
+
+        // companyUserId 传空的查询所有
+        PageHelper.startPage(pageNum, pageSize);
+        List<FsUserInfo> list = fsUserInfoService.selectFsUserInfoList(fsUserInfo.getCompanyUserId());
+        return R.ok().put("data", new PageInfo<>(list));
+    }
+
+
+    /**
+     * 获取用户信息详细信息
+     */
+    @Login
+    @GetMapping(value = "/info")
+    @ApiOperation("获取用户详情信息")
+    public R getInfo(@RequestParam("userId") Long userId) {
+        FsUserInfo fsUserInfo = fsUserInfoService.selectFsUserInfoById(userId);
+        if (fsUserInfo == null) {
+            return R.error("用户不存在");
+        } else if(fsUserInfo.getIsDel()!=0){
+            return R.error("用户信息已删除");
+        }else{
+            if(fsUserInfo.getBirthdate()!=null){
+                fsUserInfo.setAge(DateUtils.getAge(fsUserInfo.getBirthdate()));
+            }
+        }
+        return R.ok().put("data", fsUserInfo);
+    }
+
+
+    /**
+     * 新增用户信息
+     */
+    @Login
+    @PostMapping("/add")
+    @ApiOperation("新增用户信息")
+    public R add(@RequestBody FsUserInfo fsUserInfo) {
+        fsUserInfoService.add(fsUserInfo);
+        return R.ok();
+    }
+
+    /**
+     * 修改用户信息
+     */
+    @Login
+    @PostMapping("/update")
+    @ApiOperation("修改用户信息")
+    public R edit(@RequestBody FsUserInfo fsUserInfo) {
+        fsUserInfoService.updateFsUserInfo(fsUserInfo);
+        return R.ok();
+    }
+
+    /**
+     * 删除用户信息
+     */
+    @Login
+    @GetMapping("/delete")
+    @ApiOperation("删除用户信息")
+    @Transactional
+    public R remove(@RequestParam("userId") Long userId) {
+        // 更新fsUser表状态
+        if (fsUserInfoService.deleteFsUserInfoByUserId(userId) <= 0) {
+            return R.error("用户信息删除原表失败");
+        }
+        return R.ok();
+    }
+}

+ 96 - 0
fs-company-app/src/main/java/com/fs/app/controller/FsUserPayCompetitorsRecordController.java

@@ -0,0 +1,96 @@
+package com.fs.app.controller;
+
+import com.fs.app.annotation.Login;
+import com.fs.common.core.domain.R;
+import com.fs.his.domain.FsUserPayCompetitorsRecord;
+import com.fs.his.service.IFsUserPayCompetitorsRecordService;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 用户购买竞品信息记录Controller
+ *
+ * @author fs
+ * @date 2025-08-26
+ */
+@RestController
+@RequestMapping("/app/fs/rival/products")
+public class FsUserPayCompetitorsRecordController extends AppBaseController {
+    @Autowired
+    private IFsUserPayCompetitorsRecordService fsUserPayCompetitorsRecordService;
+
+    /**
+     * 查询用户购买竞品信息记录列表
+     */
+    @Login
+    @GetMapping("/list")
+    @ApiOperation("获取用户购买竞品信息记录列表")
+    public R list(FsUserPayCompetitorsRecord fsUserPayCompetitorsRecord,
+                  @RequestParam(required = false, defaultValue = "1") Integer pageNum,
+                  @RequestParam(required = false, defaultValue = "10") Integer pageSize) {
+        // 校验userId不能为空
+        if (fsUserPayCompetitorsRecord.getUserId() == null) {
+            return R.error("用户ID不能为空");
+        }
+
+        PageHelper.startPage(pageNum, pageSize);
+        List<FsUserPayCompetitorsRecord> list = fsUserPayCompetitorsRecordService.selectFsUserPayCompetitorsRecordList(fsUserPayCompetitorsRecord);
+        return R.ok().put("data", new PageInfo<>(list));
+    }
+
+
+    /**
+     * 获取用户购买竞品信息记录详细信息
+     */
+    @Login
+    @GetMapping(value = "/info")
+    @ApiOperation("获取用户购买竞品信息记录详细信息")
+    public R getInfo(@RequestParam("id") Long id) {
+        FsUserPayCompetitorsRecord record = fsUserPayCompetitorsRecordService.selectFsUserPayCompetitorsRecordById(id);
+        return R.ok().put("data", record);
+    }
+
+    /**
+     * 新增用户购买竞品信息记录
+     */
+    @Login
+    @PostMapping("/add")
+    @ApiOperation("新增用户购买竞品信息记录")
+    public R add(@RequestBody FsUserPayCompetitorsRecord fsUserPayCompetitorsRecord) {
+        if (fsUserPayCompetitorsRecordService.insertFsUserPayCompetitorsRecord(fsUserPayCompetitorsRecord) <= 0) {
+            return R.error("用户购买竞品信息记录登记失败");
+        }
+        return R.ok();
+    }
+
+    /**
+     * 修改用户购买竞品信息记录
+     */
+    @Login
+    @PostMapping("/update")
+    @ApiOperation("修改用户购买竞品信息记录")
+    public R edit(@RequestBody FsUserPayCompetitorsRecord fsUserPayCompetitorsRecord) {
+        if (fsUserPayCompetitorsRecordService.updateFsUserPayCompetitorsRecord(fsUserPayCompetitorsRecord) <= 0) {
+            return R.error("用户购买竞品信息记录修改失败");
+        }
+        return R.ok();
+    }
+
+    /**
+     * 删除用户购买竞品信息记录
+     */
+    @Login
+    @GetMapping("/delete")
+    @ApiOperation("删除用户购买竞品信息记录")
+    public R remove(@RequestParam("id") Long id) {
+        if (fsUserPayCompetitorsRecordService.deleteFsUserPayCompetitorsRecordById(id) <= 0) {
+            return R.error("用户购买竞品信息记录删除失败");
+        }
+        return R.ok();
+    }
+}

+ 96 - 0
fs-company-app/src/main/java/com/fs/app/controller/FsUserPayRecordController.java

@@ -0,0 +1,96 @@
+package com.fs.app.controller;
+
+import com.fs.app.annotation.Login;
+import com.fs.common.core.domain.R;
+import com.fs.his.domain.FsUserPayRecord;
+import com.fs.his.service.IFsUserPayRecordService;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 用户购买服务信息记录Controller
+ *
+ * @author fs
+ * @date 2025-08-26
+ */
+@RestController
+@RequestMapping("/app/fs/pay/products")
+public class FsUserPayRecordController extends AppBaseController {
+    @Autowired
+    private IFsUserPayRecordService fsUserPayRecordService;
+
+    /**
+     * 查询用户购买服务信息记录列表
+     */
+    @Login
+    @GetMapping("/list")
+    @ApiOperation("获取用户购买服务信息记录列表")
+    public R list(FsUserPayRecord fsUserPayRecord,
+                  @RequestParam(required = false, defaultValue = "1") Integer pageNum,
+                  @RequestParam(required = false, defaultValue = "10") Integer pageSize) {
+
+        if (fsUserPayRecord.getUserId() == null) {
+            return R.error("用户ID不能为空");
+        }
+
+        PageHelper.startPage(pageNum, pageSize);
+        List<FsUserPayRecord> list = fsUserPayRecordService.selectFsUserPayRecordList(fsUserPayRecord);
+        return R.ok().put("data", new PageInfo<>(list));
+    }
+
+
+    /**
+     * 获取用户购买服务信息记录详细信息
+     */
+    @Login
+    @GetMapping(value = "/info")
+    @ApiOperation("获取用户购买服务信息记录详细信息")
+    public R getInfo(@RequestParam("id") Long id) {
+        FsUserPayRecord fsUserPayRecord = fsUserPayRecordService.selectFsUserPayRecordById(id);
+        return R.ok().put("data", fsUserPayRecord);
+    }
+
+    /**
+     * 新增用户购买服务信息记录
+     */
+    @Login
+    @PostMapping("/add")
+    @ApiOperation("新增用户购买服务信息记录")
+    public R add(@RequestBody FsUserPayRecord fsUserPayRecord) {
+        if (fsUserPayRecordService.insertFsUserPayRecord(fsUserPayRecord) <= 0) {
+            return R.error("用户购买服务信息记录登记失败");
+        }
+        return R.ok();
+    }
+
+    /**
+     * 修改用户购买服务信息记录
+     */
+    @Login
+    @PostMapping("/update")
+    @ApiOperation("修改用户购买服务信息记录")
+    public R edit(@RequestBody FsUserPayRecord fsUserPayRecord) {
+        if (fsUserPayRecordService.updateFsUserPayRecord(fsUserPayRecord) <= 0) {
+            return R.error("用户购买服务信息记录修改失败");
+        }
+        return R.ok();
+    }
+
+    /**
+     * 删除用户购买服务信息记录
+     */
+    @Login
+    @GetMapping("/delete")
+    @ApiOperation("删除用户购买服务信息记录")
+    public R remove(@RequestParam("id") Long id) {
+        if (fsUserPayRecordService.deleteFsUserPayRecordById(id) <= 0) {
+            return R.error("用户购买服务信息记录删除失败");
+        }
+        return R.ok();
+    }
+}

+ 13 - 0
fs-company-app/src/main/java/com/fs/app/exception/FSExceptionHandler.java

@@ -5,6 +5,7 @@ package com.fs.app.exception;
 
 import com.fs.common.core.domain.R;
 import com.fs.common.exception.CustomException;
+import com.fs.common.exception.ServiceException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.dao.DuplicateKeyException;
@@ -36,6 +37,18 @@ public class FSExceptionHandler {
 		return r;
 	}
 
+	/**
+	 * 处理自定义异常
+	 */
+	@ExceptionHandler(ServiceException.class)
+	public R handleRRException(ServiceException e){
+		R r = new R();
+		r.put("code", e.getCode());
+		r.put("msg", e.getMessage());
+
+		return r;
+	}
+
 	@ExceptionHandler(NoHandlerFoundException.class)
 	public R handlerNoFoundException(Exception e) {
 		logger.error(e.getMessage(), e);

+ 21 - 2
fs-company/src/main/java/com/fs/company/controller/company/CompanyUserController.java

@@ -16,7 +16,6 @@ import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.company.domain.*;
-import com.fs.company.mapper.CompanyUserDelayTimeMapper;
 import com.fs.company.param.CompanyUserAreaParam;
 import com.fs.company.param.CompanyUserCodeParam;
 import com.fs.company.param.CompanyUserQwParam;
@@ -38,7 +37,6 @@ import com.fs.system.service.ISysConfigService;
 import com.fs.voice.utils.StringUtil;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
-import org.apache.ibatis.annotations.Param;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
@@ -517,4 +515,25 @@ public class CompanyUserController extends BaseController
         String url = companyUserService.uploadQrCode(file, userId);
         return R.ok().put("url", url);
     }
+
+
+    /**
+     * 销售解除绑定医生
+     */
+    @PreAuthorize("@ss.hasPermi('qw:companyUser:unBindDoctorId')")
+    @Log(title = "销售解除绑定医生", businessType = BusinessType.UPDATE)
+    @GetMapping("/unBindDoctorId/{userId}")
+    public R bindDoctorId(@PathVariable("userId") Long userId){
+        return companyUserService.unBindDoctor(userId);
+    }
+
+    /**
+     * 销售绑定医生
+     */
+    @PreAuthorize("@ss.hasPermi('qw:companyUser:bindDoctorId')")
+    @Log(title = "销售绑定医生", businessType = BusinessType.UPDATE)
+    @PostMapping("/bindDoctorId")
+    public R unBindDoctorId(@RequestBody CompanyUser companyUser){
+        return companyUserService.bindDoctor(companyUser);
+    }
 }

+ 26 - 4
fs-company/src/main/java/com/fs/company/controller/company/FsDoctorController.java

@@ -1,8 +1,11 @@
 package com.fs.company.controller.company;
 
+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.his.param.FsDoctorParam;
 import com.fs.his.service.IFsDoctorService;
 import com.fs.his.utils.RedisCacheUtil;
@@ -11,14 +14,15 @@ import com.fs.his.vo.FsDoctorVO;
 import com.fs.his.vo.OptionsVO;
 import com.fs.his.vo.UserVo;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
 
 import java.util.Base64;
 import java.util.List;
 
+import static com.fs.his.utils.PhoneUtil.decryptAutoPhoneMk;
+import static com.fs.his.utils.PhoneUtil.encryptPhone;
+
 /**
  * 医生管理Controller
  *
@@ -121,6 +125,24 @@ public class FsDoctorController extends BaseController
     }
 
 
+    @GetMapping("/getDocVoList")
+    public TableDataInfo getDocVoList(FsDoctorParam param) {
+        startPage();
+        List<FsDoctorVO> list = fsDoctorService.selectDocVOByNameAndPhone(param);
+        if (list == null || list.isEmpty()) {
+            param.setMobile(encryptPhone(param.getMobile()));
+            list = fsDoctorService.selectDocVOByNameAndPhone(param);
+        }
+
+        if (list != null) {
+            list.forEach( item -> {
+                if (item.getMobile() != null)
+                    item.setMobile(decryptAutoPhoneMk(item.getMobile()));
+            });
+        }
+        return getDataTable(list);
+    }
+
 
 
 }

+ 99 - 8
fs-company/src/main/java/com/fs/company/controller/qw/QwSopLogsController.java

@@ -6,26 +6,31 @@ 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.ServletUtils;
 import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.service.ICompanyUserService;
+import com.fs.company.service.impl.CompanyDeptServiceImpl;
 import com.fs.course.service.IFsCourseLinkService;
+import com.fs.framework.security.LoginUser;
 import com.fs.framework.service.TokenService;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.dto.QwUserKeyDTO;
+import com.fs.qw.mapper.QwUserMapper;
 import com.fs.qw.param.GenerateShortLinkParam;
 import com.fs.qw.service.IQwUserService;
+import com.fs.sop.domain.QwSop;
 import com.fs.sop.domain.QwSopLogs;
 import com.fs.sop.params.QwSopLogsParam;
 import com.fs.sop.service.IQwSopLogsService;
 import com.fs.sop.vo.QwSopLogsListCVO;
+import com.fs.voice.utils.StringUtil;
 import org.apache.commons.lang3.tuple.Pair;
 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;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 import java.util.stream.Collectors;
 
 /**
@@ -50,6 +55,15 @@ public class QwSopLogsController extends BaseController
     @Autowired
     private IFsCourseLinkService linkService;
 
+    @Autowired
+    private QwUserMapper qwUserMapper;
+
+    @Autowired
+    private ICompanyUserService iCompanyUserService;
+
+    @Autowired
+    private CompanyDeptServiceImpl companyDeptService;
+
     /**
      * 查询企业微信SOP  定时任务列表
      */
@@ -57,12 +71,54 @@ public class QwSopLogsController extends BaseController
     @GetMapping("/listCVO")
     public TableDataInfo listCVO(QwSopLogsParam param)
     {
-        startPage();
+//        startPage();
+//        List<QwSopLogsListCVO> list = iQwSopLogsService.selectQwSopLogsListBySopId(param);
+//        if (!list.isEmpty()){
+//
+//            // 2. 提取不重复的 (qwUserId, corpId) 组合
+//            Set<QwUserKeyDTO> userCorpPairs = list.stream()
+//                    .filter(log -> log.getQwUserid() != null && log.getCorpId() != null)
+//                    .map(log -> new QwUserKeyDTO(log.getQwUserid(), log.getCorpId()))
+//                    .collect(Collectors.toSet());
+//
+//            // 3. 批量查询 qw_user 表
+//            List<QwUser> userList = iQwUserService.batchGetQwUser(new ArrayList<>(userCorpPairs));
+//
+//            // 4. 构建映射表
+//            Map<QwUserKeyDTO, String> userInfoMap = userList.stream()
+//                    .collect(Collectors.toMap(
+//                            user -> new QwUserKeyDTO(user.getQwUserId(), user.getCorpId()),
+//                            QwUser::getQwUserName
+//                    ));
+//
+//            // 5. 填充用户名
+//            list.forEach(log -> {
+//                QwUserKeyDTO key = new QwUserKeyDTO(log.getQwUserid(), log.getCorpId());
+//                log.setQwUserName(userInfoMap.getOrDefault(key, "未知用户"));
+//            });
+//
+//        }
+
+        List<String> qwUserIds=null;
+        if (!StringUtil.strIsNullOrEmpty(param.getQwUserName())){
+            qwUserIds = qwUserMapper.selectQwUserByQwUserName(param.getQwUserName(),param.getCorpId());
+        }
+        if (qwUserIds!=null&& !qwUserIds.isEmpty()){
+            param.setQwUseridList(qwUserIds);
+        }
+
+        if (!StringUtil.strIsNullOrEmpty(param.getQwUserName()) && (qwUserIds==null || qwUserIds.isEmpty())){
+            return getDataTable(new ArrayList<>());
+        }
+
 
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        param.setQwUserKeyList(getQwUserKeyList(param,loginUser));
+
+        startPage();
         List<QwSopLogsListCVO> list = iQwSopLogsService.selectQwSopLogsListBySopId(param);
 
         if (!list.isEmpty()){
-
             // 2. 提取不重复的 (qwUserId, corpId) 组合
             Set<QwUserKeyDTO> userCorpPairs = list.stream()
                     .filter(log -> log.getQwUserid() != null && log.getCorpId() != null)
@@ -84,14 +140,49 @@ public class QwSopLogsController extends BaseController
                 QwUserKeyDTO key = new QwUserKeyDTO(log.getQwUserid(), log.getCorpId());
                 log.setQwUserName(userInfoMap.getOrDefault(key, "未知用户"));
             });
-
         }
 
-
         return getDataTable(list);
     }
 
+    /**
+     * 我的自动化任务 和部门自动化任务 就只显示自己的或者部门的
+     */
+    private List<Long> getQwUserKeyList(QwSopLogsParam param, LoginUser loginUser) {
 
+        switch (param.getFilterSopType()) {
+            case 2:
+                CompanyUser companyUser = iCompanyUserService.selectCompanyUserById(loginUser.getUser().getUserId());
+                return Arrays.stream(companyUser.getQwUserId().split(","))
+                        .map(String::trim)
+                        .filter(s -> !s.isEmpty())
+                        .map(Long::valueOf)
+                        .collect(Collectors.toList());
+
+            case 3:
+                QwSop qwSop = new QwSop();
+                qwSop.setCompanyId(loginUser.getCompany().getCompanyId());
+
+                List<Long> combinedList = new ArrayList<>();
+                // 本部门
+                Long deptId = loginUser.getUser().getDeptId();
+                if (deptId != null) {
+                    combinedList.add(deptId);
+                }
+                // 本部门的下级部门
+                List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+                if (!deptList.isEmpty()) {
+                    combinedList.addAll(deptList);
+                }
+                qwSop.setCuDeptIdList(combinedList);
+                qwSop.setUserType(loginUser.getUser().getUserType());
+
+                return iQwUserService.selectQwUserListByCuDeptIdList(qwSop);
+
+            default:
+                return new ArrayList<>(); // 返回空列表而不是null
+        }
+    }
     /**
      * 查询企业微信SOP  定时任务列表
      */

+ 69 - 13
fs-company/src/main/java/com/fs/company/controller/qw/QwSopTempController.java

@@ -9,6 +9,7 @@ import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.service.impl.CompanyDeptServiceImpl;
 import com.fs.framework.security.LoginUser;
 import com.fs.framework.service.TokenService;
 import com.fs.qw.vo.SortDayVo;
@@ -41,6 +42,11 @@ public class QwSopTempController extends BaseController
     private IQwSopTempService qwSopTempService;
     @Autowired
     private TokenService tokenService;
+
+
+    @Autowired
+    private CompanyDeptServiceImpl companyDeptService;
+
     /**
      * 查询sop模板列表
      */
@@ -57,10 +63,59 @@ public class QwSopTempController extends BaseController
         return getDataTable(list);
     }
 
+    /**
+     * 查询我创建的sop模板列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:sopTemp:myList')")
+    @GetMapping("/myList")
+    public TableDataInfo myList(QwSopTemp qwSopTemp)
+    {
+
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        qwSopTemp.setCompanyId(loginUser.getCompany().getCompanyId());
+        qwSopTemp.setCreateBy(String.valueOf(loginUser.getUser().getUserId()));
+        startPage();
+//        List<QwSopTemp> list = qwSopTempService.selectQwSopTempList(qwSopTemp);
+        List<QwSopTemp> list = qwSopTempService.selectQwSopTempListNew(qwSopTemp);
+        return getDataTable(list);
+    }
+
+
+    /**
+     * 查询部门下的sop模板列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:sopTemp:deptList')")
+    @GetMapping("/deptList")
+    public TableDataInfo deptList(QwSopTemp qwSopTemp)
+    {
+
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        qwSopTemp.setCompanyId(loginUser.getCompany().getCompanyId());
+
+        List<Long> combinedDpetList = new ArrayList<>();
+        //本部门
+        Long deptId = loginUser.getUser().getDeptId();
+        if (deptId!=null){
+            combinedDpetList.add(deptId);
+        }
+        //本部门的下级部门
+        List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        if (!deptList.isEmpty()){
+            combinedDpetList.addAll(deptList);
+        }
+        qwSopTemp.setCuDeptIdList(combinedDpetList);
+
+        startPage();
+//        List<QwSopTemp> list = qwSopTempService.selectQwSopTempList(qwSopTemp);
+        List<QwSopTemp> list = qwSopTempService.selectQwSopTempListNew(qwSopTemp);
+        return getDataTable(list);
+    }
+
+
     /**
      * 导出sop模板列表
      */
-    @PreAuthorize("@ss.hasPermi('qw:sopTemp:export')")
+    @PreAuthorize("@ss.hasPermi('qw:sopTemp:export') or @ss.hasPermi('qw:sopTemp:myExport') or @ss.hasPermi('qw:sopTemp:deptExport')")
     @Log(title = "sop模板", businessType = BusinessType.EXPORT)
     @GetMapping("/export")
     public AjaxResult export(QwSopTemp qwSopTemp)
@@ -81,7 +136,7 @@ public class QwSopTempController extends BaseController
     /**
      * 新增sop模板
      */
-    @PreAuthorize("@ss.hasPermi('qw:sopTemp:add')")
+    @PreAuthorize("@ss.hasPermi('qw:sopTemp:add') or @ss.hasPermi('qw:sopTemp:myAdd') or @ss.hasPermi('qw:sopTemp:deptAdd')")
     @Log(title = "sop模板", businessType = BusinessType.INSERT)
     @PostMapping
     public AjaxResult add(@RequestBody QwSopTemp qwSopTemp){
@@ -94,7 +149,7 @@ public class QwSopTempController extends BaseController
     /**
      * 修改sop模板
      */
-    @PreAuthorize("@ss.hasPermi('qw:sopTemp:edit')")
+    @PreAuthorize("@ss.hasPermi('qw:sopTemp:edit') or @ss.hasPermi('qw:sopTemp:myEdit') or @ss.hasPermi('qw:sopTemp:deptEdit')")
     @Log(title = "sop模板", businessType = BusinessType.UPDATE)
     @PutMapping
     public AjaxResult edit(@RequestBody QwSopTemp qwSopTemp)
@@ -109,7 +164,7 @@ public class QwSopTempController extends BaseController
     /**
      * 删除sop模板
      */
-    @PreAuthorize("@ss.hasPermi('qw:sopTemp:remove')")
+    @PreAuthorize("@ss.hasPermi('qw:sopTemp:remove') or @ss.hasPermi('qw:sopTemp:myRemove') or @ss.hasPermi('qw:sopTemp:deptRemove')")
     @Log(title = "sop模板", businessType = BusinessType.DELETE)
 	@DeleteMapping("/{ids}")
     public AjaxResult remove(@PathVariable String[] ids)
@@ -120,7 +175,7 @@ public class QwSopTempController extends BaseController
     }
 
     /** 分享sop模板 */
-    @PreAuthorize("@ss.hasPermi('qw:sopTemp:share')")
+    @PreAuthorize("@ss.hasPermi('qw:sopTemp:share') or @ss.hasPermi('qw:sopTemp:myShare') or @ss.hasPermi('qw:sopTemp:deptShare')")
     @Log(title = "分享sop模板", businessType = BusinessType.DELETE)
     @PostMapping("/shareTemp")
     public AjaxResult shareTemp(@RequestBody QwSopShareTempParam param)
@@ -130,7 +185,7 @@ public class QwSopTempController extends BaseController
 
 
 
-    @PreAuthorize("@ss.hasPermi('qw:sopTemp:add')")
+    @PreAuthorize("@ss.hasPermi('qw:sopTemp:add') or @ss.hasPermi('qw:sopTemp:myAdd') or @ss.hasPermi('qw:sopTemp:deptAdd')")
     @Log(title = "sop模板addNew", businessType = BusinessType.INSERT)
     @PostMapping("/add")
     public AjaxResult addNew(@RequestBody QwSopTemp qwSopTemp){
@@ -148,7 +203,7 @@ public class QwSopTempController extends BaseController
         return toAjax(i);
     }
 
-    @PreAuthorize("@ss.hasPermi('qw:sopTemp:edit')")
+    @PreAuthorize("@ss.hasPermi('qw:sopTemp:edit') or @ss.hasPermi('qw:sopTemp:myEdit') or @ss.hasPermi('qw:sopTemp:deptEdit')")
     @Log(title = "sop模板update", businessType = BusinessType.UPDATE)
     @PostMapping("/update")
     public AjaxResult updateNew(@RequestBody QwSopTemp qwSopTemp){
@@ -156,41 +211,42 @@ public class QwSopTempController extends BaseController
         return toAjax(update);
     }
 
-    @PreAuthorize("@ss.hasPermi('qw:sopTemp:edit')")
+    @PreAuthorize("@ss.hasPermi('qw:sopTemp:edit') or @ss.hasPermi('qw:sopTemp:myEdit') or @ss.hasPermi('qw:sopTemp:deptEdit')")
     @Log(title = "addOrUpdateSop模板规则", businessType = BusinessType.UPDATE)
     @PostMapping("/addOrUpdateSetting")
     public AjaxResult addOrUpdateSetting(@RequestBody QwSopTempDay day){
         return AjaxResult.success(qwSopTempService.addOrUpdateSetting(day));
     }
 
-    @PreAuthorize("@ss.hasPermi('qw:sopTemp:edit')")
+    @PreAuthorize("@ss.hasPermi('qw:sopTemp:edit') or @ss.hasPermi('qw:sopTemp:myEdit') or @ss.hasPermi('qw:sopTemp:deptEdit')")
     @Log(title = "sop模板规则delRules", businessType = BusinessType.DELETE)
     @GetMapping("/delRules")
     public AjaxResult delRules(Long id){
         qwSopTempService.delRules(id);
         return toAjax(1);
     }
-    @PreAuthorize("@ss.hasPermi('qw:sopTemp:list')")
+
+    @PreAuthorize("@ss.hasPermi('qw:sopTemp:list') or @ss.hasPermi('qw:sopTemp:myList') or @ss.hasPermi('qw:sopTemp:deptList')")
     @GetMapping("/selectRulesInfo")
     public AjaxResult selectRulesInfo(Long id){
         return AjaxResult.success(qwSopTempService.selectRulesInfo(id));
     }
 
-    @PreAuthorize("@ss.hasPermi('qw:sopTemp:edit')")
+    @PreAuthorize("@ss.hasPermi('qw:sopTemp:edit') or @ss.hasPermi('qw:sopTemp:myEdit') or @ss.hasPermi('qw:sopTemp:deptEdit')")
     @PostMapping("/copyTemplate")
     public AjaxResult copyTemplate(@RequestBody QwSopTemp qwSopTemp){
         qwSopTempService.copyTemplate(qwSopTemp);
         return toAjax(1);
     }
 
-    @PreAuthorize("@ss.hasPermi('qw:sopTemp:edit')")
+    @PreAuthorize("@ss.hasPermi('qw:sopTemp:edit') or @ss.hasPermi('qw:sopTemp:myEdit') or @ss.hasPermi('qw:sopTemp:deptEdit')")
     @PostMapping("/sortDay")
     public AjaxResult sortDay(@RequestBody List<SortDayVo> list){
         qwSopTempService.sortDay(list);
         return toAjax(1);
     }
 
-    @PreAuthorize("@ss.hasPermi('qw:sopTemp:edit')")
+    @PreAuthorize("@ss.hasPermi('qw:sopTemp:edit') or @ss.hasPermi('qw:sopTemp:myEdit') or @ss.hasPermi('qw:sopTemp:deptEdit')")
     @GetMapping("/dayList")
     public AjaxResult dayList(String id){
         return AjaxResult.success(qwSopTempService.dayList(id));

+ 53 - 6
fs-company/src/main/java/com/fs/company/controller/qw/SopUserLogsController.java

@@ -7,7 +7,10 @@ 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.ServletUtils;
+import com.fs.framework.security.LoginUser;
 import com.fs.framework.service.TokenService;
+import com.fs.qw.domain.QwUser;
 import com.fs.qw.mapper.QwUserMapper;
 import com.fs.qw.param.SopUserLogsVO;
 import com.fs.qw.service.IQwUserService;
@@ -15,15 +18,19 @@ import com.fs.qw.vo.AddSopUserGroupChat;
 import com.fs.qw.vo.UpdateSopUserLogDateVo;
 import com.fs.sop.domain.QwSop;
 import com.fs.sop.domain.SopUserLogs;
+import com.fs.sop.dto.SopUserLogsParamDTO;
 import com.fs.sop.mapper.QwSopMapper;
 import com.fs.sop.params.SopUserLogsParam;
 import com.fs.sop.service.ISopUserLogsService;
+import com.fs.voice.utils.StringUtil;
 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;
+import java.util.Map;
+import java.util.stream.Collectors;
 
 /**
  * sopUserLogsController
@@ -46,6 +53,9 @@ public class SopUserLogsController extends BaseController
     @Autowired
     private QwSopMapper sopMapper;
 
+    @Autowired
+    private IQwUserService iQwUserService;
+
     /**
      * 查询sopUserLogs列表
      */
@@ -55,22 +65,59 @@ public class SopUserLogsController extends BaseController
     {
         sopUserLogs.setStatus(1);
 
+        List<String> qwUserIds=null;
+        if (!StringUtil.strIsNullOrEmpty(sopUserLogs.getQwUserName())){
+            qwUserIds = qwUserMapper.selectQwUserByQwUserName(sopUserLogs.getQwUserName(),sopUserLogs.getCorpId());
+        }
+        if (qwUserIds!=null&& !qwUserIds.isEmpty()){
+            sopUserLogs.setQwUseridList(qwUserIds);
+        }
+
+        if (!StringUtil.strIsNullOrEmpty(sopUserLogs.getQwUserName()) && (qwUserIds==null || qwUserIds.isEmpty())){
+            return getDataTable(new ArrayList<>());
+        }
+
         QwSop qwSop = sopMapper.selectQwSopById(sopUserLogs.getSopId());
         Integer filterMode = qwSop.getFilterMode();
 
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+
+        List<String> qwUserIdList=null;
+        if (sopUserLogs.getType()==2){
+            qwUserIdList = iQwUserService.selectQwUserListByCompanyUserId(loginUser.getUser().getUserId(), sopUserLogs.getCorpId());
+        }
+        if (qwUserIdList!=null&& !qwUserIdList.isEmpty() && sopUserLogs.getType()==2 ){
+            sopUserLogs.setQwIdsList(qwUserIdList);
+        }
+
         List<SopUserLogsVO> list=null;
         if(filterMode == null || filterMode == 1){
             startPage();
-             list = sopUserLogsService.selectSopUserLogsList(sopUserLogs);
+            list = sopUserLogsService.selectSopUserLogsList(sopUserLogs);
         }else {
             startPage();
             list = sopUserLogsService.selectSopUserLogsGroupListByParam(sopUserLogs);
         }
-
-        list.forEach(item->{
-            item.setQwUserName(qwUserMapper.selectQwUserByQwUserIdAndCorpId(item.getQwUserId(), item.getCorpId()));
-        });
-
+        if (!list.isEmpty()){
+            // 收集所有需要查询的 qwUserId 和 corpId 组合
+            List<SopUserLogsParamDTO> queryList = list.stream()
+                    .map(item -> new SopUserLogsParamDTO(item.getQwUserId(), item.getCorpId()))
+                    .distinct()  // 去重
+                    .collect(Collectors.toList());
+
+            List<QwUser> userList = qwUserMapper.batchSelectQwUserByQwUserIdAndCorpId(queryList);
+            Map<String, String> userMap = userList.stream()
+                    .collect(Collectors.toMap(
+                            user -> user.getQwUserId() + "_" + user.getCorpId(),
+                            QwUser::getQwUserName
+                    ));
+
+            // 设置用户名
+            list.forEach(item -> {
+                String key = item.getQwUserId() + "_" + item.getCorpId();
+                item.setQwUserName(userMap.get(key));
+            });
+        }
         return getDataTable(list);
     }
 

+ 134 - 32
fs-company/src/main/java/com/fs/company/controller/qw/SopUserLogsInfoController.java

@@ -31,6 +31,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
+import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
@@ -89,6 +90,7 @@ public class SopUserLogsInfoController extends BaseController
                                 QwExternalContactVOTime::getId,
                                 item -> new SopExternalContactInfo(item.getCreateTime(), item.getTagIds(), item.getRemark(),item.getLevel())
                         ));
+
                 List<String> tagIds = qwExternalContactVOTimes.stream().map(QwExternalContactVOTime::getTagIds).filter(StringUtils::isNotEmpty).flatMap(e -> JSON.parseArray(e, String.class).stream()).collect(Collectors.toList());
                 if(!tagIds.isEmpty()){
                     List<QwTag> tagList = qwTagMapper.selectQwTagListByTagIdsNew(tagIds);
@@ -114,22 +116,14 @@ public class SopUserLogsInfoController extends BaseController
                 });
             }
 
-            Predicate<SopUserLogsInfo> tagFilter = item -> {
-                String queryTagIds = sopUserLogsInfo.getTagIds();
-                String itemTagIds = item.getTagIds();
-
-                if (queryTagIds == null || queryTagIds.trim().equals("[]")) {
-                    return true;
-                }
-                List<String> queryTags = parseTagIds(queryTagIds);
-                List<String> itemTags = parseTagIds(itemTagIds);
-
-                // 检查 itemTags 是否包含所有 queryTags(AND 关系)
-                return itemTags.containsAll(queryTags);
-            };
-
             // 优化过滤条件
             boolean isRemarkEmpty = StringUtil.strIsNullOrEmpty(sopUserLogsInfo.getRemark());
+
+            Predicate<SopUserLogsInfo> tagFilter = item ->
+                    sopUserLogsInfo.getTagIds() == null ||
+                            sopUserLogsInfo.getTagIds().isEmpty() ||
+                            item.getTagIds().contains(sopUserLogsInfo.getTagIds());
+
             Predicate<SopUserLogsInfo> remarkFilter = item ->
                     isRemarkEmpty ||
                             item.getRemark().contains(sopUserLogsInfo.getRemark());
@@ -142,34 +136,25 @@ public class SopUserLogsInfoController extends BaseController
 
 
             Predicate<SopUserLogsInfo> timeFilter = item -> {
-
-                if (StringUtil.strIsNullOrEmpty(sopUserLogsInfo.getInComingSTime())
-                        && StringUtil.strIsNullOrEmpty(sopUserLogsInfo.getInComingETime()) ) {
+                if (StringUtil.strIsNullOrEmpty(sopUserLogsInfo.getEntryTime())) {
                     return true;
                 }
                 try {
-                    LocalDateTime entryDate = LocalDateTime.parse(item.getInComTime(),
-                            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
+                    LocalDate entryDate = LocalDate.parse(
+                            sopUserLogsInfo.getEntryTime(),
+                            DateTimeFormatter.ofPattern("yyyy-MM-dd")
                     );
-                    LocalDateTime inComingSTime = LocalDateTime.parse(sopUserLogsInfo.getInComingSTime(),
-                            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
+                    LocalDate createDate = LocalDate.parse(
+                            item.getInComTime().substring(0, 10),
+                            DateTimeFormatter.ofPattern("yyyy-MM-dd")
                     );
-
-                    LocalDateTime inComingETime = LocalDateTime.parse(sopUserLogsInfo.getInComingETime(),
-                            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
-                    );
-
-                    return !entryDate.isBefore(inComingSTime) && !entryDate.isAfter(inComingETime);
+                    return entryDate.equals(createDate);
                 } catch (Exception e) {
                     return false;
                 }
             };
 
-
-            boolean hasTimeFilter = !StringUtil.strIsNullOrEmpty(sopUserLogsInfo.getInComingSTime())
-                    && !StringUtil.strIsNullOrEmpty(sopUserLogsInfo.getInComingETime());
-
-            if (sopUserLogsInfo.getTagIds() != null || !isRemarkEmpty || hasTimeFilter ||!isLevelEmpty) {
+            if (sopUserLogsInfo.getTagIds() != null || !isRemarkEmpty || !StringUtil.strIsNullOrEmpty(sopUserLogsInfo.getEntryTime()) ||!isLevelEmpty) {
                 list = list.stream()
                         .filter(tagFilter.and(remarkFilter).and(timeFilter).and(levelFilter))
                         .collect(Collectors.toList());
@@ -188,6 +173,123 @@ public class SopUserLogsInfoController extends BaseController
                 item.setLevelName(getLevel(item.getLevel()));
             });
 
+//            List<SopUserLogsInfo> list = sopUserLogsInfoService.selectSopUserLogsInfoList(sopUserLogsInfo);
+//
+//            if (!list.isEmpty()) {
+//                // 使用并行流提取externalId
+//                List<Long> externalIdList = list.parallelStream()
+//                        .map(SopUserLogsInfo::getExternalId)
+//                        .filter(Objects::nonNull)
+//                        .collect(Collectors.toList());
+//
+//                List<QwExternalContactVOTime> qwExternalContactVOTimes =
+//                        iQwExternalContactService.selectQwExternalContactListVOByIds(externalIdList);
+//
+//                // 构建联系人信息映射
+//                Map<Long, SopExternalContactInfo> externalContactInfoMap = qwExternalContactVOTimes.stream()
+//                        .collect(Collectors.toMap(
+//                                QwExternalContactVOTime::getId,
+//                                item -> new SopExternalContactInfo(item.getCreateTime(), item.getTagIds(), item.getRemark(),item.getLevel())
+//                        ));
+//                List<String> tagIds = qwExternalContactVOTimes.stream().map(QwExternalContactVOTime::getTagIds).filter(StringUtils::isNotEmpty).flatMap(e -> JSON.parseArray(e, String.class).stream()).collect(Collectors.toList());
+//                if(!tagIds.isEmpty()){
+//                    List<QwTag> tagList = qwTagMapper.selectQwTagListByTagIdsNew(tagIds);
+//                    Map<String, QwTag> tagMap = PubFun.listToMapByGroupObject(tagList, QwTag::getTagId);
+//                    qwExternalContactVOTimes.forEach(e -> {
+//                        List<String> tagId = JSON.parseArray(e.getTagIds(), String.class);
+//                        if(StringUtils.isNotEmpty(tagId)){
+//                            List<String> tagNameList = tagId.stream().filter(tagMap::containsKey).map(t -> tagMap.get(t).getName()).filter(StringUtils::isNotEmpty).collect(Collectors.toList());
+//                            e.setTagIdsName(tagNameList);
+//                        }
+//                    });
+//                }
+//                // 设置联系信息
+//                list.forEach(item -> {
+//                    SopExternalContactInfo info = externalContactInfoMap.getOrDefault(
+//                            item.getExternalId(),
+//                            new SopExternalContactInfo("无进线时间", "无标签", "无备注",0));
+//                    item.setInComTime(info.getCreateTime());
+//                    item.setTagIds(info.getTagIds());
+//                    item.setRemark(info.getRemark());
+//                    item.setLevel(info.getLevel());
+//
+//                });
+//            }
+//
+//            Predicate<SopUserLogsInfo> tagFilter = item -> {
+//                String queryTagIds = sopUserLogsInfo.getTagIds();
+//                String itemTagIds = item.getTagIds();
+//
+//                if (queryTagIds == null || queryTagIds.trim().equals("[]")) {
+//                    return true;
+//                }
+//                List<String> queryTags = parseTagIds(queryTagIds);
+//                List<String> itemTags = parseTagIds(itemTagIds);
+//
+//                // 检查 itemTags 是否包含所有 queryTags(AND 关系)
+//                return itemTags.containsAll(queryTags);
+//            };
+//
+//            // 优化过滤条件
+//            boolean isRemarkEmpty = StringUtil.strIsNullOrEmpty(sopUserLogsInfo.getRemark());
+//            Predicate<SopUserLogsInfo> remarkFilter = item ->
+//                    isRemarkEmpty ||
+//                            item.getRemark().contains(sopUserLogsInfo.getRemark());
+//
+//
+//            boolean isLevelEmpty = sopUserLogsInfo.getLevel() == null;
+//            Predicate<SopUserLogsInfo> levelFilter = item ->
+//                    isLevelEmpty ||
+//                            (item.getLevel() != null && Objects.equals(item.getLevel(), sopUserLogsInfo.getLevel()) );
+//
+//
+//            Predicate<SopUserLogsInfo> timeFilter = item -> {
+//
+//                if (StringUtil.strIsNullOrEmpty(sopUserLogsInfo.getInComingSTime())
+//                        && StringUtil.strIsNullOrEmpty(sopUserLogsInfo.getInComingETime()) ) {
+//                    return true;
+//                }
+//                try {
+//                    LocalDateTime entryDate = LocalDateTime.parse(item.getInComTime(),
+//                            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
+//                    );
+//                    LocalDateTime inComingSTime = LocalDateTime.parse(sopUserLogsInfo.getInComingSTime(),
+//                            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
+//                    );
+//
+//                    LocalDateTime inComingETime = LocalDateTime.parse(sopUserLogsInfo.getInComingETime(),
+//                            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
+//                    );
+//
+//                    return !entryDate.isBefore(inComingSTime) && !entryDate.isAfter(inComingETime);
+//                } catch (Exception e) {
+//                    return false;
+//                }
+//            };
+//
+//
+//            boolean hasTimeFilter = !StringUtil.strIsNullOrEmpty(sopUserLogsInfo.getInComingSTime())
+//                    && !StringUtil.strIsNullOrEmpty(sopUserLogsInfo.getInComingETime());
+//
+//            if (sopUserLogsInfo.getTagIds() != null || !isRemarkEmpty || hasTimeFilter ||!isLevelEmpty) {
+//                list = list.stream()
+//                        .filter(tagFilter.and(remarkFilter).and(timeFilter).and(levelFilter))
+//                        .collect(Collectors.toList());
+//            }
+//
+//            // 处理标签名称
+//            list.parallelStream().forEach(item -> {
+//                if (item.getTagIds() != null && !item.getTagIds().equals("[]") && !item.getTagIds().equals("无标签")) {
+//                    List<String> tagIds = GSON.fromJson(item.getTagIds(), new TypeToken<List<String>>() {}.getType());
+//                    QwTagSearchParam param = new QwTagSearchParam();
+//                    param.setTagIds(tagIds);
+//                    item.setTagIdsName(iQwTagService.selectQwTagListByTagIds(param));
+//                }
+//
+//                // 处理 level
+//                item.setLevelName(getLevel(item.getLevel()));
+//            });
+
             return getDataTable(list);
         }
         else {

+ 1 - 1
fs-company/src/main/java/com/fs/company/controller/store/FsUserController.java

@@ -67,7 +67,7 @@ public class FsUserController extends BaseController
         startPage();
         LoginUser loginUser = SecurityUtils.getLoginUser();
         fsUser.setCompanyId(loginUser.getCompany().getCompanyId());
-        if(fsUser.getPhoneMk()!=null&&fsUser.getPhone()!=""){
+        if(fsUser.getPhoneMk()!=null&&StringUtils.isBlank(fsUser.getPhone())){
             fsUser.setPhone(encryptPhone(fsUser.getPhoneMk()));
         }
 

+ 1 - 1
fs-company/src/main/java/com/fs/hisStore/controller/FsStoreProductScrmController.java

@@ -37,7 +37,7 @@ public class FsStoreProductScrmController extends BaseController
     /**
      * 查询商品列表
      */
-    @PreAuthorize("@ss.hasPermi('store:storeProduct:list')")
+//    @PreAuthorize("@ss.hasPermi('store:storeProduct:list')")
     @GetMapping("/list")
     public TableDataInfo list(FsStoreProductScrm fsStoreProduct)
     {

+ 0 - 3
fs-framework/src/main/java/com/fs/framework/config/LogInterceptor.java

@@ -1,7 +1,5 @@
 package com.fs.framework.config;
 
-
-
 import org.slf4j.MDC;
 import org.springframework.stereotype.Component;
 import org.springframework.util.StringUtils;
@@ -11,7 +9,6 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.util.UUID;
 
-
 /**
  * @description: 日志拦截器
  * @author: xdd

+ 72 - 0
fs-qwhook/src/main/java/com/fs/app/controller/ApisQwUserController.java

@@ -1,10 +1,22 @@
 package com.fs.app.controller;
 
+import com.fs.app.params.LoginBindCompanyParam;
 import com.fs.common.BeanCopyUtils;
+import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
 import com.fs.common.exception.CustomException;
+import com.fs.common.exception.base.BaseException;
+import com.fs.common.utils.PatternUtils;
+import com.fs.common.utils.SecurityUtils;
+import com.fs.company.domain.Company;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.param.CompanyUserCodeParam;
+import com.fs.company.service.ICompanyPostService;
+import com.fs.company.service.ICompanyService;
+import com.fs.company.service.ICompanyUserService;
 import com.fs.course.param.FsCourseListBySidebarParam;
 import com.fs.qw.domain.QwExternalContactInfo;
 import com.fs.qw.domain.QwTagGroup;
@@ -32,6 +44,7 @@ import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.HashMap;
@@ -56,6 +69,19 @@ public class ApisQwUserController extends BaseController {
     @Autowired
     private ISopUserLogsInfoService iSopUserLogsInfoService;
 
+    @Autowired
+    private ICompanyUserService companyUserService;
+
+    @Autowired
+    ICompanyUserService userService;
+
+    @Autowired
+    private ICompanyService companyService;
+
+    @Autowired
+    ICompanyPostService postService;
+
+
 
     @GetMapping("/details")
     @ApiOperation("会员看课详情")
@@ -184,5 +210,51 @@ public class ApisQwUserController extends BaseController {
         return R.error();
     }
 
+    /**
+     * 注册或者绑定销售
+     */
+    @PostMapping("/registerCompany")
+    @Log(title = "注册或者绑定销售", businessType = BusinessType.INSERT)
+    public R registerCompany(@RequestBody CompanyUserCodeParam userCodeParam) {
+        return companyUserService.registerCompany(userCodeParam);
+    }
+
+    @PostMapping("/login")
+    @ApiOperation("密码登录")
+    public R login(@Validated @RequestBody LoginBindCompanyParam param) {
+
+        // 密码校验
+        if (!PatternUtils.checkPassword(param.getPassword())) {
+            return R.error("密码格式不正确,需包含字母、数字和特殊字符,长度为 8-20位");
+        }
+
+        try {
+
+            //判断用户基本规则
+            CompanyUser companyUser = userService.selectUserByUserName(param.getAccount());
+            if (companyUser == null) {
+                return R.error("工号不存在");
+            }
+            if (companyUser.getStatus().equals("1")) {
+                return R.error("用户已禁用");
+            }
+            if (!SecurityUtils.matchesPassword(param.getPassword(), companyUser.getPassword())) {
+                return R.error("密码错误");
+            }
+            if (companyUser.getIsAudit() == 0) {
+                return R.error("用户未审核");
+            }
+
+            Company company = companyService.selectCompanyById(companyUser.getCompanyId());
+            if (company == null || company.getStatus() == 0 || company.getIsDel() == 1) {
+                throw new BaseException("此用户所属公司不存在或已停用");
+            }
+
+            return R.ok("验证成功");
+        } catch (Exception e) {
+            return R.error("登录异常:"+e.getMessage());
+        }
+    }
+
 
 }

+ 0 - 4
fs-qwhook/src/main/java/com/fs/app/controller/QwUserController.java

@@ -217,10 +217,6 @@ public class QwUserController extends BaseController {
                 throw new BaseException("此用户所属公司不存在或已停用");
             }
 
-            if (StringUtils.isNotEmpty(company.getCourseMiniAppId()) && !company.getCourseMiniAppId().equals(param.getAppid())){
-                return R.error("登录用户不属于该小程序");
-            }
-
             return R.ok("验证成功");
         } catch (Exception e) {
             return R.error("登录异常:"+e.getMessage());

+ 0 - 4
fs-qwhook/src/main/java/com/fs/app/params/LoginBindCompanyParam.java

@@ -14,8 +14,4 @@ public class LoginBindCompanyParam {
     private String account;
     @NotBlank(message = "请填写密码")
     private String password;
-
-    private String jpushId;
-    @JsonAlias({"appid", "appId"})
-    private String appid;
 }

+ 3 - 0
fs-service/src/main/java/com/fs/company/domain/CompanyUser.java

@@ -87,6 +87,9 @@ public class CompanyUser extends BaseEntity
     private String qwUserId;
     private Integer qwStatus;
 
+    /** 医生id */
+    private Long doctorId;
+
     public String getIdCard() {
         return idCard;
     }

+ 3 - 0
fs-service/src/main/java/com/fs/company/mapper/CompanyUserMapper.java

@@ -312,4 +312,7 @@ public interface CompanyUserMapper
     int insertQwIpadTotal(List<QwIpadTotalVo> qwIpadTotalVos);
 
     void uploadQrCode(@Param("userId") String userId, @Param("url") String url);
+
+    @Update("update company_user set doctor_id = null where user_id = #{userId}")
+    public int unBindDoctorId(@Param("userId")Long userId);
 }

+ 4 - 0
fs-service/src/main/java/com/fs/company/service/ICompanyUserService.java

@@ -228,4 +228,8 @@ public interface ICompanyUserService {
     int insertQwIpadTotal(List<QwIpadTotalVo> qwIpadTotalVos);
 
     String uploadQrCode(MultipartFile file,String userId) throws IOException;
+
+    R bindDoctor(CompanyUser param);
+
+    R unBindDoctor(Long userId);
 }

+ 41 - 13
fs-service/src/main/java/com/fs/company/service/impl/CompanyUserServiceImpl.java

@@ -2,12 +2,9 @@ package com.fs.company.service.impl;
 
 import cn.hutool.core.util.ObjectUtil;
 import com.alibaba.fastjson.JSON;
-import com.fs.common.BeanCopyUtils;
 import com.fs.common.annotation.DataScope;
 import com.fs.common.constant.UserConstants;
-import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.R;
-import com.fs.common.core.domain.model.LoginUser;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.exception.CustomException;
 import com.fs.common.exception.ServiceException;
@@ -651,6 +648,7 @@ public class CompanyUserServiceImpl implements ICompanyUserService
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public void auditUsers(List<Long> userIds,Long companyId) {
         if (userIds.isEmpty()) {
             return;
@@ -677,10 +675,14 @@ public class CompanyUserServiceImpl implements ICompanyUserService
             companyUserList.stream().forEach(c->{
                 //判断角色是否为空
                 if(ObjectUtil.isNotNull(role)){
-                    CompanyUserRole userRole=new CompanyUserRole();
-                    userRole.setRoleId(role.getRoleId());
-                    userRole.setUserId(c.getUserId());
-                    companyUserRoleList.add(userRole);
+                    //判断该用户角色是否存在
+                    CompanyUserRole companyUserRole = userRoleMapper.selectCompanyUserRoleById(c.getUserId());
+                    if(companyUserRole == null || !Objects.equals(companyUserRole.getRoleId(), role.getRoleId())){
+                        CompanyUserRole userRole=new CompanyUserRole();
+                        userRole.setRoleId(role.getRoleId());
+                        userRole.setUserId(c.getUserId());
+                        companyUserRoleList.add(userRole);
+                    }
                 }
 
                 //判断部门
@@ -690,13 +692,16 @@ public class CompanyUserServiceImpl implements ICompanyUserService
 
                 //判断岗位
                 if(ObjectUtil.isNotNull(companyPost)){
-                    //添加用户岗位表
-                    CompanyUserPost userPost=new CompanyUserPost();
-                    userPost.setPostId(companyPost.getPostId());
-                    userPost.setUserId(c.getUserId());
-                    companyUserPosts.add(userPost);
+                    //判断该岗位是否存在
+                    CompanyUserPost companyUserPost = userPostMapper.selectCompanyUserPostById(c.getUserId());
+                    if(companyUserPost == null || !Objects.equals(companyUserPost.getPostId(), companyPost.getPostId())){
+                        //添加用户岗位表
+                        CompanyUserPost userPost=new CompanyUserPost();
+                        userPost.setPostId(companyPost.getPostId());
+                        userPost.setUserId(c.getUserId());
+                        companyUserPosts.add(userPost);
+                    }
                 }
-
             });
 
             //批量插入角色用户中间表
@@ -779,4 +784,27 @@ public class CompanyUserServiceImpl implements ICompanyUserService
         companyUserMapper.uploadQrCode(userId,url);
         return url;
     }
+
+    @Override
+    public R bindDoctor(CompanyUser companyUser) {
+        CompanyUser map = new CompanyUser();
+        map.setUserId(companyUser.getUserId());
+        map.setDoctorId(companyUser.getDoctorId());
+        int i = companyUserMapper.updateCompanyUser(map);
+        if (i > 0) {
+            return R.ok();
+        } else {
+            return R.error();
+        }
+    }
+
+    @Override
+    public R unBindDoctor(Long userId) {
+        int i = companyUserMapper.unBindDoctorId(userId);
+        if (i > 0) {
+            return R.ok();
+        } else {
+            return R.error();
+        }
+    }
 }

+ 65 - 0
fs-service/src/main/java/com/fs/complaint/domain/FsComplaint.java

@@ -0,0 +1,65 @@
+package com.fs.complaint.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDateTime;
+
+/**
+ * 投诉表实体类
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class FsComplaint {
+
+    /**
+     * 主键ID
+     */
+    private Long id;
+
+    /**
+     * 投诉单号
+     */
+    private String complaintNo;
+
+    /**
+     * 投诉分类ID
+     */
+    private Long categoryId;
+    /**
+     * 投诉分类名称
+     */
+    private String categoryName;
+
+    /**
+     * 投诉内容
+     */
+    private String content;
+
+    /**
+     * 联系手机号
+     */
+    private String contactPhone;
+
+    /**
+     * 联系邮箱
+     */
+    private String contactEmail;
+
+    /**
+     * 状态:1-待处理,2-处理中,3-已完成,4-已关闭
+     */
+    private Integer status;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+}

+ 51 - 0
fs-service/src/main/java/com/fs/complaint/domain/FsComplaintAttachment.java

@@ -0,0 +1,51 @@
+package com.fs.complaint.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDateTime;
+
+/**
+ * 投诉附件表实体类
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class FsComplaintAttachment {
+
+    /**
+     * 主键ID
+     */
+    private Long id;
+
+    /**
+     * 投诉ID
+     */
+    private Long complaintId;
+
+    /**
+     * 文件名
+     */
+    private String fileName;
+
+    /**
+     * 文件路径
+     */
+    private String filePath;
+
+    /**
+     * 文件大小(字节)
+     */
+    private Long fileSize;
+
+    /**
+     * 文件类型
+     */
+    private String fileType;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+}

+ 55 - 0
fs-service/src/main/java/com/fs/complaint/domain/FsComplaintCategory.java

@@ -0,0 +1,55 @@
+package com.fs.complaint.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * 投诉分类表实体类
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class FsComplaintCategory implements Serializable {
+
+    /**
+     * 主键ID
+     */
+    private Long id;
+
+    /**
+     * 分类名称
+     */
+    private String categoryName;
+
+    private Long userId;
+    private Long companyUserId;
+
+    /**
+     * 分类编码
+     */
+    private String categoryCode;
+
+    /**
+     * 排序
+     */
+    private Integer sortOrder;
+
+    /**
+     * 状态:1-启用,0-禁用
+     */
+    private Integer status;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+}

+ 20 - 0
fs-service/src/main/java/com/fs/complaint/dto/ComplaintQueryDTO.java

@@ -0,0 +1,20 @@
+package com.fs.complaint.dto;
+
+import lombok.Data;
+
+/**
+ * 投诉查询条件参数
+ */
+@Data
+public class ComplaintQueryDTO {
+
+    private String complaintNo;
+    private Long categoryId;
+    private String categoryName;
+    private Integer status;
+    private String contactPhone;
+    private String startTime;
+    private String endTime;
+    private Integer pageNum = 1;
+    private Integer pageSize = 10;
+}

+ 29 - 0
fs-service/src/main/java/com/fs/complaint/dto/SubmitComplaintDTO.java

@@ -0,0 +1,29 @@
+package com.fs.complaint.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+public class SubmitComplaintDTO implements Serializable {
+    /**
+     * 投诉类型
+     */
+    private Long type;
+
+    /**
+     * 投诉类型
+     */
+    private String content;
+
+    /**
+     * 凭证列表
+     */
+    private List<String> url;
+
+    /**
+     * 联系方式
+     */
+    private String contact;
+}

+ 16 - 0
fs-service/src/main/java/com/fs/complaint/dto/UpdateComplaintDTO.java

@@ -0,0 +1,16 @@
+package com.fs.complaint.dto;
+
+import lombok.Data;
+
+/**
+ * 更新投诉请求参数
+ */
+@Data
+public class UpdateComplaintDTO {
+
+    private Long categoryId;
+    private String content;
+    private String contactPhone;
+    private String contactEmail;
+    private Integer status;
+}

+ 59 - 0
fs-service/src/main/java/com/fs/complaint/mapper/FsComplaintAttachmentMapper.java

@@ -0,0 +1,59 @@
+package com.fs.complaint.mapper;
+
+import com.fs.complaint.domain.FsComplaintAttachment;
+import org.apache.ibatis.annotations.*;
+
+import java.util.List;
+
+/**
+ * 投诉附件表数据访问层
+ */
+@Mapper
+public interface FsComplaintAttachmentMapper {
+
+    /**
+     * 根据ID查询附件信息
+     */
+    @Select("SELECT * FROM fs_complaint_attachment WHERE id = #{id}")
+    FsComplaintAttachment selectById(Long id);
+
+    /**
+     * 根据投诉ID查询附件列表
+     */
+    @Select("SELECT * FROM fs_complaint_attachment WHERE complaint_id = #{complaintId}")
+    List<FsComplaintAttachment> selectByComplaintId(Long complaintId);
+
+    /**
+     * 插入附件信息
+     */
+    @Insert("INSERT INTO fs_complaint_attachment(complaint_id, file_name, file_path, file_size, file_type) " +
+            "VALUES(#{complaintId}, #{fileName}, #{filePath}, #{fileSize}, #{fileType})")
+    @Options(useGeneratedKeys = true, keyProperty = "id")
+    int insert(FsComplaintAttachment attachment);
+
+    /**
+     * 根据ID删除附件信息
+     */
+    @Update("DELETE FROM fs_complaint_attachment WHERE id = #{id}")
+    int deleteById(Long id);
+
+    /**
+     * 根据投诉ID删除附件信息
+     */
+    @Update("DELETE FROM fs_complaint_attachment WHERE complaint_id = #{complaintId}")
+    int deleteByComplaintId(Long complaintId);
+
+
+    /**
+     * 批量插入附件信息
+     */
+    @Insert("<script>" +
+            "INSERT INTO fs_complaint_attachment(complaint_id, file_name, file_path, file_size, file_type) VALUES " +
+            "<foreach collection='list' item='item' separator=','>" +
+            "(#{item.complaintId}, #{item.fileName}, #{item.filePath}, #{item.fileSize}, #{item.fileType})" +
+            "</foreach>" +
+            "</script>")
+    @Options(useGeneratedKeys = true, keyProperty = "id")
+    int batchInsert(@Param("list") List<FsComplaintAttachment> attachmentList);
+
+}

+ 66 - 0
fs-service/src/main/java/com/fs/complaint/mapper/FsComplaintCategoryMapper.java

@@ -0,0 +1,66 @@
+package com.fs.complaint.mapper;
+
+import com.fs.complaint.domain.FsComplaintCategory;
+import com.fs.complaint.param.FsComplaintCategoryParam;
+import com.fs.complaint.vo.FsComplaintCategoryListVO;
+import org.apache.ibatis.annotations.*;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 投诉分类表数据访问层
+ */
+@Mapper
+public interface FsComplaintCategoryMapper {
+
+    /**
+     * 根据ID查询分类信息
+     */
+    @Select("SELECT * FROM fs_complaint_category WHERE id = #{id}")
+    FsComplaintCategory selectById(Long id);
+
+    /**
+     * 查询所有启用的分类列表
+     */
+    @Select("SELECT * FROM fs_complaint_category WHERE status = 1 ORDER BY sort_order ASC")
+    List<FsComplaintCategory> selectAllEnabled();
+
+    /**
+     * 查询所有分类列表
+     */
+    @Select("SELECT * FROM fs_complaint_category where status=1 ORDER BY sort_order ASC")
+    List<FsComplaintCategory> selectAll();
+
+    @Select("SELECT id,category_name FROM fs_complaint_category where status=1 ORDER BY sort_order ASC")
+    @MapKey("id")
+    Map<Long,FsComplaintCategory> selectAllMap();
+
+    /**
+     * 插入分类信息
+     */
+    @Insert("INSERT INTO fs_complaint_category(category_name, category_code, sort_order, status) " +
+            "VALUES(#{categoryName}, #{categoryCode}, #{sortOrder}, #{status})")
+    @Options(useGeneratedKeys = true, keyProperty = "id")
+    int insert(FsComplaintCategory category);
+
+    /**
+     * 更新分类信息
+     */
+
+    int updateById(FsComplaintCategory category);
+
+    /**
+     * 根据ID删除分类信息
+     */
+    @Update("DELETE FROM fs_complaint_category WHERE id = #{id}")
+    int deleteById(Long id);
+
+    List<FsComplaintCategoryListVO> selectFsComplaintCategoryListVO(FsComplaintCategoryParam param);
+
+
+    @Select("select * from fs_complaint_category where id=#{id}")
+    FsComplaintCategory selectFsComplaintCategoryById(@Param("id") Long id);
+
+
+}

+ 135 - 0
fs-service/src/main/java/com/fs/complaint/mapper/FsComplaintMapper.java

@@ -0,0 +1,135 @@
+package com.fs.complaint.mapper;
+
+import com.fs.complaint.domain.FsComplaint;
+import com.fs.complaint.dto.ComplaintQueryDTO;
+import org.apache.ibatis.annotations.*;
+
+import java.util.List;
+
+/**
+ * 投诉表数据访问层
+ */
+@Mapper
+public interface FsComplaintMapper {
+
+    /**
+     * 根据ID查询投诉信息
+     */
+    @Select("SELECT * FROM fs_complaint WHERE id = #{id}")
+    FsComplaint selectById(Long id);
+
+    /**
+     * 根据投诉单号查询投诉信息
+     */
+    @Select("SELECT * FROM fs_complaint WHERE complaint_no = #{complaintNo}")
+    FsComplaint selectByComplaintNo(String complaintNo);
+
+    /**
+     * 条件查询投诉总数
+     */
+    @SelectProvider(type = ComplaintSqlProvider.class, method = "countByCondition")
+    int countByCondition(ComplaintQueryDTO queryDTO);
+
+    /**
+     * 条件分页查询投诉列表
+     */
+    @SelectProvider(type = ComplaintSqlProvider.class, method = "selectByCondition")
+    List<FsComplaint> selectByCondition(ComplaintQueryDTO queryDTO);
+
+    /**
+     * 插入投诉信息
+     */
+    @Insert("INSERT INTO fs_complaint(complaint_no, category_id, category_name, content, contact_phone, contact_email, status, create_time, update_time) " +
+            "VALUES(#{complaintNo}, #{categoryId}, #{categoryName}, #{content}, #{contactPhone}, #{contactEmail}, #{status}, #{createTime}, #{updateTime})")
+    @Options(useGeneratedKeys = true, keyProperty = "id")
+    int insert(FsComplaint complaint);
+
+    /**
+     * 更新投诉信息
+     */
+    @UpdateProvider(type = ComplaintSqlProvider.class, method = "updateSelective")
+    int updateSelective(FsComplaint complaint);
+
+    /**
+     * 根据ID删除投诉信息
+     */
+    @Delete("DELETE FROM fs_complaint WHERE id = #{id}")
+    int deleteById(Long id);
+
+    /**
+     * SQL构建器
+     */
+    class ComplaintSqlProvider {
+
+        public String countByCondition(ComplaintQueryDTO queryDTO) {
+            return buildConditionSql("SELECT COUNT(*) FROM fs_complaint", queryDTO, false);
+        }
+
+        public String selectByCondition(ComplaintQueryDTO queryDTO) {
+            String sql = buildConditionSql("SELECT * FROM fs_complaint", queryDTO, true);
+            int offset = (queryDTO.getPageNum() - 1) * queryDTO.getPageSize();
+            return sql + " LIMIT " + offset + ", " + queryDTO.getPageSize();
+        }
+
+        public String updateSelective(FsComplaint complaint) {
+            StringBuilder sql = new StringBuilder("UPDATE fs_complaint SET update_time = #{updateTime}");
+
+            if (complaint.getCategoryId() != null) {
+                sql.append(", category_id = #{categoryId}");
+            }
+            if (complaint.getCategoryName() != null) {
+                sql.append(", category_name = #{categoryName}");
+            }
+            if (complaint.getContent() != null) {
+                sql.append(", content = #{content}");
+            }
+            if (complaint.getContactPhone() != null) {
+                sql.append(", contact_phone = #{contactPhone}");
+            }
+            if (complaint.getContactEmail() != null) {
+                sql.append(", contact_email = #{contactEmail}");
+            }
+            if (complaint.getStatus() != null) {
+                sql.append(", status = #{status}");
+            }
+
+            sql.append(" WHERE id = #{id}");
+            return sql.toString();
+        }
+
+        private String buildConditionSql(String baseSql, ComplaintQueryDTO queryDTO, boolean needOrder) {
+            StringBuilder sql = new StringBuilder(baseSql);
+            StringBuilder where = new StringBuilder(" WHERE 1=1");
+
+            if (queryDTO.getComplaintNo() != null && !queryDTO.getComplaintNo().trim().isEmpty()) {
+                where.append(" AND complaint_no LIKE CONCAT('%', #{complaintNo}, '%')");
+            }
+            if (queryDTO.getCategoryId() != null) {
+                where.append(" AND category_id = #{categoryId}");
+            }
+            if (queryDTO.getCategoryName() != null && !queryDTO.getCategoryName().trim().isEmpty()) {
+                where.append(" AND category_name LIKE CONCAT('%', #{categoryName}, '%')");
+            }
+            if (queryDTO.getStatus() != null) {
+                where.append(" AND status = #{status}");
+            }
+            if (queryDTO.getContactPhone() != null && !queryDTO.getContactPhone().trim().isEmpty()) {
+                where.append(" AND contact_phone LIKE CONCAT('%', #{contactPhone}, '%')");
+            }
+            if (queryDTO.getStartTime() != null && !queryDTO.getStartTime().trim().isEmpty()) {
+                where.append(" AND create_time >= #{startTime}");
+            }
+            if (queryDTO.getEndTime() != null && !queryDTO.getEndTime().trim().isEmpty()) {
+                where.append(" AND create_time <= #{endTime}");
+            }
+
+            sql.append(where);
+
+            if (needOrder) {
+                sql.append(" ORDER BY create_time DESC");
+            }
+
+            return sql.toString();
+        }
+    }
+}

+ 28 - 0
fs-service/src/main/java/com/fs/complaint/param/FsComplaintCategoryParam.java

@@ -0,0 +1,28 @@
+package com.fs.complaint.param;
+
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 投诉分类查询参数
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class FsComplaintCategoryParam extends BaseEntity {
+
+    /**
+     * 分类名称
+     */
+    private String categoryName;
+
+    /**
+     * 分类编码
+     */
+    private String categoryCode;
+
+    /**
+     * 状态:1-启用,0-禁用
+     */
+    private Integer status;
+}

+ 52 - 0
fs-service/src/main/java/com/fs/complaint/service/FsComplaintCategoryService.java

@@ -0,0 +1,52 @@
+package com.fs.complaint.service;
+
+import com.fs.complaint.domain.FsComplaintCategory;
+import com.fs.complaint.param.FsComplaintCategoryParam;
+import com.fs.complaint.vo.FsComplaintCategoryListVO;
+
+import java.util.List;
+
+public interface FsComplaintCategoryService {
+    List<FsComplaintCategoryListVO> selectFsComplaintCategoryListVO(FsComplaintCategoryParam param);
+    /**
+     * 根据ID查询投诉分类
+     *
+     * @param id 投诉分类ID
+     * @return 投诉分类
+     */
+    FsComplaintCategory selectFsComplaintCategoryById(Long id);
+    /**
+     * 新增投诉分类
+     *
+     * @param fsComplaintCategory 投诉分类
+     * @return 结果
+     */
+    int insertFsComplaintCategory(FsComplaintCategory fsComplaintCategory);
+    /**
+     * 修改投诉分类
+     *
+     * @param fsComplaintCategory 投诉分类
+     * @return 结果
+     */
+    int updateFsComplaintCategory(FsComplaintCategory fsComplaintCategory);
+    /**
+     * 批量删除投诉分类
+     *
+     * @param ids 需要删除的投诉分类ID
+     * @return 结果
+     */
+    void deleteFsComplaintCategoryByIds(Long[] ids);
+    /**
+     * 修改投诉分类状态
+     *
+     * @param fsComplaintCategory 投诉分类
+     * @return 结果
+     */
+    int updateFsComplaintCategoryStatus(FsComplaintCategory fsComplaintCategory);
+
+    /**
+     * 查询所有分类
+     * @return List<FsComplaintCategory>
+     */
+    List<FsComplaintCategory> queryAllCategory();
+}

+ 43 - 0
fs-service/src/main/java/com/fs/complaint/service/FsComplaintService.java

@@ -0,0 +1,43 @@
+package com.fs.complaint.service;
+
+import cn.hutool.db.PageResult;
+import com.fs.complaint.domain.FsComplaint;
+import com.fs.complaint.dto.ComplaintQueryDTO;
+import com.fs.complaint.dto.SubmitComplaintDTO;
+import com.fs.complaint.dto.UpdateComplaintDTO;
+import com.fs.complaint.vo.ComplaintVO;
+
+import java.util.List;
+
+public interface FsComplaintService {
+
+    /**
+     * 提交投诉
+     */
+    void submitComplaint(SubmitComplaintDTO dto);
+
+    /**
+     * 根据ID查询投诉详情
+     */
+    ComplaintVO getComplaintById(Long id);
+
+    /**
+     * 根据投诉单号查询投诉详情
+     */
+    ComplaintVO getComplaintByNo(String complaintNo);
+
+    /**
+     * 分页查询投诉列表
+     */
+    List<FsComplaint> getComplaintPage(ComplaintQueryDTO queryDTO);
+
+    /**
+     * 更新投诉信息
+     */
+    void updateComplaint(Long id, UpdateComplaintDTO dto);
+
+    /**
+     * 删除投诉
+     */
+    void deleteComplaint(Long id);
+}

+ 68 - 0
fs-service/src/main/java/com/fs/complaint/service/impl/FsComplaintCategoryServiceImpl.java

@@ -0,0 +1,68 @@
+package com.fs.complaint.service.impl;
+
+import com.fs.common.exception.ServiceException;
+import com.fs.common.utils.StringUtils;
+import com.fs.complaint.domain.FsComplaintCategory;
+import com.fs.complaint.mapper.FsComplaintCategoryMapper;
+import com.fs.complaint.param.FsComplaintCategoryParam;
+import com.fs.complaint.service.FsComplaintCategoryService;
+import com.fs.complaint.vo.FsComplaintCategoryListVO;
+import com.tencentcloudapi.tiems.v20190416.models.Runtime;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.util.Collections;
+import java.util.List;
+@Slf4j
+@Service
+public class FsComplaintCategoryServiceImpl implements FsComplaintCategoryService {
+    @Autowired
+    private FsComplaintCategoryMapper fsComplaintCategoryMapper;
+
+    @Override
+    public List<FsComplaintCategoryListVO> selectFsComplaintCategoryListVO(FsComplaintCategoryParam param) {
+        return fsComplaintCategoryMapper.selectFsComplaintCategoryListVO(param);
+    }
+
+    @Override
+    public FsComplaintCategory selectFsComplaintCategoryById(Long id) {
+        return fsComplaintCategoryMapper.selectFsComplaintCategoryById(id);
+    }
+
+    @Override
+    public int insertFsComplaintCategory(FsComplaintCategory fsComplaintCategory) {
+
+        fsComplaintCategory.setCreateTime(LocalDateTime.now());
+        fsComplaintCategory.setUpdateTime(LocalDateTime.now());
+        return fsComplaintCategoryMapper.insert(fsComplaintCategory);
+    }
+
+    @Override
+    public int updateFsComplaintCategory(FsComplaintCategory fsComplaintCategory) {
+
+        fsComplaintCategory.setUpdateTime(LocalDateTime.now());
+        return fsComplaintCategoryMapper.updateById(fsComplaintCategory);
+
+    }
+
+    @Override
+    public void deleteFsComplaintCategoryByIds(Long[] ids) {
+        for(Long id : ids) {
+            fsComplaintCategoryMapper.deleteById(id);
+        }
+    }
+
+    @Override
+    public int updateFsComplaintCategoryStatus(FsComplaintCategory fsComplaintCategory) {
+        fsComplaintCategory.setUpdateTime(LocalDateTime.now());
+        return fsComplaintCategoryMapper.updateById(fsComplaintCategory);
+    }
+
+    @Override
+    public List<FsComplaintCategory> queryAllCategory() {
+        return fsComplaintCategoryMapper.selectAll();
+    }
+
+}

+ 195 - 0
fs-service/src/main/java/com/fs/complaint/service/impl/FsComplaintServiceImpl.java

@@ -0,0 +1,195 @@
+package com.fs.complaint.service.impl;
+
+import cn.hutool.core.lang.Snowflake;
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.db.PageResult;
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
+import com.fs.common.utils.FileNameExtractor;
+import com.fs.common.utils.bean.BeanUtils;
+import com.fs.complaint.domain.FsComplaint;
+import com.fs.complaint.domain.FsComplaintAttachment;
+import com.fs.complaint.domain.FsComplaintCategory;
+import com.fs.complaint.dto.ComplaintQueryDTO;
+import com.fs.complaint.dto.SubmitComplaintDTO;
+import com.fs.complaint.dto.UpdateComplaintDTO;
+import com.fs.complaint.mapper.FsComplaintAttachmentMapper;
+import com.fs.complaint.mapper.FsComplaintCategoryMapper;
+import com.fs.complaint.mapper.FsComplaintMapper;
+import com.fs.complaint.param.FsComplaintCategoryParam;
+import com.fs.complaint.service.FsComplaintCategoryService;
+import com.fs.complaint.service.FsComplaintService;
+import com.fs.complaint.vo.ComplaintVO;
+import com.fs.complaint.vo.FsComplaintCategoryListVO;
+import lombok.extern.slf4j.Slf4j;
+import org.bouncycastle.oer.its.etsi102941.Url;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+public class FsComplaintServiceImpl implements FsComplaintService {
+    @Autowired
+    private FsComplaintMapper fsComplaintMapper;
+    @Autowired
+    private FsComplaintAttachmentMapper fsComplaintAttachmentMapper;
+    @Autowired
+    private FsComplaintCategoryMapper fsComplaintCategoryMapper;
+
+    @Override
+    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
+    public void submitComplaint(SubmitComplaintDTO dto) {
+        FsComplaint fsComplaint = new FsComplaint();
+        String complaintNo = IdUtil.getSnowflake(0, 0).nextIdStr();
+
+        fsComplaint.setComplaintNo(complaintNo);
+        fsComplaint.setCategoryId(dto.getType());
+        fsComplaint.setContent(dto.getContent());
+        fsComplaint.setContactPhone(dto.getContact());
+        fsComplaint.setCreateTime(LocalDateTime.now());
+        fsComplaint.setUpdateTime(LocalDateTime.now());
+        fsComplaint.setStatus(1);
+
+        fsComplaintMapper.insert(fsComplaint);
+        List<String> urls = dto.getUrl();
+
+        List<FsComplaintAttachment> attachments = new ArrayList<>();
+        for (String url : urls) {
+            FsComplaintAttachment attachment = new FsComplaintAttachment();
+            attachment.setComplaintId(fsComplaint.getId());
+            attachment.setCreateTime(LocalDateTime.now());
+
+            String fileNameFromUrl = FileNameExtractor.getFileNameFromUrl(url);
+            attachment.setFileName(fileNameFromUrl);
+            attachment.setFilePath(url);
+            attachment.setFileType(FileNameExtractor.getExtensionFromUrl(url));
+            attachment.setCreateTime(LocalDateTime.now());
+            attachments.add(attachment);
+        }
+        fsComplaintAttachmentMapper.batchInsert(attachments);
+    }
+
+    @Override
+    public ComplaintVO getComplaintById(Long id) {
+        log.info("根据ID查询投诉详情,ID:{}", id);
+
+        FsComplaint complaint = fsComplaintMapper.selectById(id);
+        if (complaint == null) {
+            throw new RuntimeException("投诉信息不存在");
+        }
+
+        return convertToVO(complaint);
+    }
+
+    @Override
+    public ComplaintVO getComplaintByNo(String complaintNo) {
+        log.info("根据投诉单号查询投诉详情,投诉单号:{}", complaintNo);
+
+        FsComplaint complaint = fsComplaintMapper.selectByComplaintNo(complaintNo);
+        if (complaint == null) {
+            throw new RuntimeException("投诉信息不存在");
+        }
+
+        return convertToVO(complaint);
+    }
+
+    @Override
+    public List<FsComplaint> getComplaintPage(ComplaintQueryDTO queryDTO) {
+        log.info("分页查询投诉列表,参数:{}", queryDTO);
+
+        Map<Long, FsComplaintCategory> categoryMap = fsComplaintCategoryMapper.selectAllMap();
+
+        List<FsComplaint> complaints = fsComplaintMapper.selectByCondition(queryDTO);
+        for (FsComplaint complaint : complaints) {
+            FsComplaintCategory fsComplaintCategory = categoryMap.get(complaint.getCategoryId());
+            if(ObjectUtils.isNotNull(fsComplaintCategory)){
+                complaint.setCategoryName(fsComplaintCategory.getCategoryName());
+            }
+        }
+
+        return complaints;
+    }
+
+    @Override
+    public void updateComplaint(Long id, UpdateComplaintDTO dto) {
+        log.info("更新投诉信息,ID:{},参数:{}", id, dto);
+
+        // 检查投诉是否存在
+        FsComplaint existComplaint = fsComplaintMapper.selectById(id);
+        if (existComplaint == null) {
+            throw new RuntimeException("投诉信息不存在");
+        }
+
+        FsComplaint complaint = new FsComplaint();
+        BeanUtils.copyProperties(dto, complaint);
+        complaint.setId(id);
+        complaint.setUpdateTime(LocalDateTime.now());
+
+        int result = fsComplaintMapper.updateSelective(complaint);
+        if (result <= 0) {
+            throw new RuntimeException("更新投诉信息失败");
+        }
+
+        log.info("投诉信息更新成功,ID:{}", id);
+    }
+
+    @Override
+    public void deleteComplaint(Long id) {
+        log.info("删除投诉,ID:{}", id);
+
+        // 检查投诉是否存在
+        FsComplaint existComplaint = fsComplaintMapper.selectById(id);
+        if (existComplaint == null) {
+            throw new RuntimeException("投诉信息不存在");
+        }
+
+        int result = fsComplaintMapper.deleteById(id);
+        if (result <= 0) {
+            throw new RuntimeException("删除投诉失败");
+        }
+
+        log.info("投诉删除成功,ID:{}", id);
+    }
+
+    /**
+     * 生成投诉单号
+     */
+    private String generateComplaintNo() {
+        String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
+        String random = String.format("%04d", new Random().nextInt(10000));
+        return "TS" + timestamp + random;
+    }
+
+    /**
+     * 转换为VO对象
+     */
+    private ComplaintVO convertToVO(FsComplaint complaint) {
+        ComplaintVO vo = new ComplaintVO();
+        BeanUtils.copyProperties(complaint, vo);
+        vo.setStatusName(getStatusName(complaint.getStatus()));
+        return vo;
+    }
+
+    /**
+     * 获取状态名称
+     */
+    private String getStatusName(Integer status) {
+        if (status == null) {
+            return "";
+        }
+        switch (status) {
+            case 1: return "待处理";
+            case 2: return "处理中";
+            case 3: return "已完成";
+            case 4: return "已关闭";
+            default: return "未知状态";
+        }
+    }
+
+}

+ 22 - 0
fs-service/src/main/java/com/fs/complaint/vo/ComplaintVO.java

@@ -0,0 +1,22 @@
+package com.fs.complaint.vo;
+
+import lombok.Data;
+import java.time.LocalDateTime;
+
+/**
+ * 投诉信息返回对象
+ */
+@Data
+public class ComplaintVO {
+
+    private Long id;
+    private String complaintNo;
+    private Long categoryId;
+    private String content;
+    private String contactPhone;
+    private String contactEmail;
+    private Integer status;
+    private String statusName;
+    private LocalDateTime createTime;
+    private LocalDateTime updateTime;
+}

+ 50 - 0
fs-service/src/main/java/com/fs/complaint/vo/FsComplaintCategoryListVO.java

@@ -0,0 +1,50 @@
+package com.fs.complaint.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * 投诉分类列表VO
+ */
+@Data
+public class FsComplaintCategoryListVO {
+
+    /**
+     * 主键ID
+     */
+    private Long id;
+
+    /**
+     * 分类名称
+     */
+    private String categoryName;
+
+    /**
+     * 分类编码
+     */
+    private String categoryCode;
+
+    /**
+     * 排序
+     */
+    private Integer sortOrder;
+
+    /**
+     * 状态:1-启用,0-禁用
+     */
+    private Integer status;
+
+    /**
+     * 创建时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime updateTime;
+}

+ 8 - 2
fs-service/src/main/java/com/fs/course/service/impl/FsUserCoursePeriodServiceImpl.java

@@ -3,10 +3,8 @@ package com.fs.course.service.impl;
 import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
-import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.exception.ServiceException;
-import com.fs.common.utils.StringUtils;
 import com.fs.course.domain.FsUserCoursePeriod;
 import com.fs.course.domain.FsUserCoursePeriodDays;
 import com.fs.course.mapper.FsUserCoursePeriodDaysMapper;
@@ -107,6 +105,14 @@ public class FsUserCoursePeriodServiceImpl implements IFsUserCoursePeriodService
         // 1. 查询原始数据
         fsUserCoursePeriod.setUpdateTime(LocalDateTime.now());
 
+        if(LocalDate.now().isBefore(fsUserCoursePeriod.getPeriodStartingTime())){
+            fsUserCoursePeriod.setPeriodStatus(1L);
+        } else if(LocalDate.now().isAfter(fsUserCoursePeriod.getPeriodEndTime())){
+            fsUserCoursePeriod.setPeriodStatus(3L);
+        } else{
+            fsUserCoursePeriod.setPeriodStatus(2L);
+        }
+
         FsUserCoursePeriod fsUserCoursePeriod1 = fsUserCoursePeriodMapper.selectFsUserCoursePeriodById(fsUserCoursePeriod.getPeriodId());
         int flag = fsUserCoursePeriodMapper.updateFsUserCoursePeriod(fsUserCoursePeriod);
 

+ 59 - 0
fs-service/src/main/java/com/fs/foods/domain/FsFoodRecord.java

@@ -0,0 +1,59 @@
+package com.fs.foods.domain;
+
+import lombok.Data;
+import lombok.Builder;
+import lombok.NoArgsConstructor;
+import lombok.AllArgsConstructor;
+
+import java.util.Date;
+import java.time.LocalDate;
+import java.time.LocalTime;
+
+/**
+ * 饮食记录实体类
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class FsFoodRecord {
+
+    /**
+     * 主键ID
+     */
+    private Long id;
+
+    /**
+     * 用户ID
+     */
+    private Long userId;
+    /**
+     * 用户名
+     */
+    private String username;
+
+    /**
+     * 用餐日期
+     */
+    private LocalDate recordDate;
+
+    /**
+     * 记录时间点
+     */
+    private LocalTime recordTime;
+
+    /**
+     * 用餐情况描述
+     */
+    private String mealDescription;
+
+    /**
+     * 创建时间
+     */
+    private Date createdAt;
+
+    /**
+     * 更新时间
+     */
+    private Date updatedAt;
+}

+ 73 - 0
fs-service/src/main/java/com/fs/foods/mapper/FoodRecordMapper.java

@@ -0,0 +1,73 @@
+package com.fs.foods.mapper;
+
+import com.fs.foods.domain.FsFoodRecord;
+import com.fs.foods.param.FoodRecordQueryParam;
+import org.apache.ibatis.annotations.Insert;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Options;
+import org.apache.ibatis.annotations.Select;
+import org.apache.ibatis.annotations.Update;
+import org.apache.ibatis.annotations.Param;
+
+import java.time.LocalDate;
+import java.util.List;
+
+/**
+ * 饮食记录数据访问接口
+ */
+@Mapper
+public interface FoodRecordMapper {
+
+    /**
+     * 根据ID查询饮食记录
+     */
+    @Select("SELECT * FROM fs_food_records WHERE id = #{id}")
+    FsFoodRecord getById(@Param("id") Long id);
+
+    /**
+     * 获取用户某日的所有饮食记录
+     */
+    @Select("SELECT * FROM fs_food_records WHERE user_id = #{userId} AND record_date = #{recordDate} ORDER BY record_time")
+    List<FsFoodRecord> getByUserAndDate(@Param("userId") Long userId, @Param("recordDate") LocalDate recordDate);
+
+    /**
+     * 获取用户所有饮食记录
+     */
+    @Select("SELECT * FROM fs_food_records WHERE user_id = #{userId} ORDER BY record_date DESC, record_time DESC")
+    List<FsFoodRecord> getByUser(@Param("userId") Long userId);
+
+    /**
+     * 新增饮食记录
+     */
+    @Insert("INSERT INTO fs_food_records(user_id, record_date, record_time, meal_description) " +
+            "VALUES(#{userId}, #{recordDate}, #{recordTime}, #{mealDescription})")
+    @Options(useGeneratedKeys = true, keyProperty = "id")
+    int insert(FsFoodRecord foodRecord);
+
+    /**
+     * 更新饮食记录
+     */
+    @Update("UPDATE fs_food_records SET record_date = #{recordDate}, record_time = #{recordTime}, " +
+            "meal_description = #{mealDescription} WHERE id = #{id}")
+    int update(FsFoodRecord foodRecord);
+
+    /**
+     * 删除饮食记录
+     */
+    @Update("DELETE FROM fs_food_records WHERE id = #{id}")
+    int deleteById(@Param("id") Long id);
+
+    List<FsFoodRecord> selectFoodRecordList(FoodRecordQueryParam param);
+
+    List<FsFoodRecord> selectFoodRecordsByUserAndDate(FoodRecordQueryParam param);
+
+    int deleteFsFoodRecordByIds(Long[] ids);
+
+    Integer selectFoodRecordCount(FoodRecordQueryParam param);
+
+    Integer selectRecordDays(FoodRecordQueryParam param);
+
+    FsFoodRecord selectLatestRecord(Long userId);
+
+    List<FsFoodRecord> selectRecentFoodRecords(FoodRecordQueryParam param);
+}

+ 47 - 0
fs-service/src/main/java/com/fs/foods/param/FoodRecordAddParam.java

@@ -0,0 +1,47 @@
+package com.fs.foods.param;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import javax.validation.constraints.NotNull;
+import java.time.LocalDate;
+import java.time.LocalTime;
+
+/**
+ * 新增饮食记录参数
+ */
+@Data
+@ApiModel("新增饮食记录参数")
+public class FoodRecordAddParam {
+
+    /**
+     * 用餐日期
+     */
+    @ApiModelProperty("用餐日期")
+    @NotNull(message = "用餐日期不能为空")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate recordDate;
+
+    /**
+     * 记录时间点
+     */
+    @ApiModelProperty("记录时间点")
+    @NotNull(message = "记录时间不能为空")
+    @DateTimeFormat(pattern = "HH:mm:ss")
+    private LocalTime recordTime;
+
+    /**
+     * 用餐情况描述
+     */
+    @ApiModelProperty("用餐情况描述")
+    @NotNull(message = "用餐描述不能为空")
+    private String mealDescription;
+
+    /**
+     * 用户ID
+     */
+    private Long userId;
+
+}

+ 48 - 0
fs-service/src/main/java/com/fs/foods/param/FoodRecordEditParam.java

@@ -0,0 +1,48 @@
+package com.fs.foods.param;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import javax.validation.constraints.NotNull;
+import java.time.LocalDate;
+import java.time.LocalTime;
+
+/**
+ * 修改饮食记录参数
+ */
+@Data
+@ApiModel("修改饮食记录参数")
+public class FoodRecordEditParam {
+
+    /**
+     * 主键ID
+     */
+    @ApiModelProperty("记录ID")
+    @NotNull(message = "记录ID不能为空")
+    private Long id;
+
+    /**
+     * 用餐日期
+     */
+    @ApiModelProperty("用餐日期")
+    @NotNull(message = "用餐日期不能为空")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate recordDate;
+
+    /**
+     * 记录时间点
+     */
+    @ApiModelProperty("记录时间点")
+    @NotNull(message = "记录时间不能为空")
+    @DateTimeFormat(pattern = "HH:mm:ss")
+    private LocalTime recordTime;
+
+    /**
+     * 用餐情况描述
+     */
+    @ApiModelProperty("用餐情况描述")
+    @NotNull(message = "用餐描述不能为空")
+    private String mealDescription;
+}

+ 57 - 0
fs-service/src/main/java/com/fs/foods/param/FoodRecordQueryParam.java

@@ -0,0 +1,57 @@
+package com.fs.foods.param;
+
+import com.fs.common.core.domain.BaseEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDate;
+
+/**
+ * 饮食记录查询参数
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ApiModel("饮食记录查询参数")
+public class FoodRecordQueryParam extends BaseEntity {
+
+    /**
+     * 用户ID
+     */
+    @ApiModelProperty("用户ID")
+    private Long userId;
+
+    /**
+     * 开始日期
+     */
+    @ApiModelProperty("开始日期")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate startDate;
+
+    /**
+     * 结束日期
+     */
+    @ApiModelProperty("结束日期")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate endDate;
+
+    /**
+     * 页码
+     */
+    @ApiModelProperty("页码")
+    private Integer pageNum = 1;
+
+    /**
+     * 页大小
+     */
+    @ApiModelProperty("页大小")
+    private Integer pageSize = 10;
+
+    /**
+     * 搜索描述关键词
+     */
+    @ApiModelProperty("搜索描述关键词")
+    private String keyword;
+}

+ 90 - 0
fs-service/src/main/java/com/fs/foods/service/IFsFoodRecordService.java

@@ -0,0 +1,90 @@
+package com.fs.foods.service;
+
+import com.fs.foods.domain.FsFoodRecord;
+import com.fs.foods.param.FoodRecordQueryParam;
+
+import java.time.LocalDate;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 饮食记录Service接口
+ */
+public interface IFsFoodRecordService {
+
+    /**
+     * 查询饮食记录
+     *
+     * @param id 饮食记录主键
+     * @return 饮食记录
+     */
+    public FsFoodRecord selectFsFoodRecordById(Long id);
+
+    /**
+     * 查询饮食记录列表
+     *
+     * @param param 查询参数
+     * @return 饮食记录集合
+     */
+    public List<FsFoodRecord> selectFoodRecordList(FoodRecordQueryParam param);
+
+    /**
+     * 根据用户ID和日期查询饮食记录
+     *
+     * @param userId 用户ID
+     * @param recordDate 记录日期
+     * @return 饮食记录集合
+     */
+    public List<FsFoodRecord> selectFoodRecordsByUserAndDate(Long userId, LocalDate recordDate);
+
+    /**
+     * 新增饮食记录
+     *
+     * @param fsFoodRecord 饮食记录
+     * @return 结果
+     */
+    public int insertFsFoodRecord(FsFoodRecord fsFoodRecord);
+
+    /**
+     * 修改饮食记录
+     *
+     * @param fsFoodRecord 饮食记录
+     * @return 结果
+     */
+    public int updateFsFoodRecord(FsFoodRecord fsFoodRecord);
+
+    /**
+     * 批量删除饮食记录
+     *
+     * @param ids 需要删除的饮食记录主键集合
+     * @return 结果
+     */
+    public int deleteFsFoodRecordByIds(Long[] ids);
+
+    /**
+     * 删除饮食记录信息
+     *
+     * @param id 饮食记录主键
+     * @return 结果
+     */
+    public int deleteFsFoodRecordById(Long id);
+
+    /**
+     * 获取用户饮食记录统计信息
+     *
+     * @param userId 用户ID
+     * @param startDate 开始日期
+     * @param endDate 结束日期
+     * @return 统计信息
+     */
+    public Map<String, Object> getFoodRecordStats(Long userId, LocalDate startDate, LocalDate endDate);
+
+    /**
+     * 获取用户最近的饮食记录
+     *
+     * @param userId 用户ID
+     * @param limit 限制条数
+     * @return 饮食记录集合
+     */
+    public List<FsFoodRecord> selectRecentFoodRecords(Long userId, Integer limit);
+}

+ 179 - 0
fs-service/src/main/java/com/fs/foods/service/impl/FsFoodRecordServiceImpl.java

@@ -0,0 +1,179 @@
+package com.fs.foods.service.impl;
+
+import com.fs.common.utils.DateUtils;
+import com.fs.common.utils.StringUtils;
+import com.fs.foods.domain.FsFoodRecord;
+import com.fs.foods.mapper.FoodRecordMapper;
+import com.fs.foods.param.FoodRecordQueryParam;
+import com.fs.foods.service.IFsFoodRecordService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDate;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 饮食记录Service业务层处理
+ */
+@Slf4j
+@Service
+public class FsFoodRecordServiceImpl implements IFsFoodRecordService {
+
+    @Autowired
+    private FoodRecordMapper fsFoodRecordMapper;
+
+    /**
+     * 查询饮食记录
+     *
+     * @param id 饮食记录主键
+     * @return 饮食记录
+     */
+    @Override
+    public FsFoodRecord selectFsFoodRecordById(Long id) {
+        return fsFoodRecordMapper.getById(id);
+    }
+
+    /**
+     * 查询饮食记录列表
+     *
+     * @param param 查询参数
+     * @return 饮食记录
+     */
+    @Override
+    public List<FsFoodRecord> selectFoodRecordList(FoodRecordQueryParam param) {
+        return fsFoodRecordMapper.selectFoodRecordList(param);
+    }
+
+    /**
+     * 根据用户ID和日期查询饮食记录
+     *
+     * @param userId 用户ID
+     * @param recordDate 记录日期
+     * @return 饮食记录集合
+     */
+    @Override
+    public List<FsFoodRecord> selectFoodRecordsByUserAndDate(Long userId, LocalDate recordDate) {
+        FoodRecordQueryParam param = new FoodRecordQueryParam();
+        param.setUserId(userId);
+        param.setStartDate(recordDate);
+        param.setEndDate(recordDate);
+        return fsFoodRecordMapper.selectFoodRecordsByUserAndDate(param);
+    }
+
+    /**
+     * 新增饮食记录
+     *
+     * @param fsFoodRecord 饮食记录
+     * @return 结果
+     */
+    @Override
+    public int insertFsFoodRecord(FsFoodRecord fsFoodRecord) {
+        fsFoodRecord.setCreatedAt(DateUtils.getNowDate());
+        return fsFoodRecordMapper.insert(fsFoodRecord);
+    }
+
+    /**
+     * 修改饮食记录
+     *
+     * @param fsFoodRecord 饮食记录
+     * @return 结果
+     */
+    @Override
+    public int updateFsFoodRecord(FsFoodRecord fsFoodRecord) {
+        fsFoodRecord.setUpdatedAt(DateUtils.getNowDate());
+        return fsFoodRecordMapper.update(fsFoodRecord);
+    }
+
+    /**
+     * 批量删除饮食记录
+     *
+     * @param ids 需要删除的饮食记录主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsFoodRecordByIds(Long[] ids) {
+        return fsFoodRecordMapper.deleteFsFoodRecordByIds(ids);
+    }
+
+    /**
+     * 删除饮食记录信息
+     *
+     * @param id 饮食记录主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsFoodRecordById(Long id) {
+        return fsFoodRecordMapper.deleteById(id);
+    }
+
+    /**
+     * 获取用户饮食记录统计信息
+     *
+     * @param userId 用户ID
+     * @param startDate 开始日期
+     * @param endDate 结束日期
+     * @return 统计信息
+     */
+    @Override
+    public Map<String, Object> getFoodRecordStats(Long userId, LocalDate startDate, LocalDate endDate) {
+        try {
+            // 如果没有指定日期范围,默认查询最近30天
+            if (startDate == null || endDate == null) {
+                endDate = LocalDate.now();
+                startDate = endDate.minusDays(30);
+            }
+
+            FoodRecordQueryParam param = new FoodRecordQueryParam();
+            param.setUserId(userId);
+            param.setStartDate(startDate);
+            param.setEndDate(endDate);
+
+            // 获取总记录数
+            Integer totalCount = fsFoodRecordMapper.selectFoodRecordCount(param);
+
+            // 获取记录天数
+            Integer recordDays = fsFoodRecordMapper.selectRecordDays(param);
+
+            // 获取平均每日记录数
+            Double avgRecordsPerDay = recordDays > 0 ? (double) totalCount / recordDays : 0.0;
+
+            // 获取最近一次记录时间
+            FsFoodRecord latestRecord = fsFoodRecordMapper.selectLatestRecord(userId);
+
+            Map<String, Object> stats = new HashMap<>();
+            stats.put("totalCount", totalCount);
+            stats.put("recordDays", recordDays);
+            stats.put("avgRecordsPerDay", String.format("%.1f", avgRecordsPerDay));
+            stats.put("latestRecordDate", latestRecord != null ? latestRecord.getRecordDate() : null);
+            stats.put("startDate", startDate);
+            stats.put("endDate", endDate);
+
+            return stats;
+        } catch (Exception e) {
+            log.error("获取饮食记录统计异常:", e);
+            return new HashMap<>();
+        }
+    }
+
+    /**
+     * 获取用户最近的饮食记录
+     *
+     * @param userId 用户ID
+     * @param limit 限制条数
+     * @return 饮食记录集合
+     */
+    @Override
+    public List<FsFoodRecord> selectRecentFoodRecords(Long userId, Integer limit) {
+        FoodRecordQueryParam param = new FoodRecordQueryParam();
+        param.setUserId(userId);
+        if (limit != null && limit > 0) {
+            param.setPageSize(limit);
+        } else {
+            param.setPageSize(10); // 默认10条
+        }
+        return fsFoodRecordMapper.selectRecentFoodRecords(param);
+    }
+}

+ 66 - 0
fs-service/src/main/java/com/fs/his/config/HealthIndicatorConfig.java

@@ -0,0 +1,66 @@
+package com.fs.his.config;
+
+import com.alibaba.fastjson.JSON;
+import lombok.Data;
+
+import java.util.Map;
+
+/**
+ * @description: 血糖指标配置类
+ * @author: Xgb
+ * @createDate: 2025/8/28
+ * @version: 1.0
+ */
+@Data
+public class HealthIndicatorConfig {
+
+    /**
+     * 血糖指标
+     */
+    private Map<String, Object> bloodGlucose;
+    /**
+     * 血压指标
+     */
+    private Map<String, Object> bloodPressure;
+    /**
+     * 尿酸指标
+     */
+    private Map<String, Object> uricAcid;
+    /**
+     * BMI指标
+     */
+    private Map<String, Object> bmi;
+    /**
+     * 腰围
+     */
+    private Map<String, Object> waist;
+    /**
+     * 臀围
+     */
+    private Map<String, Object> hip;
+
+    public static final String SEVERITY = "severity";
+
+    // normal 正常, mild 轻微, severe 严重
+    public static final String NORMAL = "normal";
+    public static final String MILD = "mild";
+    public static final String SEVERE = "severe";
+
+    // systolic  高压 diastolic  低压 血压使用
+    public static final String SYSTOLIC = "systolic";
+    public static final String DIASTOLIC = "diastolic";
+
+    // male  男性 female  女性 尿酸使用
+    public static final String MALE = "male";
+    public static final String FEMALE = "female";
+
+
+    /**
+     * 从JSON字符串创建对象实例
+     * @param json JSON字符串
+     * @return HealthIndicatorConfig对象
+     */
+    public static HealthIndicatorConfig fromJson(String json) {
+        return JSON.parseObject(json, HealthIndicatorConfig.class);
+    }
+}

+ 55 - 0
fs-service/src/main/java/com/fs/his/domain/FsAttachment.java

@@ -0,0 +1,55 @@
+package com.fs.his.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fs.common.annotation.Excel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 附件管理对象 fs_attachment
+ *
+ * @author fs
+ * @date 2025-08-23
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class FsAttachment extends BaseEntity{
+
+    @TableId
+    @ApiModelProperty(value = "附件id")
+    private Long attachmentId;
+
+    /** 父id */
+    @Excel(name = "父id")
+    @ApiModelProperty(value = "父id")
+    private Long parentId;
+
+    /** 用户id */
+    @Excel(name = "用户id")
+    @ApiModelProperty(value = "用户id")
+    private Long userId;
+
+    /** 文件类型 0:文件夹 1图片 */
+    @Excel(name = "文件类型 0:文件夹 1图片 2体检报告")
+    @ApiModelProperty(value = "文件类型 0:文件夹 1图片 2体检报告")
+    private Integer type;
+
+    /** 文件大小(kb) */
+    @Excel(name = "文件大小(kb)")
+    @ApiModelProperty(value = "文件大小(kb)")
+    private Long size;
+
+    /** 文件名 */
+    @Excel(name = "文件名")
+    @ApiModelProperty(value = "文件名")
+    private String fileName;
+
+    /** oss路径 */
+    @Excel(name = "oss路径")
+    @ApiModelProperty(value = "文件:oss地址 体检报告:报告id")
+    private String url;
+
+
+}

+ 63 - 0
fs-service/src/main/java/com/fs/his/domain/FsHfpayConfig.java

@@ -0,0 +1,63 @@
+package com.fs.his.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 汇付多支付配置对象 fs_hfpay_config
+ *
+ * @author fs
+ * @date 2025-09-10
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class FsHfpayConfig extends BaseEntity{
+
+    /** $column.columnComment */
+    private Long id;
+
+    /** appId */
+    @Excel(name = "appId")
+    private String appId;
+
+    /** $column.columnComment */
+    @Excel(name = "appId")
+    private String hfProductId;
+
+    /** $column.columnComment */
+    @Excel(name = "appId")
+    private String hfSysId;
+
+    /** $column.columnComment */
+    @Excel(name = "appId")
+    private String huifuId;
+
+    /** $column.columnComment */
+    @Excel(name = "appId")
+    private String hfPayNotifyUrl;
+
+    /** $column.columnComment */
+    @Excel(name = "appId")
+    private String hfPayOnlineNotifyUrl;
+
+    /** $column.columnComment */
+    @Excel(name = "appId")
+    private String hfRefundNotifyUrl;
+
+    /** $column.columnComment */
+    @Excel(name = "appId")
+    private String hfOnlineRefundNotifyUrl;
+
+    /** $column.columnComment */
+    @Excel(name = "appId")
+    private String hfRsaPrivateKey;
+
+    /** $column.columnComment */
+    @Excel(name = "appId")
+    private String hfRsaPublicKey;
+
+
+}

+ 4 - 7
fs-service/src/main/java/com/fs/his/domain/FsUser.java

@@ -191,11 +191,8 @@ public class FsUser extends BaseEntity
     @TableField(exist = false)
     private String nickname;
 
-    public String getNickname() {
-        return nickname;
-    }
-
-    public void setNickname(String nickname) {
-        this.nickname = nickname;
-    }
+    /**
+     * 用户余额
+     */
+    private BigDecimal money;
 }

+ 74 - 0
fs-service/src/main/java/com/fs/his/domain/FsUserHealthData.java

@@ -0,0 +1,74 @@
+package com.fs.his.domain;
+
+import java.math.BigDecimal;
+import java.sql.Time;
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fs.common.annotation.Excel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 用户身体检测数据对象 fs_user_health_data
+ *
+ * @author fs
+ * @date 2025-08-27
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class FsUserHealthData extends BaseEntity{
+
+    /** 自增主键 */
+    @ApiModelProperty("自增主键")
+    private Long id;
+
+    /** 用户ID */
+    @ApiModelProperty("用户ID")
+    private Long userId;
+
+    /** 测量类型(0-腰围,1-臀围,2-血糖,3-血压,4-尿酸 5-BMI) */
+    @ApiModelProperty("测量类型(0-腰围,1-臀围,2-血糖,3-血压,4-尿酸 5-BMI)")
+    private Integer measurementType;
+
+    /** 数值1(测量值1 测量值只有一个时默认填写/身高cm/舒张压) */
+    @ApiModelProperty("数值1(测量值1 测量值只有一个时默认填写/身高cm/舒张压)")
+    private BigDecimal value1;
+
+    /** 数值2(测量值2 体重kg/收缩压) */
+    @ApiModelProperty("数值2(测量值2 体重kg/收缩压)")
+    private BigDecimal value2;
+
+    /** 测量日期 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @ApiModelProperty("测量日期")
+    private Date measurementDate;
+
+    /** 测量时间 */
+    @JsonFormat(pattern = "HH:mm:ss")
+    @ApiModelProperty("测量时间")
+    private Date measurementTime;
+
+    /** 星期 */
+    @ApiModelProperty("星期")
+    private Integer week;
+
+    /** 等级(无-0,轻微-1,严重-2) */
+    @ApiModelProperty("等级(无-0,轻微-1,严重-2)")
+    private Integer level;
+
+    /** 记录创建时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @ApiModelProperty("记录创建时间")
+    private Date createdAt;
+
+    /** 性别(0:男, 1:女, 2:未知) */
+    @ApiModelProperty("性别(0:男, 1:女, 2:未知)")
+    private Integer sex;
+    /** 查询时间 格式yyyy-MM-dd yyyy-MM-dd;yyyy-MM-dd yyyy-MM */
+    @ApiModelProperty("查询时间 格式yyyy-MM-dd yyyy-MM-dd;yyyy-MM-dd yyyy-MM")
+    private String timeSearch;
+
+}

+ 98 - 0
fs-service/src/main/java/com/fs/his/domain/FsUserHealthProfile.java

@@ -0,0 +1,98 @@
+package com.fs.his.domain;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fs.common.annotation.Excel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 用户健康档案对象 fs_user_health_profile
+ *
+ * @author fs
+ * @date 2025-08-27
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class FsUserHealthProfile extends BaseEntity{
+
+    /** 用户ID(主键) */
+    @ApiModelProperty("用户ID(主键)")
+    private Long userId;
+
+    /** 身高(单位:厘米) */
+    @ApiModelProperty("身高(单位:厘米)")
+    private BigDecimal height;
+
+    /** 体重(单位:千克) */
+    @ApiModelProperty("体重(单位:千克)")
+    private BigDecimal weight;
+
+    /** 腰围(单位:厘米) */
+    @ApiModelProperty("腰围(单位:厘米)")
+    private BigDecimal waistCircumference;
+
+    /** 臀围(单位:厘米) */
+    @ApiModelProperty("臀围(单位:厘米)")
+    private BigDecimal hipCircumference;
+
+    /** 高血糖(无-0,轻微-1,严重-2) */
+    @ApiModelProperty("高血糖(无-0,轻微-1,严重-2)")
+    private Long hyperglycemia;
+
+    /** 高血糖测量值(单位:mmol/L) */
+    @ApiModelProperty("高血糖测量值(单位:mmol/L)")
+    private BigDecimal hyperglycemiaValue;
+
+    /** 高血压(无-0,轻微-1,严重-2) */
+    @ApiModelProperty("高血压(无-0,轻微-1,严重-2)")
+    private Long hypertension;
+
+    /** 收缩压(高压) */
+    @ApiModelProperty("收缩压(高压)")
+    private BigDecimal systolicPressure;
+
+    /** 舒张压(低压) */
+    @ApiModelProperty("舒张压(低压)")
+    private BigDecimal diastolicPressure;
+
+    /** 高血脂(无-0,轻微-1,严重-2) */
+    @ApiModelProperty("hyperlipidemia")
+    private Long hyperlipidemia;
+
+    /** 高尿酸(无-0,轻微-1,严重-2) */
+    @ApiModelProperty("高尿酸(无-0,轻微-1,严重-2)")
+    private Long hyperuricemia;
+
+    /** 高尿酸测量值(单位:μmol/L) */
+    @ApiModelProperty("高尿酸测量值(单位:μmol/L)")
+    private BigDecimal hyperuricemiaValue;
+
+    /** 高体重(正常-0,偏瘦-1,偏重-2) */
+    @ApiModelProperty("高体重(正常-0,偏瘦-1,偏重-2)")
+    private Long bodyWeightStatus;
+
+    /** 其他病史 */
+    @ApiModelProperty("其他病史")
+    private String otherMedicalHistory;
+
+    /** 症状史 */
+    @ApiModelProperty("症状史")
+    private String symptomHistory;
+
+    /** 创建时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @ApiModelProperty("创建时间")
+    private Date createdTime;
+
+    /** 更新时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @ApiModelProperty("更新时间")
+    private Date updatedTime;
+
+
+}

+ 225 - 0
fs-service/src/main/java/com/fs/his/domain/FsUserInfo.java

@@ -0,0 +1,225 @@
+package com.fs.his.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.common.core.domain.BaseEntity;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 用户信息对象 fs_user_info
+ *
+ * @author fs
+ * @date 2025-08-25
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class FsUserInfo extends BaseEntity {
+
+    /**
+     * 用户ID
+     */
+    @ApiModelProperty("用户ID")
+    private Long userId;
+
+    /**
+     * 企业用户ID
+     */
+    @ApiModelProperty("企业用户ID")
+    private Long companyUserId;
+
+    /**
+     * 姓名
+     */
+    @ApiModelProperty("姓名")
+    private String username;
+
+    /**
+     * 头像
+     */
+    @ApiModelProperty("头像")
+    private String avatar;
+
+    /**
+     * 性别(0:男, 1:女, 2:未知)
+     */
+    @ApiModelProperty("性别(0:男, 1:女, 2:未知)")
+    private Integer sex;
+
+    /**
+     * 出生年月
+     */
+    @ApiModelProperty("出生年月")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date birthdate;
+
+    /**
+     * 年龄
+     */
+    @ApiModelProperty("年龄")
+    private Integer age;
+
+    /**
+     * 电话
+     */
+    @ApiModelProperty("电话")
+    private String phone;
+
+    /**
+     * 身份证号
+     */
+    @ApiModelProperty("身份证号")
+    private String idCard;
+
+    /**
+     * 退休前工作单位
+     */
+    @ApiModelProperty("退休前工作单位")
+    private String previousEmployer;
+
+    /**
+     * 可支配收入(元)
+     */
+    @ApiModelProperty("可支配收入(元)")
+    private BigDecimal disposableIncome;
+
+    /**
+     * 实际消费(元)
+     */
+    @ApiModelProperty("实际消费(元)")
+    private BigDecimal actualConsumption;
+
+    /**
+     * 市区
+     */
+    @ApiModelProperty("市区")
+    private String city;
+
+    /**
+     * 详情小区
+     */
+    @ApiModelProperty("详情小区")
+    private String residentialCommunity;
+
+    /**
+     * 门牌号
+     */
+    @ApiModelProperty("门牌号")
+    private String houseNumber;
+
+    /**
+     * 面积(平方米)
+     */
+    @ApiModelProperty("面积(平方米)")
+    private BigDecimal area;
+
+    /**
+     * 楼层
+     */
+    @ApiModelProperty("楼层")
+    private String floor;
+
+    /**
+     * 伴侣姓名
+     */
+    @ApiModelProperty("伴侣姓名")
+    private String partnerName;
+
+    /**
+     * 伴侣年龄
+     */
+    @ApiModelProperty("伴侣年龄")
+    private String partnerAge;
+
+    /**
+     * 伴侣单位
+     */
+    @ApiModelProperty("伴侣单位")
+    private String partnerEmployer;
+
+    /**
+     * 孙辈学校
+     */
+    @ApiModelProperty("孙辈学校")
+    private String grandchildrenSchool;
+
+    /**
+     * 是否会员(0:不是, 1:是)
+     */
+    @ApiModelProperty("是否会员(0:不是, 1:是)")
+    private String isMember;
+
+    /**
+     * 会员分类/等级
+     */
+    @ApiModelProperty("会员分类/等级")
+    private String memberLevel;
+
+    /**
+     * 加入时间
+     */
+    @ApiModelProperty("加入时间")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date joinTime;
+
+    /**
+     * 到期时间
+     */
+    @ApiModelProperty("到期时间")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date expiryTime;
+
+    /**
+     * 管理月份(格式如: 2024-01)
+     */
+    @ApiModelProperty("管理月份(格式如: 2024-01)")
+    private String managementMonth;
+
+    /**
+     * 职位
+     */
+    @ApiModelProperty("职位")
+    private String position;
+
+    /**
+     * 癖好/平日喜好
+     */
+    @ApiModelProperty("癖好/平日喜好")
+    private String hobbies;
+
+    /**
+     * 特长
+     */
+    @ApiModelProperty("特长")
+    private String specialties;
+
+    /**
+     * 信仰
+     */
+    @ApiModelProperty("信仰")
+    private String faith;
+
+    /**
+     * 担忧
+     */
+    @ApiModelProperty("担忧")
+    private String concerns;
+
+    /**
+     * 用户想解决的问题
+     */
+    @ApiModelProperty("用户想解决的问题")
+    private String problemsToSolve;
+
+    /**
+     * 健康建议
+     */
+    @ApiModelProperty("健康建议")
+    private String healthSuggestions;
+
+    private Integer isDel;
+
+}

+ 53 - 0
fs-service/src/main/java/com/fs/his/domain/FsUserItinerary.java

@@ -0,0 +1,53 @@
+package com.fs.his.domain;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fs.common.annotation.Excel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.EqualsAndHashCode;
+import org.springframework.format.annotation.DateTimeFormat;
+
+/**
+ * 用户日期行程对象 fs_user_itinerary
+ *
+ * @author fs
+ * @date 2025-09-04
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class FsUserItinerary extends BaseEntity{
+
+    /** 自增主键ID */
+    @ApiModelProperty("自增主键ID")
+    private Long id;
+
+    /** 用户ID */
+    @ApiModelProperty("用户ID")
+    private Long userId;
+
+    /** 行程内容 */
+    @ApiModelProperty("行程内容")
+    private String itinerary;
+
+    /** 行程日期 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private Date itineraryDate;
+
+    /** 行程标记 */
+    private String mark;
+
+    /** 行程时间 */
+    @JsonFormat(pattern = "HH:mm")
+    @ApiModelProperty("行程时间")
+    private Date itineraryTime;
+
+    /** 预留字段 */
+    @ApiModelProperty("预留字段")
+    private String reservedField;
+
+
+}

+ 55 - 0
fs-service/src/main/java/com/fs/his/domain/FsUserPayCompetitorsRecord.java

@@ -0,0 +1,55 @@
+package com.fs.his.domain;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 用户购买竞品信息记录对象 fs_user_pay_competitors_record
+ *
+ * @author fs
+ * @date 2025-08-26
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class FsUserPayCompetitorsRecord extends BaseEntity{
+
+    /** 自增主键ID */
+    private Long id;
+
+    /** 用户ID */
+    private Long userId;
+
+    /** 竞品公司 */
+    private String competitorCompany;
+
+    /** 产品名称 */
+    private String product;
+
+    /** 价格 */
+    private BigDecimal priceAmount;
+
+    /** 服务内容 */
+    private String serviceInfo;
+
+    /** 免费服务次数 */
+    private Integer freeServiceCount;
+
+    /** 预留字段 */
+    private String reservedField;
+
+    /** 创建时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date createdTime;
+
+    /** 更新时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date updatedTime;
+
+
+}

+ 62 - 0
fs-service/src/main/java/com/fs/his/domain/FsUserPayRecord.java

@@ -0,0 +1,62 @@
+package com.fs.his.domain;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 用户购买服务信息记录对象 fs_user_pay_record
+ *
+ * @author fs
+ * @date 2025-08-26
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class FsUserPayRecord extends BaseEntity{
+
+    /** 自增主键ID */
+    private Long id;
+
+    /** 用户ID */
+    private Long userId;
+
+    /** 商品名称 */
+    private String productName;
+
+    /** 购买数量 */
+    private Integer payNum;
+
+    /** 金额 */
+    private BigDecimal amount;
+
+    /** 预计用完时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date estimatedUseTime;
+
+    /** 购买次数 */
+    private Integer payCount;
+
+    /** 剩余次数 */
+    private Integer remainingCount;
+
+    /** 会员情况 */
+    private String membershipInfo;
+
+    /** 预留字段 */
+    private String reservedField;
+
+    /** 创建时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date createdTime;
+
+    /** 更新时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date updatedTime;
+
+
+}

+ 55 - 0
fs-service/src/main/java/com/fs/his/dto/FsUserHealthInfoDTO.java

@@ -0,0 +1,55 @@
+package com.fs.his.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 用户健康档案对象 FsUserHealthInfoDTO
+ *
+ * @author fs
+ * @date 2025-08-27
+ */
+@Data
+public class FsUserHealthInfoDTO extends BaseEntity{
+
+    /** 用户ID(主键) */
+    private Long userId;
+
+    /**
+     * 姓名
+     */
+    private String username;
+
+    /**
+     * 头像
+     */
+    private String avatar;
+
+    /**
+     * 性别(0:男, 1:女, 2:未知)
+     */
+    private Integer sex;
+
+    /**
+     * 年龄
+     */
+    private Integer age;
+    /**
+     * 各数据信息
+     */
+    private Map<String, Object>  dataMap;
+
+    /** 其他病史 */
+    private String otherMedicalHistory;
+
+    /** 症状史 */
+    private String symptomHistory;
+
+}

+ 36 - 0
fs-service/src/main/java/com/fs/his/enums/HealthDataLevelEnum.java

@@ -0,0 +1,36 @@
+package com.fs.his.enums;
+/**
+ * @Description: 健康指标等级枚举
+ * @Author xgb
+ * @Date 2025/8/28 17:22
+ */
+
+public enum HealthDataLevelEnum {
+    // 正常-0,轻微-1,严重-2,3-异常数据
+    NONE("正常", 0),
+    LIGHT("轻微", 1),
+    SERIOUS("严重", 2),
+    EXCEPTION("异常数据", 3);
+    private String des;
+    private Integer value;
+    HealthDataLevelEnum(String label, Integer value) {
+        this.des = label;
+        this.value = value;
+    }
+    public String getLabel() {
+        return des;
+    }
+    public int getValue() {
+        return value;
+    }
+    public static HealthDataLevelEnum toType(Integer value) {
+        for (HealthDataLevelEnum type : HealthDataLevelEnum.values()) {
+            if (type.getValue()==value) {
+                return type;
+            }
+        }
+        return null;
+    }
+
+
+}

+ 45 - 0
fs-service/src/main/java/com/fs/his/enums/HealthDataTypeEnum.java

@@ -0,0 +1,45 @@
+package com.fs.his.enums;
+
+import lombok.Getter;
+
+/**
+ * @Description: 健康指标类型枚举
+ * @Author xgb
+ * @Date 2025/8/28 17:22
+ */
+
+@Getter
+public enum HealthDataTypeEnum {
+    // 0-腰围,1-臀围,2-血糖,3-血压,4-尿酸 5-BMI
+    WAIST( 0, "腰围","waist"),
+    HIP( 1, "臀围","hip"),
+    GLUCOSE( 2, "血糖","bloodGlucose"),
+    BLOOD_PRESSURE( 3, "血压","bloodPressure"),
+    URIC_ACID( 4, "尿酸","uricAcid"),
+    BMI( 5, "BMI","bmi");
+
+    private final Integer value;
+
+    private final String dec;
+
+    private final String type;
+
+
+    HealthDataTypeEnum(Integer value, String dec, String type) {
+        this.value = value;
+        this.dec = dec;
+        this.type = type;
+    }
+
+    public static HealthDataTypeEnum getEnumByKey(Integer value) {
+        for (HealthDataTypeEnum item : HealthDataTypeEnum.values()) {
+            if (item.value.equals(value)) {
+                return item;
+            }
+        }
+        return null;
+    }
+
+
+
+}

+ 69 - 0
fs-service/src/main/java/com/fs/his/mapper/FsAttachmentMapper.java

@@ -0,0 +1,69 @@
+package com.fs.his.mapper;
+
+import java.util.List;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.his.domain.FsAttachment;
+import com.fs.his.param.FsAttachmentPageParam;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * 附件管理Mapper接口
+ *
+ * @author fs
+ * @date 2025-08-23
+ */
+public interface FsAttachmentMapper extends BaseMapper<FsAttachment>{
+    /**
+     * 查询附件管理
+     *
+     * @param attachmentId 附件管理主键
+     * @return 附件管理
+     */
+    FsAttachment selectFsAttachmentByAttachmentId(Long attachmentId);
+
+    /**
+     * 查询附件管理列表
+     *
+     * @param fsAttachment 附件管理
+     * @return 附件管理集合
+     */
+    List<FsAttachment> selectFsAttachmentList(FsAttachment fsAttachment);
+
+    /**
+     * 新增附件管理
+     *
+     * @param fsAttachment 附件管理
+     * @return 结果
+     */
+    int insertFsAttachment(FsAttachment fsAttachment);
+
+    /**
+     * 修改附件管理
+     *
+     * @param fsAttachment 附件管理
+     * @return 结果
+     */
+    int updateFsAttachment(FsAttachment fsAttachment);
+
+    /**
+     * 删除附件管理
+     *
+     * @param attachmentId 附件管理主键
+     * @return 结果
+     */
+    int deleteFsAttachmentByAttachmentId(Long attachmentId);
+
+    /**
+     * 批量删除附件管理
+     *
+     * @param attachmentIds 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteFsAttachmentByAttachmentIds(Long[] attachmentIds);
+
+    List<FsAttachment> selectFsAttachmentListPage(FsAttachmentPageParam fsAttachment);
+
+    FsAttachment selectFsAttachmentByFolderName(@Param("folderName") String folderName);
+
+    int deleteFsAttachmentByReportId(@Param("reportId")Long reportId);
+}

+ 7 - 0
fs-service/src/main/java/com/fs/his/mapper/FsDoctorMapper.java

@@ -202,4 +202,11 @@ public interface FsDoctorMapper
     List<UserVo> selectUserDocVoListByCompany(Long companyId);
 
     String selectDoctorNameByIds(List<Long> doctorIds);
+    @Select({"<script> " +
+            "select doctor_id,doctor_name, mobile FROM fs_doctor where doctor_type = 1 "+
+            "  <if test=\"param.doctorName != null  and param.doctorName != ''\"> and doctor_name like concat( #{param.doctorName}, '%')</if>\n" +
+            "            <if test=\"param.mobile != null  and param.mobile != ''\"> and mobile =#{param.mobile}</if>\n" +
+            "order by doctor_id desc"+
+            "</script>"})
+    List<FsDoctorVO> selectDocVOByNameAndPhone(@Param("param") FsDoctorParam param);
 }

+ 61 - 0
fs-service/src/main/java/com/fs/his/mapper/FsHfpayConfigMapper.java

@@ -0,0 +1,61 @@
+package com.fs.his.mapper;
+
+import java.util.List;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.his.domain.FsHfpayConfig;
+
+/**
+ * 汇付多支付配置Mapper接口
+ * 
+ * @author fs
+ * @date 2025-09-10
+ */
+public interface FsHfpayConfigMapper extends BaseMapper<FsHfpayConfig>{
+    /**
+     * 查询汇付多支付配置
+     * 
+     * @param id 汇付多支付配置主键
+     * @return 汇付多支付配置
+     */
+    FsHfpayConfig selectFsHfpayConfigById(Long id);
+
+    /**
+     * 查询汇付多支付配置列表
+     * 
+     * @param fsHfpayConfig 汇付多支付配置
+     * @return 汇付多支付配置集合
+     */
+    List<FsHfpayConfig> selectFsHfpayConfigList(FsHfpayConfig fsHfpayConfig);
+
+    /**
+     * 新增汇付多支付配置
+     * 
+     * @param fsHfpayConfig 汇付多支付配置
+     * @return 结果
+     */
+    int insertFsHfpayConfig(FsHfpayConfig fsHfpayConfig);
+
+    /**
+     * 修改汇付多支付配置
+     * 
+     * @param fsHfpayConfig 汇付多支付配置
+     * @return 结果
+     */
+    int updateFsHfpayConfig(FsHfpayConfig fsHfpayConfig);
+
+    /**
+     * 删除汇付多支付配置
+     * 
+     * @param id 汇付多支付配置主键
+     * @return 结果
+     */
+    int deleteFsHfpayConfigById(Long id);
+
+    /**
+     * 批量删除汇付多支付配置
+     * 
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteFsHfpayConfigByIds(Long[] ids);
+}

+ 74 - 0
fs-service/src/main/java/com/fs/his/mapper/FsUserHealthDataMapper.java

@@ -0,0 +1,74 @@
+package com.fs.his.mapper;
+
+import java.util.List;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.his.domain.FsUserHealthData;
+
+/**
+ * 用户身体检测数据Mapper接口
+ * 
+ * @author fs
+ * @date 2025-08-27
+ */
+public interface FsUserHealthDataMapper extends BaseMapper<FsUserHealthData>{
+
+    /**
+     * 查询用户身体检测数据列表
+     * 
+     * @param fsUserHealthData 用户身体检测数据
+     * @return 用户身体检测数据集合
+     */
+    List<FsUserHealthData> selectFsUserHealthDataList(FsUserHealthData fsUserHealthData);
+
+    /**
+     * 新增用户身体检测数据
+     * 
+     * @param fsUserHealthData 用户身体检测数据
+     * @return 结果
+     */
+    int insertFsUserHealthData(FsUserHealthData fsUserHealthData);
+
+    /**
+     * 修改用户身体检测数据
+     * 
+     * @param fsUserHealthData 用户身体检测数据
+     * @return 结果
+     */
+    int updateFsUserHealthData(FsUserHealthData fsUserHealthData);
+
+    /**
+     * 删除用户身体检测数据
+     * 
+     * @param id 用户身体检测数据主键
+     * @return 结果
+     */
+    int deleteFsUserHealthDataById(Long id);
+
+    /**
+     * 批量删除用户身体检测数据
+     * 
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteFsUserHealthDataByIds(String[] ids);
+
+    /**
+     * 查询用户身体检测最新数据
+     *
+     * @param fsUserHealthData 用户身体检测数据主键
+     * @return 用户身体检测数据
+     */
+    FsUserHealthData selectFsUserHealthDataByUserId(FsUserHealthData fsUserHealthData);
+
+    /**
+     * 查询用户身体数据详情
+     *
+     * @param id 用户身体检测数据主键
+     * @return 用户身体检测数据
+     */
+    FsUserHealthData selectFsUserHealthDataById(Long id);
+
+    int selectFsUserHealthDataListCount(FsUserHealthData fsUserHealthData);
+
+    List<FsUserHealthData> selectFsUserHealthDataListInfoLatest(FsUserHealthData fsUserHealthData);
+}

+ 46 - 0
fs-service/src/main/java/com/fs/his/mapper/FsUserHealthProfileMapper.java

@@ -0,0 +1,46 @@
+package com.fs.his.mapper;
+
+import java.util.List;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.his.domain.FsUserHealthProfile;
+
+/**
+ * 用户健康档案Mapper接口
+ * 
+ * @author fs
+ * @date 2025-08-27
+ */
+public interface FsUserHealthProfileMapper extends BaseMapper<FsUserHealthProfile>{
+    /**
+     * 查询用户健康档案
+     * 
+     * @param userId 用户健康档案主键
+     * @return 用户健康档案
+     */
+    FsUserHealthProfile selectFsUserHealthProfileByUserId(Long userId);
+
+    /**
+     * 新增用户健康档案
+     * 
+     * @param fsUserHealthProfile 用户健康档案
+     * @return 结果
+     */
+    int insertFsUserHealthProfile(FsUserHealthProfile fsUserHealthProfile);
+
+    /**
+     * 修改用户健康档案
+     * 
+     * @param fsUserHealthProfile 用户健康档案
+     * @return 结果
+     */
+    int updateFsUserHealthProfile(FsUserHealthProfile fsUserHealthProfile);
+
+    /**
+     * 删除用户健康档案
+     * 
+     * @param userId 用户健康档案主键
+     * @return 结果
+     */
+    int deleteFsUserHealthProfileByUserId(Long userId);
+
+}

+ 54 - 0
fs-service/src/main/java/com/fs/his/mapper/FsUserInfoMapper.java

@@ -0,0 +1,54 @@
+package com.fs.his.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.his.domain.FsUserInfo;
+
+import java.util.List;
+
+/**
+ * 用户信息Mapper接口
+ *
+ * @author fs
+ * @date 2025-08-25
+ */
+public interface FsUserInfoMapper extends BaseMapper<FsUserInfo> {
+    /**
+     * 查询用户信息
+     *
+     * @param userId 用户id
+     * @return 用户信息
+     */
+    FsUserInfo selectFsUserInfoById(Long userId);
+
+    /**
+     * 查询用户信息列表
+     *
+     * @param companyUserId 用户信息
+     * @return 用户信息集合
+     */
+    List<FsUserInfo> selectFsUserInfoList(Long companyUserId);
+
+    /**
+     * 新增用户信息
+     *
+     * @param fsUserInfo 用户信息
+     * @return 结果
+     */
+    int insertFsUserInfo(FsUserInfo fsUserInfo);
+
+    /**
+     * 修改用户信息
+     *
+     * @param fsUserInfo 用户信息
+     * @return 结果
+     */
+    int updateFsUserInfo(FsUserInfo fsUserInfo);
+
+
+    FsUserInfo selectFsUserInfoByPhone(String phone);
+
+    FsUserInfo selectFsUserInfoByIdOnle(Long userId);
+
+
+    int deleteFsUserInfoByUserId(Long userId);
+}

+ 61 - 0
fs-service/src/main/java/com/fs/his/mapper/FsUserItineraryMapper.java

@@ -0,0 +1,61 @@
+package com.fs.his.mapper;
+
+import java.util.List;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.his.domain.FsUserItinerary;
+
+/**
+ * 用户日期行程Mapper接口
+ * 
+ * @author fs
+ * @date 2025-09-04
+ */
+public interface FsUserItineraryMapper extends BaseMapper<FsUserItinerary>{
+    /**
+     * 查询用户日期行程
+     * 
+     * @param id 用户日期行程主键
+     * @return 用户日期行程
+     */
+    FsUserItinerary selectFsUserItineraryById(Long id);
+
+    /**
+     * 查询用户日期行程列表
+     * 
+     * @param fsUserItinerary 用户日期行程
+     * @return 用户日期行程集合
+     */
+    List<FsUserItinerary> selectFsUserItineraryList(FsUserItinerary fsUserItinerary);
+
+    /**
+     * 新增用户日期行程
+     * 
+     * @param fsUserItinerary 用户日期行程
+     * @return 结果
+     */
+    int insertFsUserItinerary(FsUserItinerary fsUserItinerary);
+
+    /**
+     * 修改用户日期行程
+     * 
+     * @param fsUserItinerary 用户日期行程
+     * @return 结果
+     */
+    int updateFsUserItinerary(FsUserItinerary fsUserItinerary);
+
+    /**
+     * 删除用户日期行程
+     * 
+     * @param id 用户日期行程主键
+     * @return 结果
+     */
+    int deleteFsUserItineraryById(Long id);
+
+    /**
+     * 批量删除用户日期行程
+     * 
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteFsUserItineraryByIds(Long[] ids);
+}

+ 10 - 1
fs-service/src/main/java/com/fs/his/mapper/FsUserMapper.java

@@ -40,6 +40,15 @@ public interface FsUserMapper
      */
     public FsUser selectFsUserByUserId(Long userId);
 
+    @Select("select concat(user_id,'_',nickname) from fs_user where user_id=#{userId} limit 1")
+    public String selectUserNameByUserId(@Param("userId") Long userId);
+
+    @MapKey("userId")
+    public Map<Long,FsUser> selectFsUserByUserIdBatch(List<Long> userIds);
+
+    @Select("select * from fs_user where user_id=#{userId}")
+    public FsUser selectFsUserByUserIdForUpdate(@Param("userId") Long userId);
+
     /**
      * 查询用户列表
      *
@@ -118,7 +127,7 @@ public interface FsUserMapper
     FsUser selectFsUserByCourseOpenId(String openId);
 
 
-    @Select("select * from fs_user where phone=#{phone}")
+    @Select("select * from fs_user where is_del = 0 and phone=#{phone}")
     FsUser selectFsUserByPhone(String phone);
 
     @Select("select * from fs_user where phone=#{phone} limit 1")

+ 54 - 0
fs-service/src/main/java/com/fs/his/mapper/FsUserPayCompetitorsRecordMapper.java

@@ -0,0 +1,54 @@
+package com.fs.his.mapper;
+
+import java.util.List;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.his.domain.FsUserPayCompetitorsRecord;
+
+/**
+ * 用户购买竞品信息记录Mapper接口
+ * 
+ * @author fs
+ * @date 2025-08-26
+ */
+public interface FsUserPayCompetitorsRecordMapper extends BaseMapper<FsUserPayCompetitorsRecord>{
+    /**
+     * 查询用户购买竞品信息记录
+     * 
+     * @param id 用户购买竞品信息记录主键
+     * @return 用户购买竞品信息记录
+     */
+    FsUserPayCompetitorsRecord selectFsUserPayCompetitorsRecordById(Long id);
+
+    /**
+     * 查询用户购买竞品信息记录列表
+     * 
+     * @param fsUserPayCompetitorsRecord 用户购买竞品信息记录
+     * @return 用户购买竞品信息记录集合
+     */
+    List<FsUserPayCompetitorsRecord> selectFsUserPayCompetitorsRecordList(FsUserPayCompetitorsRecord fsUserPayCompetitorsRecord);
+
+    /**
+     * 新增用户购买竞品信息记录
+     * 
+     * @param fsUserPayCompetitorsRecord 用户购买竞品信息记录
+     * @return 结果
+     */
+    int insertFsUserPayCompetitorsRecord(FsUserPayCompetitorsRecord fsUserPayCompetitorsRecord);
+
+    /**
+     * 修改用户购买竞品信息记录
+     * 
+     * @param fsUserPayCompetitorsRecord 用户购买竞品信息记录
+     * @return 结果
+     */
+    int updateFsUserPayCompetitorsRecord(FsUserPayCompetitorsRecord fsUserPayCompetitorsRecord);
+
+    /**
+     * 删除用户购买竞品信息记录
+     * 
+     * @param id 用户购买竞品信息记录主键
+     * @return 结果
+     */
+    int deleteFsUserPayCompetitorsRecordById(Long id);
+
+}

+ 54 - 0
fs-service/src/main/java/com/fs/his/mapper/FsUserPayRecordMapper.java

@@ -0,0 +1,54 @@
+package com.fs.his.mapper;
+
+import java.util.List;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.his.domain.FsUserPayRecord;
+
+/**
+ * 用户购买服务信息记录Mapper接口
+ * 
+ * @author fs
+ * @date 2025-08-26
+ */
+public interface FsUserPayRecordMapper extends BaseMapper<FsUserPayRecord>{
+    /**
+     * 查询用户购买服务信息记录
+     * 
+     * @param id 用户购买服务信息记录主键
+     * @return 用户购买服务信息记录
+     */
+    FsUserPayRecord selectFsUserPayRecordById(Long id);
+
+    /**
+     * 查询用户购买服务信息记录列表
+     * 
+     * @param fsUserPayRecord 用户购买服务信息记录
+     * @return 用户购买服务信息记录集合
+     */
+    List<FsUserPayRecord> selectFsUserPayRecordList(FsUserPayRecord fsUserPayRecord);
+
+    /**
+     * 新增用户购买服务信息记录
+     * 
+     * @param fsUserPayRecord 用户购买服务信息记录
+     * @return 结果
+     */
+    int insertFsUserPayRecord(FsUserPayRecord fsUserPayRecord);
+
+    /**
+     * 修改用户购买服务信息记录
+     * 
+     * @param fsUserPayRecord 用户购买服务信息记录
+     * @return 结果
+     */
+    int updateFsUserPayRecord(FsUserPayRecord fsUserPayRecord);
+
+    /**
+     * 删除用户购买服务信息记录
+     * 
+     * @param id 用户购买服务信息记录主键
+     * @return 结果
+     */
+    int deleteFsUserPayRecordById(Long id);
+
+}

+ 38 - 0
fs-service/src/main/java/com/fs/his/param/FsAttachmentPageParam.java

@@ -0,0 +1,38 @@
+package com.fs.his.param;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import com.fs.common.param.BaseQueryParam;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 附件管理对象 fs_attachment
+ *
+ * @author fs
+ * @date 2025-08-23
+ */
+@Data
+public class FsAttachmentPageParam extends BaseQueryParam {
+    /** 父id */
+    private Long parentId;
+
+    /** 用户id */
+    private Long userId;
+
+    /** 文件类型 0:文件夹 1图片 */
+    @Excel(name = "文件类型 0:文件夹 1图片")
+    private Integer type;
+
+    /** 文件大小(kb) */
+    private Long size;
+
+    /** 文件名 */
+    private String fileName;
+
+    /** oss路径 */
+    private String url;
+
+
+}

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

@@ -11,5 +11,5 @@ public class FsPackageOrderDoPayParam implements Serializable {
     Long orderId;
     Long userId;
 
-    private String appId;
+    private String appId;//小程序id
 }

+ 70 - 0
fs-service/src/main/java/com/fs/his/service/IFsAttachmentService.java

@@ -0,0 +1,70 @@
+package com.fs.his.service;
+
+import java.util.List;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.common.core.domain.R;
+import com.fs.his.domain.FsAttachment;
+import com.fs.his.param.FsAttachmentPageParam;
+
+/**
+ * 附件管理Service接口
+ *
+ * @author fs
+ * @date 2025-08-23
+ */
+public interface IFsAttachmentService extends IService<FsAttachment>{
+    /**
+     * 查询附件管理
+     *
+     * @param attachmentId 附件管理主键
+     * @return 附件管理
+     */
+    FsAttachment selectFsAttachmentByAttachmentId(Long attachmentId);
+
+    /**
+     * 查询附件管理列表
+     *
+     * @param fsAttachment 附件管理
+     * @return 附件管理集合
+     */
+    List<FsAttachment> selectFsAttachmentList(FsAttachment fsAttachment);
+
+
+    List<FsAttachment> selectFsAttachmentList(FsAttachmentPageParam fsAttachment);
+
+    /**
+     * 新增附件管理
+     *
+     * @param fsAttachment 附件管理
+     * @return 结果
+     */
+    R insertFsAttachment(FsAttachment fsAttachment);
+
+    /**
+     * 修改附件管理
+     *
+     * @param fsAttachment 附件管理
+     * @return 结果
+     */
+    R updateFsAttachment(FsAttachment fsAttachment);
+
+    /**
+     * 批量删除附件管理
+     *
+     * @param attachmentIds 需要删除的附件管理主键集合
+     * @return 结果
+     */
+    int deleteFsAttachmentByAttachmentIds(Long[] attachmentIds);
+
+    /**
+     * 删除附件管理信息
+     *
+     * @param attachmentId 附件管理主键
+     * @return 结果
+     */
+    int deleteFsAttachmentByAttachmentId(Long attachmentId);
+
+    FsAttachment selectFsAttachmentByFolderName(String folderName);
+
+    int deleteFsAttachmentByReportId(Long reportId);
+}

+ 2 - 0
fs-service/src/main/java/com/fs/his/service/IFsDoctorService.java

@@ -107,4 +107,6 @@ public interface IFsDoctorService
     List<UserVo> selectUserDocVoListByCompany(Long companyId);
 
     String selectDoctorByIds(String doctorId);
+
+    List<FsDoctorVO> selectDocVOByNameAndPhone(FsDoctorParam param);
 }

+ 61 - 0
fs-service/src/main/java/com/fs/his/service/IFsHfpayConfigService.java

@@ -0,0 +1,61 @@
+package com.fs.his.service;
+
+import java.util.List;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.his.domain.FsHfpayConfig;
+
+/**
+ * 汇付多支付配置Service接口
+ * 
+ * @author fs
+ * @date 2025-09-10
+ */
+public interface IFsHfpayConfigService extends IService<FsHfpayConfig>{
+    /**
+     * 查询汇付多支付配置
+     * 
+     * @param id 汇付多支付配置主键
+     * @return 汇付多支付配置
+     */
+    FsHfpayConfig selectFsHfpayConfigById(Long id);
+
+    /**
+     * 查询汇付多支付配置列表
+     * 
+     * @param fsHfpayConfig 汇付多支付配置
+     * @return 汇付多支付配置集合
+     */
+    List<FsHfpayConfig> selectFsHfpayConfigList(FsHfpayConfig fsHfpayConfig);
+
+    /**
+     * 新增汇付多支付配置
+     * 
+     * @param fsHfpayConfig 汇付多支付配置
+     * @return 结果
+     */
+    int insertFsHfpayConfig(FsHfpayConfig fsHfpayConfig);
+
+    /**
+     * 修改汇付多支付配置
+     * 
+     * @param fsHfpayConfig 汇付多支付配置
+     * @return 结果
+     */
+    int updateFsHfpayConfig(FsHfpayConfig fsHfpayConfig);
+
+    /**
+     * 批量删除汇付多支付配置
+     * 
+     * @param ids 需要删除的汇付多支付配置主键集合
+     * @return 结果
+     */
+    int deleteFsHfpayConfigByIds(Long[] ids);
+
+    /**
+     * 删除汇付多支付配置信息
+     * 
+     * @param id 汇付多支付配置主键
+     * @return 结果
+     */
+    int deleteFsHfpayConfigById(Long id);
+}

+ 104 - 0
fs-service/src/main/java/com/fs/his/service/IFsUserHealthDataService.java

@@ -0,0 +1,104 @@
+package com.fs.his.service;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Map;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.his.config.HealthIndicatorConfig;
+import com.fs.his.domain.FsUserHealthData;
+import com.fs.his.domain.FsUserHealthProfile;
+
+/**
+ * 用户身体检测数据Service接口
+ * 
+ * @author fs
+ * @date 2025-08-27
+ */
+public interface IFsUserHealthDataService extends IService<FsUserHealthData>{
+    /**
+     * 查询用户身体检测数据
+     * 
+     * @param id 用户身体检测数据主键
+     * @return 用户身体检测数据
+     */
+//    FsUserHealthData selectFsUserHealthDataById(String id);
+
+    /**
+     * 查询用户身体检测数据列表
+     * 
+     * @param fsUserHealthData 用户身体检测数据
+     * @return 用户身体检测数据集合
+     */
+    List<FsUserHealthData> selectFsUserHealthDataList(FsUserHealthData fsUserHealthData);
+
+    /**
+     * 新增用户身体检测数据
+     * 
+     * @param fsUserHealthData 用户身体检测数据
+     * @return 结果
+     */
+    int insertFsUserHealthData(FsUserHealthData fsUserHealthData);
+
+    /**
+     * 修改用户身体检测数据
+     * 
+     * @param fsUserHealthData 用户身体检测数据
+     * @return 结果
+     */
+    int updateFsUserHealthData(FsUserHealthData fsUserHealthData);
+
+    /**
+     * 删除用户身体检测数据信息
+     * 
+     * @param id 用户身体检测数据主键
+     * @return 结果
+     */
+    int deleteFsUserHealthDataById(Long id);
+
+    /**
+     * @Description: 获取健康指标参数配置
+     * @Param:
+     * @Return:
+     * @Author xgb
+     * @Date 2025/9/1 18:01
+     */
+    HealthIndicatorConfig parseHealthIndicator();
+
+    /**
+     * @Description: 解析获取最新指标值
+     * @Param:
+     * @Return:
+     * @Author xgb
+     * @Date 2025/9/1 17:57
+     */
+    String getHealthIndicatorValue(HealthIndicatorConfig config, String type, String key, String level);
+
+    /**
+     * @Description: 计算用户健康指标等级
+     * @Param:  [fsUserHealthData]
+     * @Return: java.lang.String
+     * @Author xgb
+     * @Date 2025/8/28 17:13
+     */
+    int getHealthIndicatorLevel(FsUserHealthData fsUserHealthData);
+
+
+    BigDecimal calculateBMI(BigDecimal height, BigDecimal weight);
+
+    void initHealthData(FsUserHealthProfile fsUserHealthProfile);
+
+    void addHealthData(FsUserHealthData fsUserHealthData);
+
+    FsUserHealthData selectFsUserHealthDataByUserId(FsUserHealthData fsUserHealthData);
+
+    FsUserHealthData selectFsUserHealthDataById(Long id);
+
+    void updateFsUserHealthDataAndLevel(FsUserHealthData fsUserHealthData);
+
+    int selectFsUserHealthDataListCount(FsUserHealthData fsUserHealthData);
+
+    Map<String,Object> selectFsUserHealthDataListInfo(FsUserHealthData fsUserHealthData, Integer pageNum, Integer pageSize);
+
+    Map<String, Object> selectFsUserHealthDataListInfoLatest(FsUserHealthData fsUserHealthData, Integer pageNum, Integer pageSize);
+}

+ 45 - 0
fs-service/src/main/java/com/fs/his/service/IFsUserHealthProfileService.java

@@ -0,0 +1,45 @@
+package com.fs.his.service;
+
+import java.util.List;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.his.domain.FsUserHealthProfile;
+
+/**
+ * 用户健康档案Service接口
+ * 
+ * @author fs
+ * @date 2025-08-27
+ */
+public interface IFsUserHealthProfileService extends IService<FsUserHealthProfile>{
+    /**
+     * 查询用户健康档案
+     * 
+     * @param userId 用户健康档案主键
+     * @return 用户健康档案
+     */
+    FsUserHealthProfile selectFsUserHealthProfileByUserId(Long userId);
+
+    /**
+     * 新增用户健康档案
+     * 
+     * @param fsUserHealthProfile 用户健康档案
+     * @return 结果
+     */
+    int insertFsUserHealthProfile(FsUserHealthProfile fsUserHealthProfile);
+
+    /**
+     * 修改用户健康档案
+     * 
+     * @param fsUserHealthProfile 用户健康档案
+     * @return 结果
+     */
+    int updateFsUserHealthProfile(FsUserHealthProfile fsUserHealthProfile);
+
+    /**
+     * 删除用户健康档案信息
+     * 
+     * @param userId 用户健康档案主键
+     * @return 结果
+     */
+    int deleteFsUserHealthProfileByUserId(Long userId);
+}

+ 51 - 0
fs-service/src/main/java/com/fs/his/service/IFsUserInfoService.java

@@ -0,0 +1,51 @@
+package com.fs.his.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.his.domain.FsUserInfo;
+
+import java.util.List;
+
+
+/**
+ * 用户信息Service接口
+ *
+ * @author fs
+ * @date 2025-08-25
+ */
+public interface IFsUserInfoService extends IService<FsUserInfo> {
+    /**
+     * 查询用户信息
+     *
+     * @param userId 用户信息主键
+     * @return 用户信息
+     */
+    FsUserInfo selectFsUserInfoById(Long userId);
+
+    /**
+     * 查询用户信息列表
+     *
+     * @param  companyUserId 用户信息
+     * @return 用户信息集合
+     */
+    List<FsUserInfo> selectFsUserInfoList(Long companyUserId);
+
+    /**
+     * 新增用户信息
+     *
+     * @param fsUserInfo 用户信息
+     * @return 结果
+     */
+    int insertFsUserInfo(FsUserInfo fsUserInfo);
+
+    /**
+     * 修改用户信息
+     *
+     * @param fsUserInfo 用户信息
+     * @return 结果
+     */
+    void updateFsUserInfo(FsUserInfo fsUserInfo);
+
+    void add(FsUserInfo fsUserInfo);
+
+    int deleteFsUserInfoByUserId(Long userId);
+}

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