Bladeren bron

商家pc端-洗浴汗蒸

qrs 1 week geleden
bovenliggende
commit
3430d1544e
16 gewijzigde bestanden met toevoegingen van 1306 en 11 verwijderingen
  1. 8 5
      alien-store-platform/src/main/java/shop/alien/storeplatform/controller/StorePlatformBarMenuController.java
  2. 186 0
      alien-store-platform/src/main/java/shop/alien/storeplatform/controller/StorePlatformBathFacilityServiceController.java
  3. 2 2
      alien-store-platform/src/main/java/shop/alien/storeplatform/controller/StorePlatformSportsEquipmentFacilityController.java
  4. 97 0
      alien-store-platform/src/main/java/shop/alien/storeplatform/controller/StorePlatformStoreStaffConfigController.java
  5. 6 2
      alien-store-platform/src/main/java/shop/alien/storeplatform/entity/StorePlatformBathFacility.java
  6. 4 0
      alien-store-platform/src/main/java/shop/alien/storeplatform/entity/StorePlatformStoreMenu.java
  7. 10 0
      alien-store-platform/src/main/java/shop/alien/storeplatform/mapper/StorePlatformBathFacilityServiceMapper.java
  8. 9 0
      alien-store-platform/src/main/java/shop/alien/storeplatform/mapper/StorePlatformStoreStaffConfigMapper.java
  9. 1 1
      alien-store-platform/src/main/java/shop/alien/storeplatform/service/StorePlatformBarMenuService.java
  10. 85 0
      alien-store-platform/src/main/java/shop/alien/storeplatform/service/StorePlatformBathFacilityService.java
  11. 48 0
      alien-store-platform/src/main/java/shop/alien/storeplatform/service/StorePlatformStoreStaffConfigService.java
  12. 19 1
      alien-store-platform/src/main/java/shop/alien/storeplatform/service/impl/StorePlatformBarMenuServiceImpl.java
  13. 648 0
      alien-store-platform/src/main/java/shop/alien/storeplatform/service/impl/StorePlatformBathFacilityServiceImpl.java
  14. 143 0
      alien-store-platform/src/main/java/shop/alien/storeplatform/service/impl/StorePlatformStoreStaffConfigServiceImpl.java
  15. 40 0
      alien-store-platform/src/main/java/shop/alien/storeplatform/vo/StorePlatformBathFacilityImportVo.java
  16. BIN
      alien-store-platform/src/main/resources/templates/洗浴汗蒸导入模板.xlsx

+ 8 - 5
alien-store-platform/src/main/java/shop/alien/storeplatform/controller/StorePlatformBarMenuController.java

@@ -67,13 +67,16 @@ public class StorePlatformBarMenuController {
     @ApiOperationSupport(order = 3)
     @ApiImplicitParams({
             @ApiImplicitParam(name = "storeId", value = "门店ID", dataType = "Integer", paramType = "query", required = true),
-            @ApiImplicitParam(name = "dishMenuType", value = "菜单类型:1-菜单,2-酒水", dataType = "String", paramType = "query")
+            @ApiImplicitParam(name = "dishMenuType", value = "菜单类型:1-菜单,2-酒水", dataType = "String", paramType = "query"),
+            @ApiImplicitParam(name = "dishType", value = "是否推荐, 0:非推荐, 1:推荐", dataType = "String", paramType = "query")
     })
     @GetMapping("/getListByStoreIdAndType")
-    public R<List<StorePlatformStoreMenu>> getListByStoreIdAndType(@RequestParam("storeId") Integer storeId,
-                                                                   @RequestParam(value = "dishMenuType", required = false) String dishMenuType) {
-        log.info("StorePlatformBarMenuController.getListByStoreIdAndType storeId={}, dishMenuType={}", storeId, dishMenuType);
-        List<StorePlatformStoreMenu> list = barMenuService.getListByStoreIdAndType(storeId, dishMenuType);
+    public R<List<StorePlatformStoreMenu>> getListByStoreIdAndType(
+            @RequestParam("storeId") Integer storeId,
+            @RequestParam(value = "dishMenuType", required = false) String dishMenuType,
+            @RequestParam(value = "dishType", required = false) String dishType) {
+        log.info("StorePlatformBarMenuController.getListByStoreIdAndType storeId={}, dishMenuType={}, dishType={}", storeId, dishMenuType, dishType);
+        List<StorePlatformStoreMenu> list = barMenuService.getListByStoreIdAndType(storeId, dishMenuType, dishType);
         return R.data(list);
     }
 

+ 186 - 0
alien-store-platform/src/main/java/shop/alien/storeplatform/controller/StorePlatformBathFacilityServiceController.java

@@ -0,0 +1,186 @@
+package shop.alien.storeplatform.controller;
+
+import io.swagger.annotations.*;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.Resource;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+import shop.alien.entity.result.R;
+import shop.alien.storeplatform.entity.StorePlatformBathFacility;
+import shop.alien.storeplatform.service.StorePlatformBathFacilityService;
+import shop.alien.storeplatform.vo.ExcelImportVo;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
+/**
+ * 商户平台-洗浴设施及服务Controller
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Slf4j
+@Api(tags = {"商户平台-洗浴汗蒸"})
+@ApiSort(4)
+@CrossOrigin
+@RestController
+@RequestMapping("/bathFacilityService")
+@RequiredArgsConstructor
+public class StorePlatformBathFacilityServiceController {
+
+    private final StorePlatformBathFacilityService facilityService;
+
+    @ApiOperation("根据ID查询设施")
+    @ApiOperationSupport(order = 1)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "设施ID", dataType = "Integer", paramType = "query", required = true)
+    })
+    @GetMapping("/getById")
+    public R<StorePlatformBathFacility> getById(@RequestParam("id") Integer id) {
+        log.info("StorePlatformBathFacilityServiceController.getById id={}", id);
+        StorePlatformBathFacility facility = facilityService.getById(id);
+        if (facility == null) {
+            return R.fail("设施不存在");
+        }
+        return R.data(facility);
+    }
+
+    @ApiOperation("根据门店ID查询设施列表")
+    @ApiOperationSupport(order = 2)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "storeId", value = "门店ID", dataType = "Integer", paramType = "query", required = true)
+    })
+    @GetMapping("/getListByStoreId")
+    public R<List<StorePlatformBathFacility>> getListByStoreId(@RequestParam("storeId") Integer storeId) {
+        log.info("StorePlatformBathFacilityServiceController.getListByStoreId storeId={}", storeId);
+        List<StorePlatformBathFacility> list = facilityService.getListByStoreId(storeId);
+        return R.data(list);
+    }
+
+    @ApiOperation("根据门店ID和区域分类查询设施列表")
+    @ApiOperationSupport(order = 3)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "storeId", value = "门店ID", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "facilityCategory", value = "区域分类(1:洗浴区, 2:汗蒸区, 3:休闲区, 4:餐饮区)", dataType = "Integer", paramType = "query")
+    })
+    @GetMapping("/getListByStoreIdAndCategory")
+    public R<List<StorePlatformBathFacility>> getListByStoreIdAndCategory(@RequestParam("storeId") Integer storeId,
+                                                                         @RequestParam(value = "facilityCategory", required = false) Integer facilityCategory) {
+        log.info("StorePlatformBathFacilityServiceController.getListByStoreIdAndCategory storeId={}, facilityCategory={}", storeId, facilityCategory);
+        List<StorePlatformBathFacility> list = facilityService.getListByStoreIdAndCategory(storeId, facilityCategory);
+        return R.data(list);
+    }
+
+    @ApiOperation("新增设施")
+    @ApiOperationSupport(order = 4)
+    @PostMapping("/save")
+    public R<String> save(@RequestBody StorePlatformBathFacility facility) {
+        log.info("StorePlatformBathFacilityServiceController.save facility={}", facility);
+        return facilityService.saveFacility(facility);
+    }
+
+    @ApiOperation("修改设施")
+    @ApiOperationSupport(order = 5)
+    @PostMapping("/update")
+    public R<String> update(@RequestBody StorePlatformBathFacility facility) {
+        log.info("StorePlatformBathFacilityServiceController.update facility={}", facility);
+        return facilityService.updateFacility(facility);
+    }
+
+    @ApiOperation("新增或修改设施")
+    @ApiOperationSupport(order = 6)
+    @PostMapping("/saveOrUpdate")
+    public R<String> saveOrUpdate(@RequestBody StorePlatformBathFacility facility) {
+        log.info("StorePlatformBathFacilityServiceController.saveOrUpdate facility={}", facility);
+        return facilityService.saveOrUpdateFacility(facility);
+    }
+
+    @ApiOperation("删除设施")
+    @ApiOperationSupport(order = 7)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "设施ID", dataType = "Integer", paramType = "query", required = true)
+    })
+    @GetMapping("/delete")
+    public R<String> delete(@RequestParam("id") Integer id) {
+        log.info("StorePlatformBathFacilityServiceController.delete id={}", id);
+        return facilityService.deleteFacility(id);
+    }
+
+    @ApiOperation("批量删除设施")
+    @ApiOperationSupport(order = 8)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "ids", value = "设施ID列表", dataType = "List", paramType = "query", required = true)
+    })
+    @GetMapping("/deleteBatch")
+    public R<String> deleteBatch(@RequestParam("ids") List<Integer> ids) {
+        log.info("StorePlatformBathFacilityServiceController.deleteBatch ids={}", ids);
+        return facilityService.deleteFacilityBatch(ids);
+    }
+
+    @ApiOperation("Excel导入洗浴汗蒸设施")
+    @ApiOperationSupport(order = 9)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "file", value = "Excel文件", dataType = "file", paramType = "form", required = true),
+            @ApiImplicitParam(name = "storeId", value = "门店ID", dataType = "Integer", paramType = "query", required = true)
+    })
+    @PostMapping("/importFacility")
+    public R<String> importFacility(ExcelImportVo vo) {
+        log.info("StorePlatformBathFacilityServiceController.importFacility storeId={}", vo.getStoreId());
+        return facilityService.importFacilityFromExcel(vo.getFile(), vo.getStoreId());
+    }
+
+    @ApiOperation("下载洗浴汗蒸导入模板")
+    @ApiOperationSupport(order = 10)
+    @GetMapping("/downloadTemplate")
+    public void downloadTemplate(HttpServletResponse response) {
+        log.info("StorePlatformBathFacilityServiceController.downloadTemplate");
+        InputStream inputStream = null;
+        OutputStream outputStream = null;
+
+        try {
+            // 从resources/templates目录读取模板文件
+            Resource resource = new ClassPathResource("templates/洗浴汗蒸导入模板.xlsx");
+            inputStream = resource.getInputStream();
+
+            // 设置响应头
+            response.reset();
+            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
+            response.setCharacterEncoding("utf-8");
+
+            String fileName = "洗浴汗蒸导入模板.xlsx";
+            String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString()).replaceAll("\\+", "%20");
+            response.setHeader("Content-Disposition", "attachment;filename=\"" + encodedFileName + "\";filename*=utf-8''" + encodedFileName);
+
+            // 输出文件流
+            outputStream = response.getOutputStream();
+            byte[] buffer = new byte[1024];
+            int length;
+            while ((length = inputStream.read(buffer)) > 0) {
+                outputStream.write(buffer, 0, length);
+            }
+            outputStream.flush();
+
+            log.info("洗浴汗蒸导入模板下载成功");
+        } catch (Exception e) {
+            log.error("下载洗浴汗蒸导入模板失败", e);
+            throw new RuntimeException("下载模板失败:" + e.getMessage());
+        } finally {
+            try {
+                if (inputStream != null) {
+                    inputStream.close();
+                }
+                if (outputStream != null) {
+                    outputStream.close();
+                }
+            } catch (Exception e) {
+                log.error("关闭流失败", e);
+            }
+        }
+    }
+}

+ 2 - 2
alien-store-platform/src/main/java/shop/alien/storeplatform/controller/StorePlatformSportsEquipmentFacilityController.java

@@ -27,12 +27,12 @@ import java.util.List;
  * @since 2025-01-XX
  */
 @Slf4j
-@Api(tags = {"商户平台-运动健身"})
+@Api(tags = {"商户平台-运动健身-设施器材"})
 @ApiSort(1)
 @CrossOrigin
 @RestController
 @RequiredArgsConstructor
-@RequestMapping("/storePlatformSportsEquipmentFacility")
+@RequestMapping("/sportsEquipmentFacility")
 public class StorePlatformSportsEquipmentFacilityController {
 
     private final StorePlatformSportsEquipmentFacilityService facilityService;

+ 97 - 0
alien-store-platform/src/main/java/shop/alien/storeplatform/controller/StorePlatformStoreStaffConfigController.java

@@ -0,0 +1,97 @@
+package shop.alien.storeplatform.controller;
+
+import io.swagger.annotations.*;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.CrossOrigin;
+import org.springframework.web.bind.annotation.*;
+import shop.alien.entity.result.R;
+import shop.alien.storeplatform.entity.StorePlatformStoreStaffConfig;
+import shop.alien.storeplatform.service.StorePlatformStoreStaffConfigService;
+
+import java.util.List;
+
+@Slf4j
+@Api(tags = {"商户平台-运动健身-人员配置"})
+@ApiSort(1)
+@CrossOrigin
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/storeStaffConfig")
+public class StorePlatformStoreStaffConfigController {
+
+    private final StorePlatformStoreStaffConfigService staffConfigService;
+
+    @ApiOperation("根据ID查询员工")
+    @ApiOperationSupport(order = 1)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "员工ID", dataType = "Integer", paramType = "query", required = true)
+    })
+    @GetMapping("/getById")
+    public R<StorePlatformStoreStaffConfig> getById(@RequestParam("id") Integer id) {
+        log.info("StorePlatformStoreStaffConfigController.getById id={}", id);
+        StorePlatformStoreStaffConfig staffConfig = staffConfigService.getById(id);
+        if (staffConfig == null) {
+            return R.fail("员工不存在");
+        }
+        return R.data(staffConfig);
+    }
+
+    @ApiOperation("根据门店ID查询员工列表")
+    @ApiOperationSupport(order = 2)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "storeId", value = "门店ID", dataType = "Integer", paramType = "query", required = true)
+    })
+    @GetMapping("/getListByStoreId")
+    public R<List<StorePlatformStoreStaffConfig>> getListByStoreId(@RequestParam("storeId") Integer storeId) {
+        log.info("StorePlatformStoreStaffConfigController.getListByStoreId storeId={}", storeId);
+        List<StorePlatformStoreStaffConfig> list = staffConfigService.getListByStoreId(storeId);
+        return R.data(list);
+    }
+
+    @ApiOperation("新增员工")
+    @ApiOperationSupport(order = 3)
+    @PostMapping("/save")
+    public R<String> save(@RequestBody StorePlatformStoreStaffConfig staffConfig) {
+        log.info("StorePlatformStoreStaffConfigController.save staffConfig={}", staffConfig);
+        return staffConfigService.saveStaff(staffConfig);
+    }
+
+    @ApiOperation("修改员工")
+    @ApiOperationSupport(order = 4)
+    @PostMapping("/update")
+    public R<String> update(@RequestBody StorePlatformStoreStaffConfig staffConfig) {
+        log.info("StorePlatformStoreStaffConfigController.update staffConfig={}", staffConfig);
+        return staffConfigService.updateStaff(staffConfig);
+    }
+
+    @ApiOperation("新增或修改员工")
+    @ApiOperationSupport(order = 5)
+    @PostMapping("/saveOrUpdate")
+    public R<String> saveOrUpdate(@RequestBody StorePlatformStoreStaffConfig staffConfig) {
+        log.info("StorePlatformStoreStaffConfigController.saveOrUpdate staffConfig={}", staffConfig);
+        return staffConfigService.saveOrUpdateStaff(staffConfig);
+    }
+
+    @ApiOperation("删除员工")
+    @ApiOperationSupport(order = 6)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "员工ID", dataType = "Integer", paramType = "query", required = true)
+    })
+    @GetMapping("/delete")
+    public R<String> delete(@RequestParam("id") Integer id) {
+        log.info("StorePlatformStoreStaffConfigController.delete id={}", id);
+        return staffConfigService.deleteStaff(id);
+    }
+
+    @ApiOperation("批量删除员工")
+    @ApiOperationSupport(order = 7)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "ids", value = "员工ID列表", dataType = "List", paramType = "query", required = true)
+    })
+    @GetMapping("/deleteBatch")
+    public R<String> deleteBatch(@RequestParam("ids") List<Integer> ids) {
+        log.info("StorePlatformStoreStaffConfigController.deleteBatch ids={}", ids);
+        return staffConfigService.deleteStaffBatch(ids);
+    }
+}

+ 6 - 2
alien-store-platform/src/main/java/shop/alien/storeplatform/entity/StorePlatformBathFacilityService.java → alien-store-platform/src/main/java/shop/alien/storeplatform/entity/StorePlatformBathFacility.java

@@ -20,7 +20,7 @@ import java.util.Date;
 @JsonInclude
 @TableName("bath_facility_service")
 @ApiModel(value = "BathFacilityService对象", description = "洗浴设施及服务表")
-public class StorePlatformBathFacilityService implements Serializable {
+public class StorePlatformBathFacility implements Serializable {
 
     private static final long serialVersionUID = 1L;
 
@@ -32,7 +32,7 @@ public class StorePlatformBathFacilityService implements Serializable {
     @TableField("store_id")
     private Integer storeId;
 
-    @ApiModelProperty(value = "设施分类(1:洗浴区, 2:汗蒸区, 3:休闲区, 4:餐饮区)")
+    @ApiModelProperty(value = "区域分类(1:洗浴区, 2:汗蒸区, 3:休闲区, 4:餐饮区)")
     @TableField("facility_category")
     private Integer facilityCategory;
 
@@ -82,5 +82,9 @@ public class StorePlatformBathFacilityService implements Serializable {
     @ApiModelProperty(value = "修改人ID")
     @TableField(value = "updated_user_id", fill = FieldFill.INSERT_UPDATE)
     private Integer updatedUserId;
+
+    @ApiModelProperty(value = "图片id")
+    @TableField(exist = false)
+    private String imgUrl;
 }
 

+ 4 - 0
alien-store-platform/src/main/java/shop/alien/storeplatform/entity/StorePlatformStoreMenu.java

@@ -34,6 +34,10 @@ public class StorePlatformStoreMenu {
     @TableField("img_id")
     private Integer imgId;
 
+    @ApiModelProperty(value = "图片id")
+    @TableField(exist = false)
+    private String imgUrl;
+
     @ApiModelProperty(value = "菜单类型:1-菜单,2-酒水")
     @TableField("dish_menu_type")
     private Integer dishMenuType;

+ 10 - 0
alien-store-platform/src/main/java/shop/alien/storeplatform/mapper/StorePlatformBathFacilityServiceMapper.java

@@ -0,0 +1,10 @@
+package shop.alien.storeplatform.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import shop.alien.storeplatform.entity.StorePlatformBathFacility;
+
+
+@Mapper
+public interface StorePlatformBathFacilityServiceMapper extends BaseMapper<StorePlatformBathFacility> {
+}

+ 9 - 0
alien-store-platform/src/main/java/shop/alien/storeplatform/mapper/StorePlatformStoreStaffConfigMapper.java

@@ -0,0 +1,9 @@
+package shop.alien.storeplatform.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import shop.alien.storeplatform.entity.StorePlatformStoreStaffConfig;
+
+@Mapper
+public interface StorePlatformStoreStaffConfigMapper extends BaseMapper<StorePlatformStoreStaffConfig> {
+}

+ 1 - 1
alien-store-platform/src/main/java/shop/alien/storeplatform/service/StorePlatformBarMenuService.java

@@ -38,7 +38,7 @@ public interface StorePlatformBarMenuService extends IService<StorePlatformStore
      * @param dishMenuType 菜单类型:1-菜单,2-酒水
      * @return 菜单列表
      */
-    List<StorePlatformStoreMenu> getListByStoreIdAndType(Integer storeId, String dishMenuType);
+    List<StorePlatformStoreMenu> getListByStoreIdAndType(Integer storeId, String dishMenuType, String dishType);
 
     /**
      * 新增菜单

+ 85 - 0
alien-store-platform/src/main/java/shop/alien/storeplatform/service/StorePlatformBathFacilityService.java

@@ -0,0 +1,85 @@
+package shop.alien.storeplatform.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.springframework.web.multipart.MultipartFile;
+import shop.alien.entity.result.R;
+import shop.alien.storeplatform.entity.StorePlatformBathFacility;
+
+import java.util.List;
+
+/**
+ * 商户平台-洗浴设施及服务服务类
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+public interface StorePlatformBathFacilityService extends IService<StorePlatformBathFacility> {
+
+    /**
+     * 根据ID查询设施
+     *
+     * @param id 设施ID
+     * @return 设施信息
+     */
+    StorePlatformBathFacility getById(Integer id);
+
+    /**
+     * 根据门店ID查询设施列表
+     *
+     * @param storeId 门店ID
+     * @return 设施列表
+     */
+    List<StorePlatformBathFacility> getListByStoreId(Integer storeId);
+
+    /**
+     * 根据门店ID和区域分类查询设施列表
+     *
+     * @param storeId         门店ID
+     * @param facilityCategory 区域分类(1:洗浴区, 2:汗蒸区, 3:休闲区, 4:餐饮区)
+     * @return 设施列表
+     */
+    List<StorePlatformBathFacility> getListByStoreIdAndCategory(Integer storeId, Integer facilityCategory);
+
+    /**
+     * 新增设施
+     *
+     * @param facility 设施信息
+     * @return 操作结果
+     */
+    R<String> saveFacility(StorePlatformBathFacility facility);
+
+    /**
+     * 修改设施
+     *
+     * @param facility 设施信息
+     * @return 操作结果
+     */
+    R<String> updateFacility(StorePlatformBathFacility facility);
+
+    /**
+     * 新增或修改设施
+     *
+     * @param facility 设施信息
+     * @return 操作结果
+     */
+    R<String> saveOrUpdateFacility(StorePlatformBathFacility facility);
+
+    /**
+     * 删除设施(逻辑删除)
+     *
+     * @param id 设施ID
+     * @return 操作结果
+     */
+    R<String> deleteFacility(Integer id);
+
+    /**
+     * 批量删除设施(逻辑删除)
+     *
+     * @param ids 设施ID列表
+     * @return 操作结果
+     */
+    R<String> deleteFacilityBatch(List<Integer> ids);
+
+    R<String> importFacilityFromExcel(MultipartFile file, Integer storeId);
+
+}

+ 48 - 0
alien-store-platform/src/main/java/shop/alien/storeplatform/service/StorePlatformStoreStaffConfigService.java

@@ -0,0 +1,48 @@
+package shop.alien.storeplatform.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import shop.alien.entity.result.R;
+import shop.alien.storeplatform.entity.StorePlatformStoreStaffConfig;
+
+import java.util.List;
+
+/**
+ * 商户平台-员工管理 服务类
+ */
+public interface StorePlatformStoreStaffConfigService extends IService<StorePlatformStoreStaffConfig>  {
+
+    /**
+     * 根据ID查询员工
+     */
+    StorePlatformStoreStaffConfig getById(Integer id);
+
+    /**
+     * 根据门店ID查询员工列表
+     */
+    List<StorePlatformStoreStaffConfig> getListByStoreId(Integer storeId);
+
+    /**
+     * 新增员工
+     */
+    R<String> saveStaff(StorePlatformStoreStaffConfig staffConfig);
+
+    /**
+     * 修改员工
+     */
+    R<String> updateStaff(StorePlatformStoreStaffConfig staffConfig);
+
+    /**
+     * 新增或修改员工
+     */
+    R<String> saveOrUpdateStaff(StorePlatformStoreStaffConfig staffConfig);
+
+    /**
+     * 删除员工
+     */
+    R<String> deleteStaff(Integer id);
+
+    /**
+     * 批量删除员工
+     */
+    R<String> deleteStaffBatch(List<Integer> ids);
+}

+ 19 - 1
alien-store-platform/src/main/java/shop/alien/storeplatform/service/impl/StorePlatformBarMenuServiceImpl.java

@@ -76,7 +76,7 @@ public class StorePlatformBarMenuServiceImpl extends ServiceImpl<StorePlatformSt
     }
 
     @Override
-    public List<StorePlatformStoreMenu> getListByStoreIdAndType(Integer storeId, String dishMenuType) {
+    public List<StorePlatformStoreMenu> getListByStoreIdAndType(Integer storeId, String dishMenuType, String dishType) {
         log.info("StorePlatformBarMenuServiceImpl.getListByStoreIdAndType storeId={}, dishMenuType={}", storeId, dishMenuType);
         if (storeId == null) {
             throw new RuntimeException("门店ID不能为空");
@@ -87,8 +87,26 @@ public class StorePlatformBarMenuServiceImpl extends ServiceImpl<StorePlatformSt
         if (StringUtils.isNotEmpty(dishMenuType)) {
             queryWrapper.eq(StorePlatformStoreMenu::getDishMenuType, dishMenuType);
         }
+        if (StringUtils.isNotEmpty(dishType) && dishType.equals("1")) {
+            queryWrapper.eq(StorePlatformStoreMenu::getDishType, dishType);
+        }
         queryWrapper.orderByAsc(StorePlatformStoreMenu::getSort);
         List<StorePlatformStoreMenu> list = this.list(queryWrapper);
+
+        // 查询图片
+        List<Integer> ids = list.stream().map(StorePlatformStoreMenu::getImgId).collect(Collectors.toList());
+        List<StoreImg> imgList = storeImgMapper.selectList(new LambdaQueryWrapper<StoreImg>()
+                .eq(StoreImg::getStoreId, storeId).eq(StoreImg::getImgType, 7).in(StoreImg::getId, ids));
+
+        if (CollectionUtil.isNotEmpty(imgList)) {
+            list.forEach(menu -> {
+                imgList.stream()
+                        .filter(img -> img.getId().equals(menu.getImgId()))
+                        .findFirst()
+                        .ifPresent(img -> menu.setImgUrl(img.getImgUrl()));
+            });
+        }
+
         return list.stream()
                 .sorted(Comparator.comparing(StorePlatformStoreMenu::getSort))
                 .collect(Collectors.toList());

+ 648 - 0
alien-store-platform/src/main/java/shop/alien/storeplatform/service/impl/StorePlatformBathFacilityServiceImpl.java

@@ -0,0 +1,648 @@
+package shop.alien.storeplatform.service.impl;
+
+import cn.hutool.core.collection.CollectionUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.xssf.usermodel.*;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.multipart.MultipartFile;
+import shop.alien.entity.result.R;
+import shop.alien.entity.store.StoreImg;
+import shop.alien.entity.store.excelVo.util.ExcelImage;
+import shop.alien.mapper.StoreImgMapper;
+import shop.alien.storeplatform.entity.StorePlatformBathFacility;
+import shop.alien.storeplatform.entity.StorePlatformStoreMenu;
+import shop.alien.storeplatform.feign.AlienStoreFeign;
+import shop.alien.storeplatform.mapper.StorePlatformBathFacilityServiceMapper;
+import shop.alien.storeplatform.service.StorePlatformBathFacilityService;
+import shop.alien.storeplatform.vo.StorePlatformBathFacilityImportVo;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 商户平台-洗浴设施及服务服务实现类
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class StorePlatformBathFacilityServiceImpl extends ServiceImpl<StorePlatformBathFacilityServiceMapper, StorePlatformBathFacility> implements StorePlatformBathFacilityService {
+
+    private final StorePlatformBathFacilityServiceMapper facilityMapper;
+
+    private final AlienStoreFeign alienStoreFeign;
+
+    private final StoreImgMapper storeImgMapper;
+
+    @Override
+    public StorePlatformBathFacility getById(Integer id) {
+        log.info("StorePlatformBathFacilityServiceImpl.getById id={}", id);
+        if (id == null) {
+            throw new RuntimeException("设施ID不能为空");
+        }
+        return super.getById(id);
+    }
+
+    @Override
+    public List<StorePlatformBathFacility> getListByStoreId(Integer storeId) {
+        log.info("StorePlatformBathFacilityServiceImpl.getListByStoreId storeId={}", storeId);
+        if (storeId == null) {
+            throw new RuntimeException("门店ID不能为空");
+        }
+        LambdaQueryWrapper<StorePlatformBathFacility> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(StorePlatformBathFacility::getStoreId, storeId)
+                .eq(StorePlatformBathFacility::getDeleteFlag, 0)
+                .orderByAsc(StorePlatformBathFacility::getFacilityCategory)
+                .orderByAsc(StorePlatformBathFacility::getId);
+
+        List<StorePlatformBathFacility> list = this.list(queryWrapper);
+
+        // 查询图片
+        List<Integer> ids = list.stream().map(StorePlatformBathFacility::getId).collect(Collectors.toList());
+        List<StoreImg> imgList = storeImgMapper.selectList(new LambdaQueryWrapper<StoreImg>()
+                .eq(StoreImg::getStoreId, storeId).eq(StoreImg::getImgType, 29).in(StoreImg::getBusinessId, ids));
+
+        if (CollectionUtil.isNotEmpty(imgList)) {
+            list.forEach(facility -> {
+                imgList.stream()
+                        .filter(img -> img.getBusinessId().equals(facility.getId()))
+                        .findFirst()
+                        .ifPresent(img -> facility.setImgUrl(img.getImgUrl()));
+            });
+        }
+        return this.list(queryWrapper);
+    }
+
+    @Override
+    public List<StorePlatformBathFacility> getListByStoreIdAndCategory(Integer storeId, Integer facilityCategory) {
+        log.info("StorePlatformBathFacilityServiceImpl.getListByStoreIdAndCategory storeId={}, facilityCategory={}", storeId, facilityCategory);
+        if (storeId == null) {
+            throw new RuntimeException("门店ID不能为空");
+        }
+        LambdaQueryWrapper<StorePlatformBathFacility> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(StorePlatformBathFacility::getStoreId, storeId)
+                .eq(StorePlatformBathFacility::getDeleteFlag, 0);
+        if (facilityCategory != null) {
+            queryWrapper.eq(StorePlatformBathFacility::getFacilityCategory, facilityCategory);
+        }
+        queryWrapper.orderByAsc(StorePlatformBathFacility::getFacilityCategory)
+                .orderByAsc(StorePlatformBathFacility::getId);
+
+        List<StorePlatformBathFacility> list = this.list(queryWrapper);
+
+        // 查询图片
+        List<Integer> ids = list.stream().map(StorePlatformBathFacility::getId).collect(Collectors.toList());
+        List<StoreImg> imgList = storeImgMapper.selectList(new LambdaQueryWrapper<StoreImg>()
+                .eq(StoreImg::getStoreId, storeId).eq(StoreImg::getImgType, 29).in(StoreImg::getBusinessId, ids));
+
+        if (CollectionUtil.isNotEmpty(imgList)) {
+            list.forEach(facility -> {
+                imgList.stream()
+                        .filter(img -> img.getBusinessId().equals(facility.getId()))
+                        .findFirst()
+                        .ifPresent(img -> facility.setImgUrl(img.getImgUrl()));
+            });
+        }
+        return this.list(queryWrapper);
+    }
+
+    @Override
+    public R<String> saveFacility(StorePlatformBathFacility facility) {
+        log.info("StorePlatformBathFacilityServiceImpl.saveFacility facility={}", facility);
+        if (facility == null) {
+            return R.fail("设施信息不能为空");
+        }
+        if (facility.getStoreId() == null) {
+            return R.fail("门店ID不能为空");
+        }
+        if (StringUtils.isEmpty(facility.getFacilityName())) {
+            return R.fail("名称不能为空");
+        }
+        if (facility.getFacilityCategory() == null) {
+            return R.fail("区域分类不能为空");
+        }
+        // 如果使用时间类型为选择时间,则必须填写开始和结束时间
+        if (facility.getUsageTimeType() != null && facility.getUsageTimeType() == 1) {
+            if (StringUtils.isEmpty(facility.getUsageStartTime()) || StringUtils.isEmpty(facility.getUsageEndTime())) {
+                return R.fail("使用时间类型为选择时间时,开始时间和结束时间不能为空");
+            }
+        }
+
+        boolean flag = this.save(facility);
+        if (!flag) {
+            return R.fail("新增设施失败");
+        }
+        return R.success("新增设施成功");
+    }
+
+    @Override
+    public R<String> updateFacility(StorePlatformBathFacility facility) {
+        log.info("StorePlatformBathFacilityServiceImpl.updateFacility facility={}", facility);
+        if (facility == null || facility.getId() == null) {
+            return R.fail("设施信息或设施ID不能为空");
+        }
+        if (StringUtils.isEmpty(facility.getFacilityName())) {
+            return R.fail("名称不能为空");
+        }
+        if (facility.getFacilityCategory() == null) {
+            return R.fail("区域分类不能为空");
+        }
+        // 如果使用时间类型为选择时间,则必须填写开始和结束时间
+        if (facility.getUsageTimeType() != null && facility.getUsageTimeType() == 1) {
+            if (StringUtils.isEmpty(facility.getUsageStartTime()) || StringUtils.isEmpty(facility.getUsageEndTime())) {
+                return R.fail("使用时间类型为选择时间时,开始时间和结束时间不能为空");
+            }
+        }
+
+        boolean flag = this.updateById(facility);
+        if (!flag) {
+            return R.fail("修改设施失败");
+        }
+        return R.success("修改设施成功");
+    }
+
+    @Override
+    public R<String> saveOrUpdateFacility(StorePlatformBathFacility facility) {
+        log.info("StorePlatformBathFacilityServiceImpl.saveOrUpdateFacility facility={}", facility);
+        if (facility == null) {
+            return R.fail("设施信息不能为空");
+        }
+
+        if (facility.getId() != null) {
+            // 修改
+            return updateFacility(facility);
+        } else {
+            // 新增
+            return saveFacility(facility);
+        }
+    }
+
+    @Override
+    public R<String> deleteFacility(Integer id) {
+        log.info("StorePlatformBathFacilityServiceImpl.deleteFacility id={}", id);
+        if (id == null) {
+            return R.fail("设施ID不能为空");
+        }
+
+        boolean flag = this.removeById(id);
+        if (!flag) {
+            return R.fail("删除设施失败");
+        }
+        return R.success("删除设施成功");
+    }
+
+    @Override
+    public R<String> deleteFacilityBatch(List<Integer> ids) {
+        log.info("StorePlatformBathFacilityServiceImpl.deleteFacilityBatch ids={}", ids);
+        if (CollectionUtil.isEmpty(ids)) {
+            return R.fail("设施ID列表不能为空");
+        }
+
+        boolean flag = this.removeByIds(ids);
+        if (!flag) {
+            return R.fail("批量删除设施失败");
+        }
+        return R.success("批量删除设施成功");
+    }
+
+    @Override
+    public R<String> importFacilityFromExcel(MultipartFile file, Integer storeId) {
+        log.info("StorePlatformBathFacilityServiceImpl.importFacilityFromExcel storeId={}", storeId);
+
+        if (file == null || file.isEmpty()) {
+            return R.fail("上传文件为空");
+        }
+
+        String fileName = file.getOriginalFilename();
+        if (fileName == null || (!fileName.endsWith(".xlsx") && !fileName.endsWith(".xls"))) {
+            return R.fail("文件格式不正确,请上传Excel文件");
+        }
+
+        if (storeId == null) {
+            return R.fail("门店ID不能为空");
+        }
+
+        List<String> errorMessages = new ArrayList<>();
+        int successCount = 0;
+        int totalCount = 0;
+
+        try (InputStream inputStream = file.getInputStream();
+             XSSFWorkbook workbook = new XSSFWorkbook(inputStream)) {
+            Sheet sheet = workbook.getSheetAt(0);
+
+            // 获取表头(假设表头在第5行,索引为5)
+            Row headerRow = sheet.getRow(5);
+            if (headerRow == null) {
+                return R.fail("Excel文件格式不正确,缺少表头");
+            }
+
+            // 构建字段映射(表头名称 -> 列索引)
+            Map<String, Integer> headerMap = new HashMap<>();
+            Field[] fields = StorePlatformBathFacilityImportVo.class.getDeclaredFields();
+            for (int i = 0; i < headerRow.getLastCellNum(); i++) {
+                Cell cell = headerRow.getCell(i);
+                if (cell != null) {
+                    String headerName = getCellValueAsString(cell);
+                    if (StringUtils.isNotEmpty(headerName)) {
+                        headerMap.put(headerName.trim(), i);
+                    }
+                }
+            }
+
+            // 获取图片映射(行索引 -> 图片字节数组)
+            Map<Integer, byte[]> imageMap = extractImagesFromSheet(sheet);
+
+            // 读取数据行(从第6行开始,索引为6)
+            for (int rowIndex = 6; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
+                Row row = sheet.getRow(rowIndex);
+                if (row == null) {
+                    continue;
+                }
+
+                // 检查是否为空行
+                boolean isEmptyRow = true;
+                for (int i = 0; i < row.getLastCellNum(); i++) {
+                    Cell cell = row.getCell(i);
+                    if (cell != null && cell.getCellType() != CellType.BLANK) {
+                        String cellValue = getCellValueAsString(cell);
+                        if (StringUtils.isNotEmpty(cellValue)) {
+                            isEmptyRow = false;
+                            break;
+                        }
+                    }
+                }
+                if (isEmptyRow) {
+                    continue;
+                }
+
+                totalCount++;
+                StorePlatformBathFacilityImportVo excelVo = new StorePlatformBathFacilityImportVo();
+
+                // 读取每个字段
+                for (Field field : fields) {
+                    field.setAccessible(true);
+                    String fieldName = field.getName();
+                    Integer colIndex = null;
+
+                    // 根据字段名查找对应的表头
+                    for (Map.Entry<String, Integer> entry : headerMap.entrySet()) {
+                        String headerName = entry.getKey();
+                        if (isFieldMatch(fieldName, headerName)) {
+                            colIndex = entry.getValue();
+                            break;
+                        }
+                    }
+
+                    if (colIndex == null) {
+                        continue;
+                    }
+
+                    Cell cell = row.getCell(colIndex);
+                    if (cell == null && !field.isAnnotationPresent(ExcelImage.class)) {
+                        continue;
+                    }
+
+                    try {
+                        if (field.isAnnotationPresent(ExcelImage.class)) {
+                            // 处理图片字段
+                            byte[] imageBytes = imageMap.get(rowIndex);
+                            if (imageBytes != null && imageBytes.length > 0) {
+                                String imageName = "bathFacility_" + storeId + "_" + System.currentTimeMillis() + "_" + rowIndex + ".jpg";
+                                MultipartFile multipartFile = new ByteArrayMultipartFile(imageBytes, imageName);
+                                JSONObject jsonObject = alienStoreFeign.uploadFile(multipartFile);
+                                if (200 == jsonObject.getIntValue("code")) {
+                                    field.set(excelVo, jsonObject.getJSONArray("data").get(0));
+                                } else {
+                                    field.set(excelVo, "");
+                                }
+                            }
+                        } else {
+                            // 处理普通字段
+                            String cellValue = getCellValueAsString(cell);
+                            if (StringUtils.isNotEmpty(cellValue)) {
+                                setFieldValue(excelVo, field, cellValue.trim());
+                            }
+                        }
+                    } catch (Exception e) {
+                        log.warn("读取字段{}失败:{}", fieldName, e.getMessage());
+                    }
+                }
+
+                // 处理导入数据
+                try {
+                    validateAndSaveFacility(excelVo, storeId, rowIndex + 1);
+                    successCount++;
+                } catch (Exception e) {
+                    errorMessages.add(String.format("第%d行:%s", rowIndex + 1, e.getMessage()));
+                    log.error("导入第{}行数据失败", rowIndex + 1, e);
+                }
+            }
+        } catch (Exception e) {
+            log.error("导入Excel失败", e);
+            return R.fail("导入失败:" + e.getMessage());
+        }
+
+        // 构建返回消息
+        StringBuilder message = new StringBuilder();
+        message.append(String.format("导入完成:成功%d条,失败%d条", successCount, totalCount - successCount));
+        if (!errorMessages.isEmpty()) {
+            message.append("\n失败详情:\n");
+            for (int i = 0; i < Math.min(errorMessages.size(), 10); i++) {
+                message.append(errorMessages.get(i)).append("\n");
+            }
+            if (errorMessages.size() > 10) {
+                message.append("...还有").append(errorMessages.size() - 10).append("条错误信息");
+            }
+        }
+
+        return R.success(message.toString());
+    }
+
+    /**
+     * 判断字段名是否匹配表头
+     */
+    private boolean isFieldMatch(String fieldName, String headerName) {
+        Map<String, String> fieldMapping = new HashMap<>();
+        fieldMapping.put("facilityCategory", "区域(洗浴区/汗蒸区/休闲区/餐饮区)");
+        fieldMapping.put("facilityName", "名称");
+        fieldMapping.put("img", "图片");
+        fieldMapping.put("chargingStandard", "收费标准(元)");
+        fieldMapping.put("usageTimeType", "开放时间(全天/自定义时间)");
+        fieldMapping.put("usageStartTime", "自定义开始时间");
+        fieldMapping.put("usageEndTime", "自定义结束时间");
+        fieldMapping.put("displayInStoreDetail", "状态(展示/隐藏)");
+
+        String expectedHeader = fieldMapping.get(fieldName);
+        return expectedHeader != null && expectedHeader.equals(headerName);
+    }
+
+    /**
+     * 设置字段值
+     */
+    private void setFieldValue(StorePlatformBathFacilityImportVo excelVo, Field field, String cellValue) throws Exception {
+        Class<?> fieldType = field.getType();
+        String fieldName = field.getName();
+
+        if (fieldType == Integer.class) {
+            if ("facilityCategory".equals(fieldName)) {
+                // 处理区域分类:洗浴区->1, 汗蒸区->2, 休闲区->3, 餐饮区->4
+                String trimmedValue = cellValue.trim();
+                if ("洗浴区".equals(trimmedValue)) {
+                    field.set(excelVo, 1);
+                } else if ("汗蒸区".equals(trimmedValue)) {
+                    field.set(excelVo, 2);
+                } else if ("休闲区".equals(trimmedValue)) {
+                    field.set(excelVo, 3);
+                } else if ("餐饮区".equals(trimmedValue)) {
+                    field.set(excelVo, 4);
+                } else {
+                    throw new RuntimeException("区域分类格式错误,请输入'洗浴区'、'汗蒸区'、'休闲区'或'餐饮区'");
+                }
+            } else if ("usageTimeType".equals(fieldName)) {
+                // 处理开放时间:全天->0, 自定义时间->1
+                String trimmedValue = cellValue.trim();
+                if ("全天".equals(trimmedValue)) {
+                    field.set(excelVo, 0);
+                } else if ("自定义时间".equals(trimmedValue)) {
+                    field.set(excelVo, 1);
+                } else {
+                    throw new RuntimeException("开放时间格式错误,请输入'全天'或'自定义时间'");
+                }
+            } else if ("displayInStoreDetail".equals(fieldName)) {
+                // 处理状态:展示->1, 隐藏->0
+                String trimmedValue = cellValue.trim();
+                if ("展示".equals(trimmedValue)) {
+                    field.set(excelVo, 1);
+                } else if ("隐藏".equals(trimmedValue)) {
+                    field.set(excelVo, 0);
+                } else {
+                    throw new RuntimeException("状态字段格式错误,请输入'展示'或'隐藏'");
+                }
+            } else {
+                // 其他Integer字段直接解析
+                try {
+                    field.set(excelVo, Integer.parseInt(cellValue));
+                } catch (NumberFormatException e) {
+                    throw new RuntimeException(fieldName + "字段格式错误,请输入数字");
+                }
+            }
+        } else {
+            // String类型
+            field.set(excelVo, cellValue);
+        }
+    }
+
+    /**
+     * 校验并保存设施
+     */
+    private void validateAndSaveFacility(StorePlatformBathFacilityImportVo excelVo, Integer storeId, int rowNum) {
+        // 校验必填字段
+        if (StringUtils.isEmpty(excelVo.getFacilityName())) {
+            throw new RuntimeException("名称不能为空");
+        }
+        if (excelVo.getFacilityCategory() == null) {
+            throw new RuntimeException("区域分类不能为空");
+        }
+
+        // 校验开放时间和自定义时间段
+        Integer usageTimeType = excelVo.getUsageTimeType() != null ? excelVo.getUsageTimeType() : 0;
+        String usageStartTime = excelVo.getUsageStartTime();
+        String usageEndTime = excelVo.getUsageEndTime();
+
+        if (usageTimeType == 0) {
+            // 全天:自定义开始时间和结束时间应该为空
+            if (StringUtils.isNotEmpty(usageStartTime) || StringUtils.isNotEmpty(usageEndTime)) {
+                throw new RuntimeException("开放时间为'全天'时,自定义开始时间和结束时间不能填写");
+            }
+        } else if (usageTimeType == 1) {
+            // 自定义时间:自定义开始时间和结束时间必须填写
+            if (StringUtils.isEmpty(usageStartTime)) {
+                throw new RuntimeException("开放时间为'自定义时间'时,自定义开始时间不能为空");
+            }
+            if (StringUtils.isEmpty(usageEndTime)) {
+                throw new RuntimeException("开放时间为'自定义时间'时,自定义结束时间不能为空");
+            }
+            // 校验时间格式:HH:mm
+            if (!isValidTimeFormat(usageStartTime)) {
+                throw new RuntimeException("自定义开始时间格式错误,请输入'HH:mm'格式,如'16:00'");
+            }
+            if (!isValidTimeFormat(usageEndTime)) {
+                throw new RuntimeException("自定义结束时间格式错误,请输入'HH:mm'格式,如'18:00'");
+            }
+        }
+
+        // 创建StorePlatformBathFacility对象
+        StorePlatformBathFacility facility = new StorePlatformBathFacility();
+        facility.setStoreId(storeId);
+        facility.setFacilityCategory(excelVo.getFacilityCategory());
+        facility.setFacilityName(excelVo.getFacilityName());
+        facility.setChargingStandard(excelVo.getChargingStandard());
+        facility.setUsageTimeType(usageTimeType);
+        facility.setDisplayInStoreDetail(excelVo.getDisplayInStoreDetail() != null ? excelVo.getDisplayInStoreDetail() : 0);
+
+        // 设置开始和结束时间
+        if (usageTimeType == 1) {
+            facility.setUsageStartTime(usageStartTime);
+            facility.setUsageEndTime(usageEndTime);
+        } else {
+            facility.setUsageStartTime(null);
+            facility.setUsageEndTime(null);
+        }
+
+        // 保存设施
+        boolean flag = this.save(facility);
+
+        // 处理图片
+        if (StringUtils.isNotEmpty(excelVo.getImg())) {
+            StoreImg storeImg = new StoreImg();
+            storeImg.setStoreId(storeId);
+            storeImg.setImgType(29); // 菜单图片类型
+            storeImg.setImgUrl(excelVo.getImg());
+            storeImg.setBusinessId(facility.getId());
+            storeImgMapper.insert(storeImg);
+        }
+        if (!flag) {
+            throw new RuntimeException("保存设施失败");
+        }
+    }
+
+    /**
+     * 校验时间格式是否为 HH:mm
+     */
+    private boolean isValidTimeFormat(String time) {
+        if (StringUtils.isEmpty(time)) {
+            return false;
+        }
+        // 格式:HH:mm (00:00-23:59)
+        String timePattern = "^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$";
+        return time.matches(timePattern);
+    }
+
+    /**
+     * 获取单元格值(字符串格式)
+     */
+    private String getCellValueAsString(Cell cell) {
+        if (cell == null) {
+            return null;
+        }
+
+        switch (cell.getCellType()) {
+            case STRING:
+                return cell.getStringCellValue();
+            case NUMERIC:
+                if (org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell)) {
+                    return cell.getDateCellValue().toString();
+                } else {
+                    // 处理数字,避免科学计数法
+                    double numericValue = cell.getNumericCellValue();
+                    if (numericValue == (long) numericValue) {
+                        return String.valueOf((long) numericValue);
+                    } else {
+                        return String.valueOf(numericValue);
+                    }
+                }
+            case BOOLEAN:
+                return String.valueOf(cell.getBooleanCellValue());
+            case FORMULA:
+                return cell.getCellFormula();
+            default:
+                return null;
+        }
+    }
+
+    /**
+     * 从Sheet中提取图片
+     */
+    private Map<Integer, byte[]> extractImagesFromSheet(Sheet sheet) {
+        Map<Integer, byte[]> imageMap = new HashMap<>();
+        if (sheet instanceof XSSFSheet) {
+            XSSFSheet xssfSheet = (XSSFSheet) sheet;
+            XSSFDrawing drawing = xssfSheet.getDrawingPatriarch();
+            if (drawing != null) {
+                List<XSSFShape> shapes = drawing.getShapes();
+                for (XSSFShape shape : shapes) {
+                    if (shape instanceof XSSFPicture) {
+                        XSSFPicture picture = (XSSFPicture) shape;
+                        XSSFClientAnchor anchor = (XSSFClientAnchor) picture.getAnchor();
+                        int rowIndex = anchor.getRow1();
+                        try {
+                            // 直接使用 getData() 方法获取图片字节数组
+                            byte[] imageBytes = picture.getPictureData().getData();
+                            imageMap.put(rowIndex, imageBytes);
+                        } catch (Exception e) {
+                            log.warn("提取第{}行图片失败:{}", rowIndex, e.getMessage());
+                        }
+                    }
+                }
+            }
+        }
+        return imageMap;
+    }
+
+    /**
+     * 临时MultipartFile实现类,用于上传字节数组
+     */
+    private static class ByteArrayMultipartFile implements MultipartFile {
+        private final byte[] content;
+        private final String fileName;
+
+        public ByteArrayMultipartFile(byte[] content, String fileName) {
+            this.content = content;
+            this.fileName = fileName;
+        }
+
+        @Override
+        public String getName() {
+            return "file";
+        }
+
+        @Override
+        public String getOriginalFilename() {
+            return fileName;
+        }
+
+        @Override
+        public String getContentType() {
+            return "image/jpeg";
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return content == null || content.length == 0;
+        }
+
+        @Override
+        public long getSize() {
+            return content.length;
+        }
+
+        @Override
+        public byte[] getBytes() throws IOException {
+            return content;
+        }
+
+        @Override
+        public InputStream getInputStream() throws IOException {
+            return new ByteArrayInputStream(content);
+        }
+
+        @Override
+        public void transferTo(java.io.File dest) throws IOException, IllegalStateException {
+            java.nio.file.Files.write(dest.toPath(), content);
+        }
+    }
+
+}

+ 143 - 0
alien-store-platform/src/main/java/shop/alien/storeplatform/service/impl/StorePlatformStoreStaffConfigServiceImpl.java

@@ -0,0 +1,143 @@
+package shop.alien.storeplatform.service.impl;
+
+import cn.hutool.core.collection.CollectionUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import shop.alien.entity.result.R;
+import shop.alien.storeplatform.entity.StorePlatformStoreStaffConfig;
+import shop.alien.storeplatform.mapper.StorePlatformStoreStaffConfigMapper;
+import shop.alien.storeplatform.service.StorePlatformStoreStaffConfigService;
+
+import java.util.List;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class StorePlatformStoreStaffConfigServiceImpl extends ServiceImpl<StorePlatformStoreStaffConfigMapper, StorePlatformStoreStaffConfig> implements StorePlatformStoreStaffConfigService {
+
+    private final StorePlatformStoreStaffConfigMapper staffConfigMapper;
+
+    @Override
+    public StorePlatformStoreStaffConfig getById(Integer id) {
+        log.info("StorePlatformStoreStaffConfigServiceImpl.getById id={}", id);
+        if (id == null) {
+            throw new RuntimeException("员工ID不能为空");
+        }
+        return super.getById(id);
+    }
+
+    @Override
+    public List<StorePlatformStoreStaffConfig> getListByStoreId(Integer storeId) {
+        log.info("StorePlatformStoreStaffConfigServiceImpl.getListByStoreId storeId={}", storeId);
+        if (storeId == null) {
+            throw new RuntimeException("门店ID不能为空");
+        }
+        LambdaQueryWrapper<StorePlatformStoreStaffConfig> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(StorePlatformStoreStaffConfig::getStoreId, storeId)
+                .eq(StorePlatformStoreStaffConfig::getDeleteFlag, 0)
+                .orderByDesc(StorePlatformStoreStaffConfig::getTopStatus)
+                .orderByAsc(StorePlatformStoreStaffConfig::getId);
+        return this.list(queryWrapper);
+    }
+
+    @Override
+    public R<String> saveStaff(StorePlatformStoreStaffConfig staffConfig) {
+        log.info("StorePlatformStoreStaffConfigServiceImpl.saveStaff staffConfig={}", staffConfig);
+        String validateResult = validateStaffConfig(staffConfig, false);
+        if (validateResult != null) {
+            return R.fail(validateResult);
+        }
+
+        boolean flag = this.save(staffConfig);
+        if (!flag) {
+            return R.fail("新增员工失败");
+        }
+        return R.success("新增员工成功");
+    }
+
+    @Override
+    public R<String> updateStaff(StorePlatformStoreStaffConfig staffConfig) {
+        log.info("StorePlatformStoreStaffConfigServiceImpl.updateStaff staffConfig={}", staffConfig);
+        if (staffConfig == null || staffConfig.getId() == null) {
+            return R.fail("员工信息或员工ID不能为空");
+        }
+        String validateResult = validateStaffConfig(staffConfig, true);
+        if (validateResult != null) {
+            return R.fail(validateResult);
+        }
+
+        boolean flag = this.updateById(staffConfig);
+        if (!flag) {
+            return R.fail("修改员工失败");
+        }
+        return R.success("修改员工成功");
+    }
+
+    @Override
+    public R<String> saveOrUpdateStaff(StorePlatformStoreStaffConfig staffConfig) {
+        log.info("StorePlatformStoreStaffConfigServiceImpl.saveOrUpdateStaff staffConfig={}", staffConfig);
+        if (staffConfig == null) {
+            return R.fail("员工信息不能为空");
+        }
+        if (staffConfig.getId() == null) {
+            return saveStaff(staffConfig);
+        } else {
+            return updateStaff(staffConfig);
+        }
+    }
+
+    @Override
+    public R<String> deleteStaff(Integer id) {
+        log.info("StorePlatformStoreStaffConfigServiceImpl.deleteStaff id={}", id);
+        if (id == null) {
+            return R.fail("员工ID不能为空");
+        }
+        boolean flag = this.removeById(id);
+        if (!flag) {
+            return R.fail("删除员工失败");
+        }
+        return R.success("删除员工成功");
+    }
+
+    @Override
+    public R<String> deleteStaffBatch(List<Integer> ids) {
+        log.info("StorePlatformStoreStaffConfigServiceImpl.deleteStaffBatch ids={}", ids);
+        if (CollectionUtil.isEmpty(ids)) {
+            return R.fail("员工ID列表不能为空");
+        }
+        boolean flag = this.removeByIds(ids);
+        if (!flag) {
+            return R.fail("批量删除员工失败");
+        }
+        return R.success("批量删除员工成功");
+    }
+
+    /**
+     * 校验员工数据
+     */
+    private String validateStaffConfig(StorePlatformStoreStaffConfig staffConfig, boolean isUpdate) {
+        if (staffConfig == null) {
+            return "员工信息不能为空";
+        }
+        if (!isUpdate && staffConfig.getStoreId() == null) {
+            return "门店ID不能为空";
+        }
+        if (StringUtils.isEmpty(staffConfig.getName())) {
+            return "员工姓名不能为空";
+        }
+        if (StringUtils.isEmpty(staffConfig.getStaffPosition())) {
+            return "员工职位不能为空";
+        }
+        if (StringUtils.isEmpty(staffConfig.getStatus())) {
+            staffConfig.setStatus("0");
+        }
+        if (staffConfig.getTopStatus() == null) {
+            staffConfig.setTopStatus(0);
+        }
+        return null;
+    }
+}

+ 40 - 0
alien-store-platform/src/main/java/shop/alien/storeplatform/vo/StorePlatformBathFacilityImportVo.java

@@ -0,0 +1,40 @@
+package shop.alien.storeplatform.vo;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import shop.alien.entity.store.excelVo.util.ExcelImage;
+
+@Data
+@JsonInclude
+@ApiModel(value = "StorePlatformBathFacilityImportVo对象")
+public class StorePlatformBathFacilityImportVo {
+
+    @ApiModelProperty(value = "区域(洗浴区/汗蒸区/休闲区/餐饮区)")
+    private Integer facilityCategory;
+
+    @ApiModelProperty(value = "名称")
+    private String facilityName;
+
+    @ApiModelProperty(value = "图片")
+    @ExcelImage
+    private String img;
+
+    @ApiModelProperty(value = "收费标准(元)")
+    private String chargingStandard;
+
+    @ApiModelProperty(value = "开放时间")
+    private Integer usageTimeType;
+
+    @ApiModelProperty(value = "自定义开始时间")
+    private String usageStartTime;
+
+    @ApiModelProperty(value = "自定义结束时间")
+    private String usageEndTime;
+
+    @ApiModelProperty(value = "状态(展示/隐藏)")
+    private Integer displayInStoreDetail;
+
+}

BIN
alien-store-platform/src/main/resources/templates/洗浴汗蒸导入模板.xlsx