Parcourir la source

预约服务 分类管理增删改查

qinxuyang il y a 2 mois
Parent
commit
c13bad509e

+ 74 - 0
alien-entity/src/main/java/shop/alien/entity/store/StoreBookingCategory.java

@@ -0,0 +1,74 @@
+package shop.alien.entity.store;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 预订服务分类表
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@JsonInclude
+@TableName("store_booking_category")
+@ApiModel(value = "StoreBookingCategory对象", description = "预订服务分类表")
+public class StoreBookingCategory {
+
+    @ApiModelProperty(value = "主键ID")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @ApiModelProperty(value = "门店ID")
+    @TableField("store_id")
+    private Integer storeId;
+
+    @ApiModelProperty(value = "分类名称")
+    @TableField("category_name")
+    private String categoryName;
+
+    @ApiModelProperty(value = "平面图(包含桌号),最多9张图片,用逗号分隔")
+    @TableField("floor_plan_images")
+    private String floorPlanImages;
+
+    @ApiModelProperty(value = "是否显示(0:隐藏, 1:显示)")
+    @TableField("is_display")
+    private Integer isDisplay;
+
+    @ApiModelProperty(value = "最长预订时间(分钟)")
+    @TableField("max_booking_time")
+    private Integer maxBookingTime;
+
+    @ApiModelProperty(value = "排序")
+    @TableField("sort")
+    private Integer sort;
+
+    @ApiModelProperty(value = "删除标记, 0:未删除, 1:已删除")
+    @TableField("delete_flag")
+    @TableLogic
+    private Integer deleteFlag;
+
+    @ApiModelProperty(value = "创建时间")
+    @TableField(value = "created_time", fill = FieldFill.INSERT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date createdTime;
+
+    @ApiModelProperty(value = "创建人ID")
+    @TableField("created_user_id")
+    private Integer createdUserId;
+
+    @ApiModelProperty(value = "修改时间")
+    @TableField(value = "updated_time", fill = FieldFill.INSERT_UPDATE)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date updatedTime;
+
+    @ApiModelProperty(value = "修改人ID")
+    @TableField("updated_user_id")
+    private Integer updatedUserId;
+}

+ 39 - 0
alien-entity/src/main/java/shop/alien/entity/store/dto/StoreBookingCategoryDTO.java

@@ -0,0 +1,39 @@
+package shop.alien.entity.store.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 预订服务分类DTO
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@ApiModel(value = "StoreBookingCategoryDTO", description = "预订服务分类DTO")
+public class StoreBookingCategoryDTO {
+
+    @ApiModelProperty(value = "分类ID(编辑时必填)")
+    private Integer id;
+
+    @ApiModelProperty(value = "门店ID", required = true)
+    private Integer storeId;
+
+    @ApiModelProperty(value = "分类名称", required = true)
+    private String categoryName;
+
+    @ApiModelProperty(value = "平面图(包含桌号),最多9张图片,用逗号分隔", required = true)
+    private String floorPlanImages;
+
+    @ApiModelProperty(value = "是否显示(0:隐藏, 1:显示)", required = true)
+    private Integer isDisplay;
+
+    @ApiModelProperty(value = "最长预订时间(分钟)", required = true)
+    private Integer maxBookingTime;
+
+    @ApiModelProperty(value = "排序")
+    private Integer sort;
+}

+ 24 - 0
alien-entity/src/main/java/shop/alien/entity/store/dto/StoreBookingCategorySortDTO.java

@@ -0,0 +1,24 @@
+package shop.alien.entity.store.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 预订服务分类排序DTO
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@ApiModel(value = "StoreBookingCategorySortDTO", description = "预订服务分类排序DTO")
+public class StoreBookingCategorySortDTO {
+
+    @ApiModelProperty(value = "门店ID", required = true)
+    private Integer storeId;
+
+    @ApiModelProperty(value = "分类ID列表(按顺序排列)", required = true)
+    private List<Integer> categoryIds;
+}

+ 13 - 0
alien-entity/src/main/java/shop/alien/mapper/StoreBookingCategoryMapper.java

@@ -0,0 +1,13 @@
+package shop.alien.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import shop.alien.entity.store.StoreBookingCategory;
+
+/**
+ * 预订服务分类表 Mapper 接口
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+public interface StoreBookingCategoryMapper extends BaseMapper<StoreBookingCategory> {
+}

+ 27 - 0
alien-entity/src/main/resources/mapper/StoreBookingCategoryMapper.xml

@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="shop.alien.mapper.StoreBookingCategoryMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="shop.alien.entity.store.StoreBookingCategory">
+        <id column="id" property="id" />
+        <result column="store_id" property="storeId" />
+        <result column="category_name" property="categoryName" />
+        <result column="floor_plan_images" property="floorPlanImages" />
+        <result column="is_display" property="isDisplay" />
+        <result column="max_booking_time" property="maxBookingTime" />
+        <result column="sort" property="sort" />
+        <result column="delete_flag" property="deleteFlag" />
+        <result column="created_time" property="createdTime" />
+        <result column="created_user_id" property="createdUserId" />
+        <result column="updated_time" property="updatedTime" />
+        <result column="updated_user_id" property="updatedUserId" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, store_id, category_name, floor_plan_images, is_display, max_booking_time, sort, 
+        delete_flag, created_time, created_user_id, updated_time, updated_user_id
+    </sql>
+
+</mapper>

+ 187 - 0
alien-store/src/main/java/shop/alien/store/controller/StoreBookingCategoryController.java

@@ -0,0 +1,187 @@
+package shop.alien.store.controller;
+
+import io.swagger.annotations.*;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.*;
+import shop.alien.entity.result.R;
+import shop.alien.entity.store.StoreBookingCategory;
+import shop.alien.entity.store.dto.StoreBookingCategoryDTO;
+import shop.alien.entity.store.dto.StoreBookingCategorySortDTO;
+import shop.alien.store.service.StoreBookingCategoryService;
+
+import java.util.List;
+
+/**
+ * 预订服务分类管理 前端控制器
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Slf4j
+@Api(tags = {"预订服务-分类管理"})
+@ApiSort(15)
+@CrossOrigin
+@RestController
+@RequestMapping("/store/booking/category")
+@RequiredArgsConstructor
+public class StoreBookingCategoryController {
+
+    private final StoreBookingCategoryService storeBookingCategoryService;
+
+    @ApiOperationSupport(order = 1)
+    @ApiOperation("查询预订服务分类列表")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "storeId", value = "门店ID", dataType = "Integer", paramType = "query", required = true)
+    })
+    @GetMapping("/list")
+    public R<List<StoreBookingCategory>> getCategoryList(@RequestParam Integer storeId) {
+        log.info("StoreBookingCategoryController.getCategoryList?storeId={}", storeId);
+        
+        if (storeId == null) {
+            return R.fail("门店ID不能为空");
+        }
+        
+        try {
+            List<StoreBookingCategory> list = storeBookingCategoryService.getCategoryList(storeId);
+            return R.data(list);
+        } catch (Exception e) {
+            log.error("查询预订服务分类列表失败", e);
+            return R.fail("查询失败:" + e.getMessage());
+        }
+    }
+
+    @ApiOperationSupport(order = 2)
+    @ApiOperation("新增预订服务分类")
+    @PostMapping("/add")
+    public R<StoreBookingCategory> addCategory(@RequestBody StoreBookingCategoryDTO dto) {
+        log.info("StoreBookingCategoryController.addCategory?dto={}", dto);
+        
+        // 参数验证
+        if (dto.getStoreId() == null) {
+            return R.fail("门店ID不能为空");
+        }
+        if (!StringUtils.hasText(dto.getCategoryName())) {
+            return R.fail("分类名称不能为空");
+        }
+        if (!StringUtils.hasText(dto.getFloorPlanImages())) {
+            return R.fail("平面图不能为空");
+        }
+        if (dto.getMaxBookingTime() == null || dto.getMaxBookingTime() <= 0) {
+            return R.fail("最长预订时间必须大于0");
+        }
+        
+        try {
+            StoreBookingCategory category = new StoreBookingCategory();
+            category.setStoreId(dto.getStoreId());
+            category.setCategoryName(dto.getCategoryName());
+            category.setFloorPlanImages(dto.getFloorPlanImages());
+            category.setIsDisplay(dto.getIsDisplay() != null ? dto.getIsDisplay() : 1); // 默认显示
+            category.setMaxBookingTime(dto.getMaxBookingTime());
+            category.setSort(dto.getSort());
+            
+            boolean result = storeBookingCategoryService.addCategory(category);
+            if (result) {
+                // 返回保存后的完整对象
+                StoreBookingCategory savedCategory = storeBookingCategoryService.getById(category.getId());
+                return R.data(savedCategory, "新增成功");
+            } else {
+                return R.fail("新增失败");
+            }
+        } catch (Exception e) {
+            log.error("新增预订服务分类失败", e);
+            return R.fail("新增失败:" + e.getMessage());
+        }
+    }
+
+    @ApiOperationSupport(order = 3)
+    @ApiOperation("编辑预订服务分类")
+    @PostMapping("/update")
+    public R<String> updateCategory(@RequestBody StoreBookingCategoryDTO dto) {
+        log.info("StoreBookingCategoryController.updateCategory?dto={}", dto);
+        
+        if (dto.getId() == null) {
+            return R.fail("分类ID不能为空");
+        }
+        
+        try {
+            StoreBookingCategory category = new StoreBookingCategory();
+            category.setId(dto.getId());
+            if (StringUtils.hasText(dto.getCategoryName())) {
+                category.setCategoryName(dto.getCategoryName());
+            }
+            if (StringUtils.hasText(dto.getFloorPlanImages())) {
+                category.setFloorPlanImages(dto.getFloorPlanImages());
+            }
+            if (dto.getIsDisplay() != null) {
+                category.setIsDisplay(dto.getIsDisplay());
+            }
+            if (dto.getMaxBookingTime() != null) {
+                category.setMaxBookingTime(dto.getMaxBookingTime());
+            }
+            if (dto.getSort() != null) {
+                category.setSort(dto.getSort());
+            }
+            
+            boolean result = storeBookingCategoryService.updateCategory(category);
+            if (result) {
+                return R.success("更新成功");
+            } else {
+                return R.fail("更新失败");
+            }
+        } catch (Exception e) {
+            log.error("更新预订服务分类失败", e);
+            return R.fail("更新失败:" + e.getMessage());
+        }
+    }
+
+    @ApiOperationSupport(order = 4)
+    @ApiOperation("删除预订服务分类")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "分类ID", dataType = "Integer", paramType = "query", required = true)
+    })
+    @PostMapping("/delete")
+    public R<String> deleteCategory(@RequestParam Integer id) {
+        log.info("StoreBookingCategoryController.deleteCategory?id={}", id);
+        
+        if (id == null) {
+            return R.fail("分类ID不能为空");
+        }
+        
+        try {
+            boolean result = storeBookingCategoryService.deleteCategory(id);
+            if (result) {
+                return R.success("删除成功");
+            } else {
+                return R.fail("删除失败");
+            }
+        } catch (Exception e) {
+            log.error("删除预订服务分类失败", e);
+            return R.fail("删除失败:" + e.getMessage());
+        }
+    }
+
+    @ApiOperationSupport(order = 5)
+    @ApiOperation("更新预订服务分类排序")
+    @PostMapping("/updateSort")
+    public R<String> updateCategorySort(@RequestBody StoreBookingCategorySortDTO dto) {
+        log.info("StoreBookingCategoryController.updateCategorySort?dto={}", dto);
+        
+        if (dto.getStoreId() == null || dto.getCategoryIds() == null || dto.getCategoryIds().isEmpty()) {
+            return R.fail("门店ID和分类ID列表不能为空");
+        }
+        
+        try {
+            boolean result = storeBookingCategoryService.updateCategorySort(dto.getStoreId(), dto.getCategoryIds());
+            if (result) {
+                return R.success("更新排序成功");
+            } else {
+                return R.fail("更新排序失败");
+            }
+        } catch (Exception e) {
+            log.error("更新预订服务分类排序失败", e);
+            return R.fail("更新排序失败:" + e.getMessage());
+        }
+    }
+}

+ 56 - 0
alien-store/src/main/java/shop/alien/store/service/StoreBookingCategoryService.java

@@ -0,0 +1,56 @@
+package shop.alien.store.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import shop.alien.entity.store.StoreBookingCategory;
+
+import java.util.List;
+
+/**
+ * 预订服务分类表 服务类
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+public interface StoreBookingCategoryService extends IService<StoreBookingCategory> {
+
+    /**
+     * 查询预订服务分类列表(按排序字段排序)
+     *
+     * @param storeId 门店ID
+     * @return List<StoreBookingCategory>
+     */
+    List<StoreBookingCategory> getCategoryList(Integer storeId);
+
+    /**
+     * 新增预订服务分类
+     *
+     * @param category 分类对象
+     * @return boolean
+     */
+    boolean addCategory(StoreBookingCategory category);
+
+    /**
+     * 更新预订服务分类
+     *
+     * @param category 分类对象
+     * @return boolean
+     */
+    boolean updateCategory(StoreBookingCategory category);
+
+    /**
+     * 删除预订服务分类
+     *
+     * @param id 分类ID
+     * @return boolean
+     */
+    boolean deleteCategory(Integer id);
+
+    /**
+     * 更新预订服务分类排序
+     *
+     * @param storeId     门店ID
+     * @param categoryIds 分类ID列表(按顺序排列)
+     * @return boolean
+     */
+    boolean updateCategorySort(Integer storeId, List<Integer> categoryIds);
+}

+ 246 - 0
alien-store/src/main/java/shop/alien/store/service/impl/StoreBookingCategoryServiceImpl.java

@@ -0,0 +1,246 @@
+package shop.alien.store.service.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.StringUtils;
+import shop.alien.entity.store.StoreBookingCategory;
+import shop.alien.mapper.StoreBookingCategoryMapper;
+import shop.alien.store.service.StoreBookingCategoryService;
+import shop.alien.util.common.JwtUtil;
+
+import java.util.List;
+
+/**
+ * 预订服务分类表 服务实现类
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Slf4j
+@Service
+@Transactional
+@RequiredArgsConstructor
+public class StoreBookingCategoryServiceImpl extends ServiceImpl<StoreBookingCategoryMapper, StoreBookingCategory> implements StoreBookingCategoryService {
+
+    @Override
+    public List<StoreBookingCategory> getCategoryList(Integer storeId) {
+        log.info("StoreBookingCategoryServiceImpl.getCategoryList?storeId={}", storeId);
+        
+        LambdaQueryWrapper<StoreBookingCategory> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(StoreBookingCategory::getStoreId, storeId)
+                .orderByAsc(StoreBookingCategory::getSort) // 按排序字段升序
+                .orderByDesc(StoreBookingCategory::getCreatedTime); // 如果排序字段相同,按创建时间倒序
+        
+        return this.list(wrapper);
+    }
+
+    @Override
+    public boolean addCategory(StoreBookingCategory category) {
+        log.info("StoreBookingCategoryServiceImpl.addCategory?category={}", category);
+        
+        // 从JWT获取当前登录用户ID
+        Integer userId = getCurrentUserId();
+        
+        // 参数验证
+        if (category.getStoreId() == null) {
+            log.warn("新增预订服务分类失败:门店ID不能为空");
+            throw new RuntimeException("门店ID不能为空");
+        }
+        if (!StringUtils.hasText(category.getCategoryName())) {
+            log.warn("新增预订服务分类失败:分类名称不能为空");
+            throw new RuntimeException("分类名称不能为空");
+        }
+        if (!StringUtils.hasText(category.getFloorPlanImages())) {
+            log.warn("新增预订服务分类失败:平面图不能为空");
+            throw new RuntimeException("平面图不能为空");
+        }
+        if (category.getMaxBookingTime() == null || category.getMaxBookingTime() <= 0) {
+            log.warn("新增预订服务分类失败:最长预订时间必须大于0");
+            throw new RuntimeException("最长预订时间必须大于0");
+        }
+        
+        // 验证图片数量(最多9张)
+        String[] images = category.getFloorPlanImages().split(",");
+        if (images.length > 9) {
+            log.warn("新增预订服务分类失败:平面图最多9张");
+            throw new RuntimeException("平面图最多9张");
+        }
+        
+        // 检查分类名称是否已存在
+        LambdaQueryWrapper<StoreBookingCategory> checkWrapper = new LambdaQueryWrapper<>();
+        checkWrapper.eq(StoreBookingCategory::getStoreId, category.getStoreId())
+                .eq(StoreBookingCategory::getCategoryName, category.getCategoryName());
+        StoreBookingCategory existingCategory = this.getOne(checkWrapper);
+        if (existingCategory != null) {
+            log.warn("新增预订服务分类失败:分类名称已存在,categoryName={}", category.getCategoryName());
+            throw new RuntimeException("分类名称已存在:" + category.getCategoryName());
+        }
+        
+        // 查询当前最大的排序值
+        LambdaQueryWrapper<StoreBookingCategory> maxSortWrapper = new LambdaQueryWrapper<>();
+        maxSortWrapper.eq(StoreBookingCategory::getStoreId, category.getStoreId())
+                .orderByDesc(StoreBookingCategory::getSort)
+                .last("LIMIT 1");
+        StoreBookingCategory maxSortCategory = this.getOne(maxSortWrapper);
+        int maxSort = (maxSortCategory != null && maxSortCategory.getSort() != null) ? maxSortCategory.getSort() : 0;
+        
+        // 设置默认值
+        if (category.getIsDisplay() == null) {
+            category.setIsDisplay(1); // 默认显示
+        }
+        if (category.getSort() == null) {
+            category.setSort(maxSort + 1); // 设置排序值
+        }
+        category.setCreatedUserId(userId);
+        
+        return this.save(category);
+    }
+
+    @Override
+    public boolean updateCategory(StoreBookingCategory category) {
+        log.info("StoreBookingCategoryServiceImpl.updateCategory?category={}", category);
+        
+        // 从JWT获取当前登录用户ID
+        Integer userId = getCurrentUserId();
+        
+        // 参数验证
+        if (category.getId() == null) {
+            log.warn("更新预订服务分类失败:分类ID不能为空");
+            throw new RuntimeException("分类ID不能为空");
+        }
+        
+        StoreBookingCategory existingCategory = this.getById(category.getId());
+        if (existingCategory == null) {
+            log.warn("更新预订服务分类失败:分类不存在,id={}", category.getId());
+            throw new RuntimeException("分类不存在");
+        }
+        
+        // 如果修改了分类名称,检查新分类名称是否已存在
+        if (StringUtils.hasText(category.getCategoryName()) && 
+            !category.getCategoryName().equals(existingCategory.getCategoryName())) {
+            LambdaQueryWrapper<StoreBookingCategory> wrapper = new LambdaQueryWrapper<>();
+            wrapper.eq(StoreBookingCategory::getStoreId, existingCategory.getStoreId())
+                    .eq(StoreBookingCategory::getCategoryName, category.getCategoryName())
+                    .ne(StoreBookingCategory::getId, category.getId());
+            StoreBookingCategory duplicateCategory = this.getOne(wrapper);
+            if (duplicateCategory != null) {
+                log.warn("更新预订服务分类失败:分类名称已存在,categoryName={}", category.getCategoryName());
+                throw new RuntimeException("分类名称已存在:" + category.getCategoryName());
+            }
+        }
+        
+        // 验证图片数量(最多9张)
+        if (StringUtils.hasText(category.getFloorPlanImages())) {
+            String[] images = category.getFloorPlanImages().split(",");
+            if (images.length > 9) {
+                log.warn("更新预订服务分类失败:平面图最多9张");
+                throw new RuntimeException("平面图最多9张");
+            }
+        }
+        
+        // 验证最长预订时间
+        if (category.getMaxBookingTime() != null && category.getMaxBookingTime() <= 0) {
+            log.warn("更新预订服务分类失败:最长预订时间必须大于0");
+            throw new RuntimeException("最长预订时间必须大于0");
+        }
+        
+        // 更新字段
+        LambdaUpdateWrapper<StoreBookingCategory> updateWrapper = new LambdaUpdateWrapper<>();
+        updateWrapper.eq(StoreBookingCategory::getId, category.getId());
+        
+        if (StringUtils.hasText(category.getCategoryName())) {
+            updateWrapper.set(StoreBookingCategory::getCategoryName, category.getCategoryName());
+        }
+        if (StringUtils.hasText(category.getFloorPlanImages())) {
+            updateWrapper.set(StoreBookingCategory::getFloorPlanImages, category.getFloorPlanImages());
+        }
+        if (category.getIsDisplay() != null) {
+            updateWrapper.set(StoreBookingCategory::getIsDisplay, category.getIsDisplay());
+        }
+        if (category.getMaxBookingTime() != null) {
+            updateWrapper.set(StoreBookingCategory::getMaxBookingTime, category.getMaxBookingTime());
+        }
+        if (category.getSort() != null) {
+            updateWrapper.set(StoreBookingCategory::getSort, category.getSort());
+        }
+        
+        if (userId != null) {
+            updateWrapper.set(StoreBookingCategory::getUpdatedUserId, userId);
+        }
+        
+        return this.update(updateWrapper);
+    }
+
+    @Override
+    public boolean deleteCategory(Integer id) {
+        log.info("StoreBookingCategoryServiceImpl.deleteCategory?id={}", id);
+        
+        StoreBookingCategory category = this.getById(id);
+        if (category == null) {
+            log.warn("删除预订服务分类失败:分类不存在,id={}", id);
+            throw new RuntimeException("分类不存在");
+        }
+        
+        // 逻辑删除
+        return this.removeById(id);
+    }
+
+    @Override
+    public boolean updateCategorySort(Integer storeId, List<Integer> categoryIds) {
+        log.info("StoreBookingCategoryServiceImpl.updateCategorySort?storeId={}&categoryIds={}", storeId, categoryIds);
+        
+        if (storeId == null || categoryIds == null || categoryIds.isEmpty()) {
+            log.warn("更新预订服务分类排序失败:参数不完整");
+            throw new RuntimeException("参数不完整");
+        }
+        
+        // 验证所有分类ID是否属于该门店
+        LambdaQueryWrapper<StoreBookingCategory> checkWrapper = new LambdaQueryWrapper<>();
+        checkWrapper.eq(StoreBookingCategory::getStoreId, storeId)
+                .in(StoreBookingCategory::getId, categoryIds);
+        long count = this.count(checkWrapper);
+        if (count != categoryIds.size()) {
+            log.warn("更新预订服务分类排序失败:部分分类ID不属于该门店");
+            throw new RuntimeException("部分分类ID不属于该门店");
+        }
+        
+        // 从JWT获取当前登录用户ID
+        Integer userId = getCurrentUserId();
+        
+        // 批量更新排序值
+        for (int i = 0; i < categoryIds.size(); i++) {
+            LambdaUpdateWrapper<StoreBookingCategory> updateWrapper = new LambdaUpdateWrapper<>();
+            updateWrapper.eq(StoreBookingCategory::getId, categoryIds.get(i))
+                    .set(StoreBookingCategory::getSort, i + 1);
+            if (userId != null) {
+                updateWrapper.set(StoreBookingCategory::getUpdatedUserId, userId);
+            }
+            this.update(updateWrapper);
+        }
+        
+        return true;
+    }
+
+    /**
+     * 从JWT获取当前登录用户ID
+     *
+     * @return 用户ID,如果未登录返回null
+     */
+    private Integer getCurrentUserId() {
+        try {
+            JSONObject userInfo = JwtUtil.getCurrentUserInfo();
+            if (userInfo != null) {
+                return userInfo.getInteger("userId");
+            }
+        } catch (Exception e) {
+            log.warn("获取当前登录用户ID失败: {}", e.getMessage());
+        }
+        return null;
+    }
+}