ソースを参照

加入新增演出信息接口

zhangchen 3 ヶ月 前
コミット
5d5c616751

+ 11 - 0
alien-entity/src/main/java/shop/alien/entity/store/BarPerformance.java

@@ -8,6 +8,7 @@ import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
 import java.io.Serializable;
+import java.time.LocalTime;
 import java.util.Date;
 
 /**
@@ -139,4 +140,14 @@ public class BarPerformance implements Serializable {
     @TableField(value = "updated_time", fill = FieldFill.UPDATE)
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
     private Date updatedTime;
+
+    @ApiModelProperty(value = "演出开始时间")
+    @TableField(value = "daily_start_time")
+    @JsonFormat(pattern = "HH:mm:ss", timezone = "GMT+8")
+    private LocalTime dailyStartTime;
+
+    @ApiModelProperty(value = "演出结束时间")
+    @TableField(value = "daily_end_time")
+    @JsonFormat(pattern = "HH:mm:ss", timezone = "GMT+8")
+    private LocalTime dailyEndTime;
 }

+ 4 - 0
alien-entity/src/main/java/shop/alien/entity/store/StoreStaffConfig.java

@@ -156,4 +156,8 @@ public class StoreStaffConfig extends Model<StoreStaffConfig> {
     @ApiModelProperty(value = "今日是否有演出(true-有演出,false-无演出)")
     @TableField(exist = false)
     private Boolean hasPerformanceToday;
+
+    @ApiModelProperty(value = "好评数量")
+    @TableField(exist = false)
+    private Integer positiveCommentsCount;
 }

+ 79 - 0
alien-entity/src/main/java/shop/alien/entity/store/vo/PerformanceDetailVo.java

@@ -0,0 +1,79 @@
+package shop.alien.entity.store.vo;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 演出详情VO
+ * 用于展示演出详细信息
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@ApiModel(value = "PerformanceDetailVo对象", description = "演出详情")
+public class PerformanceDetailVo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 演出ID
+     */
+    @ApiModelProperty(value = "演出ID")
+    private Integer id;
+
+    /**
+     * 演出名称
+     */
+    @ApiModelProperty(value = "演出名称")
+    private String performanceName;
+
+    /**
+     * 演出海报路径
+     */
+    @ApiModelProperty(value = "演出海报路径")
+    private String performancePoster;
+
+    /**
+     * 演出时间(格式:2025.11.11-2027.01.31每周一、四19:30-次日00:00)
+     */
+    @ApiModelProperty(value = "演出时间(格式:2025.11.11-2027.01.31每周一、四19:30-次日00:00)")
+    private String performanceTime;
+
+    /**
+     * 演出风格(格式:流行、民谣)
+     */
+    @ApiModelProperty(value = "演出风格(格式:流行、民谣)")
+    private String performanceStyle;
+
+    /**
+     * 演出详情描述
+     */
+    @ApiModelProperty(value = "演出详情描述")
+    private String performanceContent;
+
+    /**
+     * 演出嘉宾列表
+     */
+    @ApiModelProperty(value = "演出嘉宾列表")
+    private List<PerformanceGuestVo> guestList;
+
+    /**
+     * 演出人员数量
+     */
+    @ApiModelProperty(value = "演出人员数量")
+    private Integer guestCount;
+
+    /**
+     * 演出类型(0-特邀演出,1-常规演出)
+     */
+    @ApiModelProperty(value = "演出类型(0-特邀演出,1-常规演出)")
+    private Integer performanceType;
+}
+

+ 49 - 0
alien-entity/src/main/java/shop/alien/entity/store/vo/PerformanceGroupByDateVo.java

@@ -0,0 +1,49 @@
+package shop.alien.entity.store.vo;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 按日期分组的演出列表VO
+ * 用于展示按日期分组的演出列表,每个日期组包含该日期下的所有演出
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@ApiModel(value = "PerformanceGroupByDateVo对象", description = "按日期分组的演出列表")
+public class PerformanceGroupByDateVo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 日期标题(格式:12-08 今天 或 12-12 周五)
+     */
+    @ApiModelProperty(value = "日期标题(格式:12-08 今天 或 12-12 周五)")
+    private String dateTitle;
+
+    /**
+     * 日期(格式:yyyy-MM-dd)
+     */
+    @ApiModelProperty(value = "日期(格式:yyyy-MM-dd)")
+    private String date;
+
+    /**
+     * 是否为今天
+     */
+    @ApiModelProperty(value = "是否为今天")
+    private Boolean isToday;
+
+    /**
+     * 该日期下的演出列表
+     */
+    @ApiModelProperty(value = "该日期下的演出列表")
+    private List<PerformanceListVo> performanceList;
+}
+

+ 37 - 0
alien-entity/src/main/java/shop/alien/entity/store/vo/PerformanceGroupListVo.java

@@ -0,0 +1,37 @@
+package shop.alien.entity.store.vo;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 按日期分组的演出列表返回VO
+ * 包含所有日期分组和演出列表
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@ApiModel(value = "PerformanceGroupListVo对象", description = "按日期分组的演出列表")
+public class PerformanceGroupListVo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 按日期分组的演出列表
+     */
+    @ApiModelProperty(value = "按日期分组的演出列表")
+    private List<PerformanceGroupByDateVo> groupList;
+
+    /**
+     * 总记录数
+     */
+    @ApiModelProperty(value = "总记录数")
+    private Long total;
+}
+

+ 60 - 0
alien-entity/src/main/java/shop/alien/entity/store/vo/PerformanceGuestVo.java

@@ -0,0 +1,60 @@
+package shop.alien.entity.store.vo;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 演出嘉宾VO
+ * 用于展示演出嘉宾信息
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@ApiModel(value = "PerformanceGuestVo对象", description = "演出嘉宾")
+public class PerformanceGuestVo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 员工ID
+     */
+    @ApiModelProperty(value = "员工ID")
+    private Integer staffId;
+
+    /**
+     * 员工姓名
+     */
+    @ApiModelProperty(value = "员工姓名")
+    private String name;
+
+    /**
+     * 员工头像
+     */
+    @ApiModelProperty(value = "员工头像")
+    private String staffImage;
+
+    /**
+     * 员工职位/角色(如:贝斯)
+     */
+    @ApiModelProperty(value = "员工职位/角色(如:贝斯)")
+    private String staffPosition;
+
+    /**
+     * 擅长项目/风格(如:民谣)
+     */
+    @ApiModelProperty(value = "擅长项目/风格(如:民谣)")
+    private String proficientProjects;
+
+    /**
+     * 点赞数量
+     */
+    @ApiModelProperty(value = "点赞数量")
+    private Integer likeCount;
+}
+

+ 66 - 0
alien-entity/src/main/java/shop/alien/entity/store/vo/PerformanceListVo.java

@@ -0,0 +1,66 @@
+package shop.alien.entity.store.vo;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 演出列表VO
+ * 用于展示演出列表信息
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@ApiModel(value = "PerformanceListVo对象", description = "演出列表")
+public class PerformanceListVo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 演出ID
+     */
+    @ApiModelProperty(value = "演出ID")
+    private Integer id;
+
+    /**
+     * 演出名称
+     */
+    @ApiModelProperty(value = "演出名称")
+    private String performanceName;
+
+    /**
+     * 演出海报路径
+     */
+    @ApiModelProperty(value = "演出海报路径")
+    private String performancePoster;
+
+    /**
+     * 演出者信息(如:刘能等7人)
+     */
+    @ApiModelProperty(value = "演出者信息(如:刘能等7人)")
+    private String performersInfo;
+
+    /**
+     * 日期范围(格式:2025.11.11-2027.01.31)
+     */
+    @ApiModelProperty(value = "日期范围(格式:2025.11.11-2027.01.31)")
+    private String dateRange;
+
+    /**
+     * 演出时间安排(格式:每周一、二、三、四19:30-次日00:00)
+     */
+    @ApiModelProperty(value = "演出时间安排(格式:每周一、二、三、四19:30-次日00:00)")
+    private String scheduleInfo;
+
+    /**
+     * 演出类型(0-特邀演出,1-常规演出)
+     */
+    @ApiModelProperty(value = "演出类型(0-特邀演出,1-常规演出)")
+    private Integer performanceType;
+}
+

+ 197 - 0
alien-store/src/main/java/shop/alien/store/controller/PerformanceListController.java

@@ -0,0 +1,197 @@
+package shop.alien.store.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import io.swagger.annotations.*;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+import shop.alien.entity.result.R;
+import shop.alien.entity.store.vo.PerformanceDetailVo;
+import shop.alien.entity.store.vo.PerformanceGroupListVo;
+import shop.alien.entity.store.vo.PerformanceListVo;
+import shop.alien.store.service.PerformanceListService;
+import shop.alien.store.util.CommonConstant;
+
+/**
+ * 演出列表Controller(用户端)
+ * 提供用户端演出列表查询接口
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Slf4j
+@Api(tags = {"用户端-演出"})
+@CrossOrigin
+@RestController
+@RequestMapping("/performance/list")
+@RequiredArgsConstructor
+public class PerformanceListController {
+
+    private final PerformanceListService performanceListService;
+
+    /**
+     * 查询演出列表(用户端)
+     * <p>
+     * 根据店铺ID查询演出列表,支持分页
+     * 只返回审核通过、已上线、未删除的演出
+     * 返回结果包含演出名称、演出者信息、日期范围、演出时间安排等
+     * </p>
+     *
+     * @param page    分页页数,默认1,必须大于0
+     * @param size    分页条数,默认10,必须大于0且不超过100
+     * @param storeId 店铺ID,必填,必须大于0
+     * @return 演出列表分页结果
+     */
+    @ApiOperation("查询演出列表(用户端)")
+    @ApiOperationSupport(order = 1)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "page", value = "分页页数", dataType = "Integer", paramType = "query", required = false),
+            @ApiImplicitParam(name = "size", value = "分页条数", dataType = "Integer", paramType = "query", required = false),
+            @ApiImplicitParam(name = "storeId", value = "店铺ID", dataType = "Integer", paramType = "query", required = true)
+    })
+    @GetMapping("/query")
+    public R<IPage<PerformanceListVo>> queryPerformanceList(
+            @RequestParam(value = "page", defaultValue = "1") Integer page,
+            @RequestParam(value = "size", defaultValue = "10") Integer size,
+            @RequestParam(value = "storeId") Integer storeId) {
+        log.info("查询演出列表,参数:page={}, size={}, storeId={}", page, size, storeId);
+
+        try {
+            // 参数校验
+            if (storeId == null || storeId <= 0) {
+                log.warn("查询演出列表参数校验失败,店铺ID无效:storeId={}", storeId);
+                return R.fail("店铺ID不能为空且必须大于0");
+            }
+            if (page != null && page < 1) {
+                log.warn("查询演出列表参数校验失败,分页页数无效:page={}", page);
+                return R.fail("分页页数必须大于0");
+            }
+            if (size != null && size < 1) {
+                log.warn("查询演出列表参数校验失败,分页条数无效:size={}", size);
+                return R.fail("分页条数必须大于0");
+            }
+            if (size != null && size > CommonConstant.MAX_PAGE_SIZE) {
+                log.warn("查询演出列表参数校验失败,分页条数超过最大值:size={}", size);
+                return R.fail("分页条数不能超过" + CommonConstant.MAX_PAGE_SIZE);
+            }
+
+            // 规范化分页参数
+            Integer normalizedPage = (page == null || page < 1) ? CommonConstant.DEFAULT_PAGE_NUM : page;
+            Integer normalizedSize;
+            if (size == null || size < 1) {
+                normalizedSize = CommonConstant.DEFAULT_PAGE_SIZE;
+            } else if (size > CommonConstant.MAX_PAGE_SIZE) {
+                normalizedSize = CommonConstant.MAX_PAGE_SIZE;
+            } else {
+                normalizedSize = size;
+            }
+
+            // 调用服务层查询
+            IPage<PerformanceListVo> result = performanceListService.queryPerformanceList(
+                    normalizedPage, normalizedSize, storeId);
+
+            log.info("查询演出列表成功,店铺ID={},共{}条记录,当前页{}条",
+                    storeId, result.getTotal(), result.getRecords() != null ? result.getRecords().size() : 0);
+            return R.data(result);
+        } catch (IllegalArgumentException e) {
+            log.warn("查询演出列表参数错误,storeId={},错误信息:{}", storeId, e.getMessage());
+            return R.fail(e.getMessage());
+        } catch (Exception e) {
+            log.error("查询演出列表异常,storeId={},异常信息:{}", storeId, e.getMessage(), e);
+            return R.fail("查询演出列表失败,请稍后重试");
+        }
+    }
+
+    /**
+     * 查询按日期分组的演出列表(用户端)
+     * <p>
+     * 根据店铺ID查询演出列表,按日期分组返回
+     * 只返回审核通过、已上线、未删除的演出
+     * 返回未来30天内有演出的日期及其对应的演出列表
+     * 日期标题格式:MM-dd 今天 或 MM-dd 星期几
+     * </p>
+     *
+     * @param storeId 店铺ID,必填,必须大于0
+     * @return 按日期分组的演出列表
+     */
+    @ApiOperation("查询按日期分组的演出列表(用户端)")
+    @ApiOperationSupport(order = 2)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "storeId", value = "店铺ID", dataType = "Integer", paramType = "query", required = true)
+    })
+    @GetMapping("/queryGroupByDate")
+    public R<PerformanceGroupListVo> queryPerformanceListGroupByDate(
+            @RequestParam(value = "storeId") Integer storeId) {
+        log.info("查询按日期分组的演出列表,参数:storeId={}", storeId);
+
+        try {
+            // 参数校验
+            if (storeId == null || storeId <= 0) {
+                log.warn("查询按日期分组的演出列表参数校验失败,店铺ID无效:storeId={}", storeId);
+                return R.fail("店铺ID不能为空且必须大于0");
+            }
+
+            // 调用服务层查询
+            PerformanceGroupListVo result = performanceListService.queryPerformanceListGroupByDate(storeId);
+
+            log.info("查询按日期分组的演出列表成功,店铺ID={},共{}个日期组,{}条演出记录",
+                    storeId, result.getGroupList() != null ? result.getGroupList().size() : 0, result.getTotal());
+            return R.data(result);
+        } catch (IllegalArgumentException e) {
+            log.warn("查询按日期分组的演出列表参数错误,storeId={},错误信息:{}", storeId, e.getMessage());
+            return R.fail(e.getMessage());
+        } catch (Exception e) {
+            log.error("查询按日期分组的演出列表异常,storeId={},异常信息:{}", storeId, e.getMessage(), e);
+            return R.fail("查询按日期分组的演出列表失败,请稍后重试");
+        }
+    }
+
+    /**
+     * 查询演出详情(用户端)
+     * <p>
+     * 根据演出ID查询演出详细信息
+     * 包含演出基本信息、演出时间、演出风格、演出详情描述和演出嘉宾列表
+     * 只返回审核通过、已上线、未删除的演出
+     * </p>
+     *
+     * @param id 演出ID,必填,必须大于0
+     * @return 演出详情
+     */
+    @ApiOperation("查询演出详情(用户端)")
+    @ApiOperationSupport(order = 3)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "演出ID", dataType = "Integer", paramType = "query", required = true)
+    })
+    @GetMapping("/detail")
+    public R<PerformanceDetailVo> queryPerformanceDetail(
+            @RequestParam(value = "id") Integer id) {
+        log.info("查询演出详情,参数:id={}", id);
+
+        try {
+            // 参数校验
+            if (id == null || id <= 0) {
+                log.warn("查询演出详情参数校验失败,演出ID无效:id={}", id);
+                return R.fail("演出ID不能为空且必须大于0");
+            }
+
+            // 调用服务层查询
+            PerformanceDetailVo result = performanceListService.queryPerformanceDetail(id);
+
+            if (result == null) {
+                log.warn("查询演出详情失败,演出不存在或状态不符合要求:id={}", id);
+                return R.fail("演出不存在或已下线");
+            }
+
+            log.info("查询演出详情成功,id={},嘉宾数量:{}", id,
+                    result.getGuestList() != null ? result.getGuestList().size() : 0);
+            return R.data(result);
+        } catch (IllegalArgumentException e) {
+            log.warn("查询演出详情参数错误,id={},错误信息:{}", id, e.getMessage());
+            return R.fail(e.getMessage());
+        } catch (Exception e) {
+            log.error("查询演出详情异常,id={},异常信息:{}", id, e.getMessage(), e);
+            return R.fail("查询演出详情失败,请稍后重试");
+        }
+    }
+}
+

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

@@ -0,0 +1,56 @@
+package shop.alien.store.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import shop.alien.entity.store.vo.PerformanceDetailVo;
+import shop.alien.entity.store.vo.PerformanceGroupListVo;
+import shop.alien.entity.store.vo.PerformanceListVo;
+
+/**
+ * 演出列表服务接口
+ * 提供用户端演出列表查询功能
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+public interface PerformanceListService {
+
+    /**
+     * 查询演出列表(用户端)
+     * <p>
+     * 根据店铺ID查询演出列表,支持分页
+     * 只返回审核通过、已上线、未删除的演出
+     * </p>
+     *
+     * @param page    分页页数,必须大于0
+     * @param size    分页条数,必须大于0
+     * @param storeId 店铺ID,必须大于0
+     * @return 演出列表分页结果
+     */
+    IPage<PerformanceListVo> queryPerformanceList(Integer page, Integer size, Integer storeId);
+
+    /**
+     * 查询按日期分组的演出列表(用户端)
+     * <p>
+     * 根据店铺ID查询演出列表,按日期分组返回
+     * 只返回审核通过、已上线、未删除的演出
+     * 返回未来30天内有演出的日期及其对应的演出列表
+     * </p>
+     *
+     * @param storeId 店铺ID,必须大于0
+     * @return 按日期分组的演出列表
+     */
+    PerformanceGroupListVo queryPerformanceListGroupByDate(Integer storeId);
+
+    /**
+     * 查询演出详情(用户端)
+     * <p>
+     * 根据演出ID查询演出详细信息
+     * 包含演出基本信息、演出时间、演出风格、演出详情描述和演出嘉宾列表
+     * </p>
+     *
+     * @param id 演出ID,必须大于0
+     * @return 演出详情,如果演出不存在则返回null
+     */
+    PerformanceDetailVo queryPerformanceDetail(Integer id);
+}
+

+ 906 - 0
alien-store/src/main/java/shop/alien/store/service/impl/PerformanceListServiceImpl.java

@@ -0,0 +1,906 @@
+package shop.alien.store.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import shop.alien.entity.store.BarPerformance;
+import shop.alien.entity.store.StoreDictionary;
+import shop.alien.entity.store.StoreStaffConfig;
+import shop.alien.entity.store.vo.PerformanceDetailVo;
+import shop.alien.entity.store.vo.PerformanceGroupByDateVo;
+import shop.alien.entity.store.vo.PerformanceGroupListVo;
+import shop.alien.entity.store.vo.PerformanceGuestVo;
+import shop.alien.entity.store.vo.PerformanceListVo;
+import shop.alien.mapper.BarPerformanceMapper;
+import shop.alien.mapper.StoreDictionaryMapper;
+import shop.alien.mapper.StoreStaffConfigMapper;
+import shop.alien.store.service.PerformanceListService;
+import shop.alien.store.util.CommonConstant;
+
+import java.text.SimpleDateFormat;
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * 演出列表服务实现类
+ * 实现用户端演出列表查询功能
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class PerformanceListServiceImpl implements PerformanceListService {
+
+    private final BarPerformanceMapper barPerformanceMapper;
+    private final StoreStaffConfigMapper storeStaffConfigMapper;
+    private final StoreDictionaryMapper storeDictionaryMapper;
+
+    /**
+     * 日期格式化:yyyy.MM.dd
+     */
+    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy.MM.dd");
+
+    /**
+     * 日期格式化:MM-dd(用于日期标题)
+     */
+    private static final SimpleDateFormat DATE_TITLE_FORMAT = new SimpleDateFormat("MM-dd");
+
+    /**
+     * 日期格式化:yyyy-MM-dd(用于日期字符串)
+     */
+    private static final SimpleDateFormat DATE_STRING_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
+
+    /**
+     * 时间格式化:HH:mm
+     */
+    private static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm");
+
+    /**
+     * LocalTime格式化:HH:mm
+     */
+    private static final DateTimeFormatter LOCAL_TIME_FORMAT = DateTimeFormatter.ofPattern("HH:mm");
+
+    /**
+     * 星期几中文数组
+     * Calendar中:1=周日,2=周一,...,7=周六
+     */
+    private static final String[] WEEK_DAYS = {"周日", "周一", "周二", "周三", "周四", "周五", "周六"};
+
+    @Override
+    public IPage<PerformanceListVo> queryPerformanceList(Integer page, Integer size, Integer storeId) {
+        log.info("查询演出列表,参数:page={}, size={}, storeId={}", page, size, storeId);
+
+        // 参数校验
+        validateQueryParams(page, size, storeId);
+
+        // 构建分页对象
+        IPage<BarPerformance> performancePage = new Page<>(page, size);
+
+        // 构建查询条件
+        LambdaQueryWrapper<BarPerformance> queryWrapper = buildQueryWrapper(storeId);
+
+        // 执行查询
+        IPage<BarPerformance> result = barPerformanceMapper.selectPage(performancePage, queryWrapper);
+
+        // 转换为VO列表
+        List<PerformanceListVo> voList = convertToVoList(result.getRecords());
+
+        // 构建返回结果
+        IPage<PerformanceListVo> voPage = new Page<>(page, size, result.getTotal());
+        voPage.setRecords(voList);
+
+        log.info("查询演出列表成功,店铺ID={},共{}条记录,当前页{}条", 
+                storeId, result.getTotal(), voList.size());
+        return voPage;
+    }
+
+    /**
+     * 校验查询参数
+     *
+     * @param page    分页页数
+     * @param size    分页条数
+     * @param storeId 店铺ID
+     * @throws IllegalArgumentException 当参数无效时抛出
+     */
+    private void validateQueryParams(Integer page, Integer size, Integer storeId) {
+        if (page == null || page < 1) {
+            throw new IllegalArgumentException("分页页数不能为空且必须大于0");
+        }
+        if (size == null || size < 1) {
+            throw new IllegalArgumentException("分页条数不能为空且必须大于0");
+        }
+        if (size > CommonConstant.MAX_PAGE_SIZE) {
+            throw new IllegalArgumentException("分页条数不能超过" + CommonConstant.MAX_PAGE_SIZE);
+        }
+        if (storeId == null || storeId <= 0) {
+            throw new IllegalArgumentException("店铺ID不能为空且必须大于0");
+        }
+    }
+
+    /**
+     * 构建查询条件
+     *
+     * @param storeId 店铺ID
+     * @return 查询条件包装器
+     */
+    private LambdaQueryWrapper<BarPerformance> buildQueryWrapper(Integer storeId) {
+        LambdaQueryWrapper<BarPerformance> queryWrapper = new LambdaQueryWrapper<>();
+
+        // 必须条件:店铺ID、未删除、审核通过、已上线
+        queryWrapper.eq(BarPerformance::getStoreId, storeId)
+                .eq(BarPerformance::getDeleteFlag, CommonConstant.DELETE_FLAG_UNDELETE)
+                .eq(BarPerformance::getReviewStatus, CommonConstant.PERFORMANCE_REVIEW_STATUS_APPROVED)
+                .eq(BarPerformance::getOnlineStatus, CommonConstant.PERFORMANCE_ONLINE_STATUS_ONLINE);
+
+        // 排序规则:按创建时间降序
+        queryWrapper.orderByDesc(BarPerformance::getCreatedTime);
+
+        return queryWrapper;
+    }
+
+    /**
+     * 转换为VO列表
+     *
+     * @param performances 演出列表
+     * @return VO列表
+     */
+    private List<PerformanceListVo> convertToVoList(List<BarPerformance> performances) {
+        if (performances == null || performances.isEmpty()) {
+            return new ArrayList<>();
+        }
+
+        return performances.stream()
+                .map(this::convertToVo)
+                .collect(Collectors.toList());
+    }
+
+    /**
+     * 转换为VO
+     *
+     * @param performance 演出信息
+     * @return VO对象
+     */
+    private PerformanceListVo convertToVo(BarPerformance performance) {
+        PerformanceListVo vo = new PerformanceListVo();
+        vo.setId(performance.getId());
+        vo.setPerformanceName(performance.getPerformanceName());
+        vo.setPerformancePoster(performance.getPerformancePoster());
+        vo.setPerformanceType(performance.getPerformanceType());
+
+        // 设置演出者信息
+        vo.setPerformersInfo(buildPerformersInfo(performance.getStaffConfigIds()));
+
+        // 设置日期范围
+        vo.setDateRange(buildDateRange(performance));
+
+        // 设置演出时间安排
+        vo.setScheduleInfo(buildScheduleInfo(performance));
+
+        return vo;
+    }
+
+    /**
+     * 构建演出者信息
+     * <p>
+     * 从员工ID列表中查询第一个有名字的员工,显示格式:
+     * - 1人:显示员工名字
+     * - 多人:显示"xx等X人"
+     * </p>
+     *
+     * @param staffConfigIds 员工配置ID字符串(逗号分隔)
+     * @return 演出者信息(如:刘能等7人)
+     */
+    private String buildPerformersInfo(String staffConfigIds) {
+        if (StringUtils.isEmpty(staffConfigIds)) {
+            return "";
+        }
+
+        try {
+            String[] ids = staffConfigIds.split(",");
+            List<Integer> staffIdList = new ArrayList<>();
+            
+            // 解析所有有效的员工ID
+            for (String idStr : ids) {
+                if (StringUtils.isNotEmpty(idStr.trim())) {
+                    try {
+                        Integer staffId = Integer.parseInt(idStr.trim());
+                        if (staffId > 0) {
+                            staffIdList.add(staffId);
+                        }
+                    } catch (NumberFormatException e) {
+                        log.warn("解析员工配置ID失败,无效的ID:{}", idStr);
+                    }
+                }
+            }
+
+            if (staffIdList.isEmpty()) {
+                return "";
+            }
+
+            int count = staffIdList.size();
+            String firstName = null;
+
+            // 遍历员工ID列表,找到第一个有名字的员工
+            for (Integer staffId : staffIdList) {
+                try {
+                    StoreStaffConfig staff = storeStaffConfigMapper.selectById(staffId);
+                    if (staff != null && StringUtils.isNotEmpty(staff.getName())) {
+                        firstName = staff.getName();
+                        break; // 找到第一个有名字的员工就退出
+                    }
+                } catch (Exception e) {
+                    log.warn("查询员工信息失败,staffId={},异常信息:{}", staffId, e.getMessage());
+                    // 继续查询下一个员工
+                }
+            }
+
+            // 根据人数和是否找到名字来构建返回信息
+            if (count == 1) {
+                return firstName != null ? firstName : "1人";
+            } else {
+                return firstName != null ? firstName + "等" + count + "人" : count + "人";
+            }
+        } catch (Exception e) {
+            log.error("构建演出者信息异常,staffConfigIds={},异常信息:{}", staffConfigIds, e.getMessage(), e);
+            return "";
+        }
+    }
+
+    /**
+     * 构建日期范围
+     *
+     * @param performance 演出信息
+     * @return 日期范围(格式:2025.11.11-2027.01.31)
+     */
+    private String buildDateRange(BarPerformance performance) {
+        String frequency = performance.getPerformanceFrequency();
+        if (StringUtils.isEmpty(frequency)) {
+            return "";
+        }
+
+        try {
+            switch (frequency) {
+                case CommonConstant.PERFORMANCE_FREQUENCY_SINGLE:
+                    // 单次演出:使用singleStartDatetime和singleEndDatetime
+                    Date singleStart = performance.getSingleStartDatetime();
+                    Date singleEnd = performance.getSingleEndDatetime();
+                    if (singleStart != null && singleEnd != null) {
+                        return DATE_FORMAT.format(singleStart) + "-" + DATE_FORMAT.format(singleEnd);
+                    }
+                    break;
+                case CommonConstant.PERFORMANCE_FREQUENCY_DAILY:
+                case CommonConstant.PERFORMANCE_FREQUENCY_WEEKLY:
+                    // 每天定时或每周定时:使用dailyStartDate和dailyEndDate
+                    Date dailyStart = performance.getDailyStartDate();
+                    Date dailyEnd = performance.getDailyEndDate();
+                    if (dailyStart != null && dailyEnd != null) {
+                        return DATE_FORMAT.format(dailyStart) + "-" + DATE_FORMAT.format(dailyEnd);
+                    }
+                    break;
+                default:
+                    break;
+            }
+        } catch (Exception e) {
+            log.error("构建日期范围异常,performanceId={},异常信息:{}", performance.getId(), e.getMessage(), e);
+        }
+
+        return "";
+    }
+
+    /**
+     * 构建演出时间安排
+     *
+     * @param performance 演出信息
+     * @return 演出时间安排(格式:每周一、二、三、四19:30-次日00:00)
+     */
+    private String buildScheduleInfo(BarPerformance performance) {
+        String frequency = performance.getPerformanceFrequency();
+        if (StringUtils.isEmpty(frequency)) {
+            return "";
+        }
+
+        try {
+            switch (frequency) {
+                case CommonConstant.PERFORMANCE_FREQUENCY_SINGLE:
+                    // 单次演出:显示具体日期和时间
+                    Date singleStart = performance.getSingleStartDatetime();
+                    Date singleEnd = performance.getSingleEndDatetime();
+                    if (singleStart != null && singleEnd != null) {
+                        return buildSingleScheduleInfo(singleStart, singleEnd);
+                    }
+                    break;
+                case CommonConstant.PERFORMANCE_FREQUENCY_DAILY:
+                    // 每天定时:使用dailyStartTime和dailyEndTime
+                    LocalTime dailyStartTime = performance.getDailyStartTime();
+                    LocalTime dailyEndTime = performance.getDailyEndTime();
+                    if (dailyStartTime != null && dailyEndTime != null) {
+                        return "每天" + buildLocalTimeRange(dailyStartTime, dailyEndTime);
+                    }
+                    break;
+                case CommonConstant.PERFORMANCE_FREQUENCY_WEEKLY:
+                    // 每周定时:显示星期几和时间,使用dailyStartTime和dailyEndTime
+                    String performanceWeek = performance.getPerformanceWeek();
+                    LocalTime weeklyStartTime = performance.getDailyStartTime();
+                    LocalTime weeklyEndTime = performance.getDailyEndTime();
+                    if (StringUtils.isNotEmpty(performanceWeek) && weeklyStartTime != null && weeklyEndTime != null) {
+                        return buildWeeklyScheduleInfo(performanceWeek, weeklyStartTime, weeklyEndTime);
+                    }
+                    break;
+                default:
+                    break;
+            }
+        } catch (Exception e) {
+            log.error("构建演出时间安排异常,performanceId={},异常信息:{}", performance.getId(), e.getMessage(), e);
+        }
+
+        return "";
+    }
+
+    /**
+     * 构建单次演出时间安排
+     *
+     * @param startTime 开始时间
+     * @param endTime   结束时间
+     * @return 时间安排字符串
+     */
+    private String buildSingleScheduleInfo(Date startTime, Date endTime) {
+        java.util.Calendar cal = java.util.Calendar.getInstance();
+        cal.setTime(startTime);
+        int dayOfWeek = cal.get(java.util.Calendar.DAY_OF_WEEK);
+        String weekDay = WEEK_DAYS[dayOfWeek - 1];
+
+        return weekDay + " " + buildTimeRange(startTime, endTime);
+    }
+
+    /**
+     * 构建每周定时演出时间安排(使用LocalTime)
+     *
+     * @param performanceWeek 星期几字符串(0-周一,1-周二,...,6-周日,逗号分隔)
+     * @param startTime        开始时间(LocalTime)
+     * @param endTime          结束时间(LocalTime)
+     * @return 时间安排字符串
+     */
+    private String buildWeeklyScheduleInfo(String performanceWeek, LocalTime startTime, LocalTime endTime) {
+        String[] weekDays = performanceWeek.split(",");
+        List<String> weekDayList = new ArrayList<>();
+
+        for (String weekDay : weekDays) {
+            if (StringUtils.isNotEmpty(weekDay.trim())) {
+                try {
+                    int dayIndex = Integer.parseInt(weekDay.trim());
+                    if (dayIndex >= 0 && dayIndex < WEEK_DAYS.length) {
+                        weekDayList.add(WEEK_DAYS[dayIndex]);
+                    }
+                } catch (NumberFormatException e) {
+                    log.warn("解析星期几失败,无效的值:{}", weekDay);
+                }
+            }
+        }
+
+        if (weekDayList.isEmpty()) {
+            return "";
+        }
+
+        String weekDayStr = String.join("、", weekDayList);
+        String timeRange = buildLocalTimeRange(startTime, endTime);
+
+        return "每周" + weekDayStr + timeRange;
+    }
+
+    /**
+     * 构建时间范围(使用Date)
+     *
+     * @param startTime 开始时间
+     * @param endTime   结束时间
+     * @return 时间范围字符串(格式:19:30-次日00:00)
+     */
+    private String buildTimeRange(Date startTime, Date endTime) {
+        String startTimeStr = TIME_FORMAT.format(startTime);
+
+        // 判断是否跨天
+        java.util.Calendar startCal = java.util.Calendar.getInstance();
+        startCal.setTime(startTime);
+        java.util.Calendar endCal = java.util.Calendar.getInstance();
+        endCal.setTime(endTime);
+
+        boolean isNextDay = endCal.get(java.util.Calendar.DAY_OF_YEAR) > startCal.get(java.util.Calendar.DAY_OF_YEAR) ||
+                endCal.get(java.util.Calendar.YEAR) > startCal.get(java.util.Calendar.YEAR);
+
+        String endTimeStr;
+        if (isNextDay) {
+            endTimeStr = "次日" + TIME_FORMAT.format(endTime);
+        } else {
+            endTimeStr = TIME_FORMAT.format(endTime);
+        }
+
+        return startTimeStr + "-" + endTimeStr;
+    }
+
+    /**
+     * 构建时间范围(使用LocalTime)
+     * <p>
+     * 用于每天定时和每周定时演出,判断是否跨天(结束时间小于或等于开始时间表示跨天)
+     * </p>
+     *
+     * @param startTime 开始时间(LocalTime)
+     * @param endTime   结束时间(LocalTime)
+     * @return 时间范围字符串(格式:19:30-次日00:00)
+     */
+    private String buildLocalTimeRange(LocalTime startTime, LocalTime endTime) {
+        String startTimeStr = startTime.format(LOCAL_TIME_FORMAT);
+
+        // 判断是否跨天:结束时间小于或等于开始时间表示跨天
+        boolean isNextDay = !endTime.isAfter(startTime);
+
+        String endTimeStr;
+        if (isNextDay) {
+            endTimeStr = "次日" + endTime.format(LOCAL_TIME_FORMAT);
+        } else {
+            endTimeStr = endTime.format(LOCAL_TIME_FORMAT);
+        }
+
+        return startTimeStr + "-" + endTimeStr;
+    }
+
+    /**
+     * 查询按日期分组的演出列表(用户端)
+     * <p>
+     * 根据店铺ID查询演出列表,按日期分组返回
+     * 只返回审核通过、已上线、未删除的演出
+     * 返回未来30天内有演出的日期及其对应的演出列表
+     * </p>
+     *
+     * @param storeId 店铺ID,必须大于0
+     * @return 按日期分组的演出列表
+     */
+    @Override
+    public PerformanceGroupListVo queryPerformanceListGroupByDate(Integer storeId) {
+        log.info("查询按日期分组的演出列表,参数:storeId={}", storeId);
+
+        // 参数校验
+        if (storeId == null || storeId <= 0) {
+            throw new IllegalArgumentException("店铺ID不能为空且必须大于0");
+        }
+
+        try {
+            // 查询所有演出
+            List<BarPerformance> performances = queryAllPerformances(storeId);
+
+            if (performances == null || performances.isEmpty()) {
+                PerformanceGroupListVo result = new PerformanceGroupListVo();
+                result.setGroupList(new ArrayList<>());
+                result.setTotal(0L);
+                return result;
+            }
+
+            // 转换为VO列表
+            List<PerformanceListVo> voList = convertToVoList(performances);
+
+            // 生成演出日期映射(日期 -> 演出列表)
+            Map<String, List<PerformanceListVo>> datePerformanceMap = generateDatePerformanceMap(performances, voList);
+
+            // 构建按日期分组的列表
+            List<PerformanceGroupByDateVo> groupList = buildGroupList(datePerformanceMap);
+
+            // 构建返回结果
+            PerformanceGroupListVo result = new PerformanceGroupListVo();
+            result.setGroupList(groupList);
+            result.setTotal((long) voList.size());
+
+            log.info("查询按日期分组的演出列表成功,店铺ID={},共{}个日期组,{}条演出记录",
+                    storeId, groupList.size(), voList.size());
+            return result;
+        } catch (Exception e) {
+            log.error("查询按日期分组的演出列表异常,storeId={},异常信息:{}", storeId, e.getMessage(), e);
+            throw new RuntimeException("查询按日期分组的演出列表失败:" + e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 查询所有演出
+     *
+     * @param storeId 店铺ID
+     * @return 演出列表
+     */
+    private List<BarPerformance> queryAllPerformances(Integer storeId) {
+        LambdaQueryWrapper<BarPerformance> queryWrapper = buildQueryWrapper(storeId);
+        // 不限制数量,查询所有符合条件的演出
+        return barPerformanceMapper.selectList(queryWrapper);
+    }
+
+    /**
+     * 生成演出日期映射
+     * <p>
+     * 根据演出类型生成未来30天内的演出日期,并建立日期与演出的映射关系
+     * </p>
+     *
+     * @param performances 演出列表
+     * @param voList       VO列表
+     * @return 日期与演出列表的映射
+     */
+    private Map<String, List<PerformanceListVo>> generateDatePerformanceMap(
+            List<BarPerformance> performances, List<PerformanceListVo> voList) {
+        Map<String, List<PerformanceListVo>> datePerformanceMap = new LinkedHashMap<>();
+
+        // 获取今天和未来30天的日期范围
+        Date today = new Date();
+        java.util.Calendar cal = java.util.Calendar.getInstance();
+        cal.setTime(today);
+        cal.set(java.util.Calendar.HOUR_OF_DAY, 0);
+        cal.set(java.util.Calendar.MINUTE, 0);
+        cal.set(java.util.Calendar.SECOND, 0);
+        cal.set(java.util.Calendar.MILLISECOND, 0);
+        Date todayStart = cal.getTime();
+
+        cal.add(java.util.Calendar.DAY_OF_MONTH, 30);
+        Date futureEnd = cal.getTime();
+
+        // 遍历演出,生成日期映射
+        for (int i = 0; i < performances.size(); i++) {
+            BarPerformance performance = performances.get(i);
+            PerformanceListVo vo = voList.get(i);
+            String frequency = performance.getPerformanceFrequency();
+
+            if (StringUtils.isEmpty(frequency)) {
+                continue;
+            }
+
+            Set<String> performanceDates = new HashSet<>();
+
+            switch (frequency) {
+                case CommonConstant.PERFORMANCE_FREQUENCY_SINGLE:
+                    // 单次演出:使用singleStartDatetime
+                    Date singleStart = performance.getSingleStartDatetime();
+                    if (singleStart != null && !singleStart.before(todayStart) && !singleStart.after(futureEnd)) {
+                        String dateStr = DATE_STRING_FORMAT.format(singleStart);
+                        performanceDates.add(dateStr);
+                    }
+                    break;
+                case CommonConstant.PERFORMANCE_FREQUENCY_DAILY:
+                    // 每天定时:从dailyStartDate到dailyEndDate,每天生成一条记录
+                    Date dailyStart = performance.getDailyStartDate();
+                    Date dailyEnd = performance.getDailyEndDate();
+                    if (dailyStart != null && dailyEnd != null) {
+                        Date queryStart = dailyStart.before(todayStart) ? todayStart : dailyStart;
+                        Date queryEnd = dailyEnd.after(futureEnd) ? futureEnd : dailyEnd;
+                        if (!queryStart.after(queryEnd)) {
+                            java.util.Calendar dateCal = java.util.Calendar.getInstance();
+                            dateCal.setTime(queryStart);
+                            while (!dateCal.getTime().after(queryEnd)) {
+                                String dateStr = DATE_STRING_FORMAT.format(dateCal.getTime());
+                                performanceDates.add(dateStr);
+                                dateCal.add(java.util.Calendar.DAY_OF_MONTH, 1);
+                            }
+                        }
+                    }
+                    break;
+                case CommonConstant.PERFORMANCE_FREQUENCY_WEEKLY:
+                    // 每周定时:从dailyStartDate到dailyEndDate,只生成符合performanceWeek的日期
+                    Date weeklyStart = performance.getDailyStartDate();
+                    Date weeklyEnd = performance.getDailyEndDate();
+                    String performanceWeek = performance.getPerformanceWeek();
+                    if (weeklyStart != null && weeklyEnd != null && StringUtils.isNotEmpty(performanceWeek)) {
+                        Date queryStart = weeklyStart.before(todayStart) ? todayStart : weeklyStart;
+                        Date queryEnd = weeklyEnd.after(futureEnd) ? futureEnd : weeklyEnd;
+                        if (!queryStart.after(queryEnd)) {
+                            // 解析星期几列表
+                            Set<String> weekDaySet = new HashSet<>();
+                            String[] weekDays = performanceWeek.split(",");
+                            for (String weekDay : weekDays) {
+                                if (StringUtils.isNotEmpty(weekDay.trim())) {
+                                    weekDaySet.add(weekDay.trim());
+                                }
+                            }
+
+                            java.util.Calendar dateCal = java.util.Calendar.getInstance();
+                            dateCal.setTime(queryStart);
+                            while (!dateCal.getTime().after(queryEnd)) {
+                                // 获取当前日期是星期几(0-周一,1-周二,...,6-周日)
+                                int dayOfWeek = dateCal.get(java.util.Calendar.DAY_OF_WEEK);
+                                int todayWeekDay = (dayOfWeek == 1) ? 6 : (dayOfWeek - 2);
+                                String todayWeekDayStr = String.valueOf(todayWeekDay);
+
+                                if (weekDaySet.contains(todayWeekDayStr)) {
+                                    String dateStr = DATE_STRING_FORMAT.format(dateCal.getTime());
+                                    performanceDates.add(dateStr);
+                                }
+                                dateCal.add(java.util.Calendar.DAY_OF_MONTH, 1);
+                            }
+                        }
+                    }
+                    break;
+                default:
+                    break;
+            }
+
+            // 将演出添加到对应日期的列表中
+            for (String dateStr : performanceDates) {
+                datePerformanceMap.computeIfAbsent(dateStr, k -> new ArrayList<>()).add(vo);
+            }
+        }
+
+        return datePerformanceMap;
+    }
+
+    /**
+     * 构建按日期分组的列表
+     *
+     * @param datePerformanceMap 日期与演出列表的映射
+     * @return 按日期分组的列表
+     */
+    private List<PerformanceGroupByDateVo> buildGroupList(Map<String, List<PerformanceListVo>> datePerformanceMap) {
+        List<PerformanceGroupByDateVo> groupList = new ArrayList<>();
+
+        // 获取今天的日期字符串
+        String todayStr = DATE_STRING_FORMAT.format(new Date());
+
+        // 按日期排序
+        List<String> sortedDates = datePerformanceMap.keySet().stream()
+                .sorted()
+                .collect(Collectors.toList());
+
+        // 构建分组列表
+        for (String dateStr : sortedDates) {
+            PerformanceGroupByDateVo group = new PerformanceGroupByDateVo();
+            group.setDate(dateStr);
+
+            // 判断是否为今天
+            boolean isToday = todayStr.equals(dateStr);
+            group.setIsToday(isToday);
+
+            // 构建日期标题
+            try {
+                Date date = DATE_STRING_FORMAT.parse(dateStr);
+                String dateTitle = DATE_TITLE_FORMAT.format(date);
+
+                if (isToday) {
+                    group.setDateTitle(dateTitle + " 今天");
+                } else {
+                    // 获取星期几
+                    java.util.Calendar cal = java.util.Calendar.getInstance();
+                    cal.setTime(date);
+                    int dayOfWeek = cal.get(java.util.Calendar.DAY_OF_WEEK);
+                    String weekDay = WEEK_DAYS[dayOfWeek - 1];
+                    group.setDateTitle(dateTitle + " " + weekDay);
+                }
+            } catch (Exception e) {
+                log.warn("解析日期失败,dateStr={},异常信息:{}", dateStr, e.getMessage());
+                group.setDateTitle(dateStr);
+            }
+
+            group.setPerformanceList(datePerformanceMap.get(dateStr));
+            groupList.add(group);
+        }
+
+        return groupList;
+    }
+
+    /**
+     * 查询演出详情(用户端)
+     * <p>
+     * 根据演出ID查询演出详细信息
+     * 包含演出基本信息、演出时间、演出风格、演出详情描述和演出嘉宾列表
+     * </p>
+     *
+     * @param id 演出ID,必须大于0
+     * @return 演出详情,如果演出不存在则返回null
+     */
+    @Override
+    public PerformanceDetailVo queryPerformanceDetail(Integer id) {
+        log.info("查询演出详情,参数:id={}", id);
+
+        // 参数校验
+        if (id == null || id <= 0) {
+            log.warn("查询演出详情失败,演出ID无效:id={}", id);
+            throw new IllegalArgumentException("演出ID不能为空且必须大于0");
+        }
+
+        try {
+            // 查询演出基本信息
+            BarPerformance performance = barPerformanceMapper.selectById(id);
+            if (performance == null) {
+                log.warn("查询演出详情失败,演出不存在:id={}", id);
+                return null;
+            }
+
+            // 校验演出状态:只返回审核通过、已上线、未删除的演出
+            if (!CommonConstant.DELETE_FLAG_UNDELETE.equals(performance.getDeleteFlag()) ||
+                    !CommonConstant.PERFORMANCE_REVIEW_STATUS_APPROVED.equals(performance.getReviewStatus()) ||
+                    !CommonConstant.PERFORMANCE_ONLINE_STATUS_ONLINE.equals(performance.getOnlineStatus())) {
+                log.warn("查询演出详情失败,演出状态不符合要求:id={},deleteFlag={},reviewStatus={},onlineStatus={}",
+                        id, performance.getDeleteFlag(), performance.getReviewStatus(), performance.getOnlineStatus());
+                return null;
+            }
+
+            // 构建演出详情VO
+            PerformanceDetailVo vo = new PerformanceDetailVo();
+            vo.setId(performance.getId());
+            vo.setPerformanceName(performance.getPerformanceName());
+            vo.setPerformancePoster(performance.getPerformancePoster());
+            vo.setPerformanceType(performance.getPerformanceType());
+            vo.setPerformanceContent(performance.getPerformanceContent());
+
+            // 构建演出时间
+            vo.setPerformanceTime(buildPerformanceTime(performance));
+
+            // 构建演出风格
+            vo.setPerformanceStyle(buildPerformanceStyle(performance.getPerformanceStyle()));
+
+            // 查询演出嘉宾列表
+            List<PerformanceGuestVo> guestList = queryGuestList(performance.getStaffConfigIds());
+            vo.setGuestList(guestList);
+
+            // 设置演出人员数量
+            vo.setGuestCount(guestList != null ? guestList.size() : 0);
+
+            log.info("查询演出详情成功,id={},嘉宾数量:{}", id,
+                    vo.getGuestCount());
+            return vo;
+        } catch (Exception e) {
+            log.error("查询演出详情异常,id={},异常信息:{}", id, e.getMessage(), e);
+            throw new RuntimeException("查询演出详情失败:" + e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 构建演出时间字符串
+     * <p>
+     * 格式:2025.11.11-2027.01.31每周一、四19:30-次日00:00
+     * </p>
+     *
+     * @param performance 演出信息
+     * @return 演出时间字符串
+     */
+    private String buildPerformanceTime(BarPerformance performance) {
+        String frequency = performance.getPerformanceFrequency();
+        if (StringUtils.isEmpty(frequency)) {
+            return "";
+        }
+
+        try {
+            StringBuilder timeStr = new StringBuilder();
+
+            // 构建日期范围
+            String dateRange = buildDateRange(performance);
+            if (StringUtils.isNotEmpty(dateRange)) {
+                timeStr.append(dateRange);
+            }
+
+            // 构建时间安排
+            String scheduleInfo = buildScheduleInfo(performance);
+            if (StringUtils.isNotEmpty(scheduleInfo)) {
+                if (timeStr.length() > 0) {
+                    timeStr.append(scheduleInfo);
+                } else {
+                    timeStr.append(scheduleInfo);
+                }
+            }
+
+            return timeStr.toString();
+        } catch (Exception e) {
+            log.error("构建演出时间字符串异常,performanceId={},异常信息:{}", performance.getId(), e.getMessage(), e);
+            return "";
+        }
+    }
+
+    /**
+     * 构建演出风格字符串
+     * <p>
+     * 根据performance_style字段(dict_id逗号分隔)查询字典表,转换为名称
+     * 格式:流行、民谣
+     * </p>
+     *
+     * @param performanceStyle 演出风格dict_id字符串(逗号分隔)
+     * @return 演出风格名称字符串(逗号分隔)
+     */
+    private String buildPerformanceStyle(String performanceStyle) {
+        if (StringUtils.isEmpty(performanceStyle)) {
+            return "";
+        }
+
+        try {
+            String[] styleIds = performanceStyle.split(",");
+            List<String> styleNames = new ArrayList<>();
+
+            for (String styleId : styleIds) {
+                if (StringUtils.isNotEmpty(styleId.trim())) {
+                    try {
+                        // 查询字典表,typeName为proficient_tag
+                        LambdaQueryWrapper<StoreDictionary> queryWrapper = new LambdaQueryWrapper<>();
+                        queryWrapper.eq(StoreDictionary::getTypeName, "proficient_tag")
+                                .eq(StoreDictionary::getDictId, styleId.trim())
+                                .eq(StoreDictionary::getDeleteFlag, CommonConstant.DELETE_FLAG_UNDELETE)
+                                .last("limit 1");
+                        StoreDictionary dictionary = storeDictionaryMapper.selectOne(queryWrapper);
+                        if (dictionary != null && StringUtils.isNotEmpty(dictionary.getDictDetail())) {
+                            styleNames.add(dictionary.getDictDetail());
+                        }
+                    } catch (Exception e) {
+                        log.warn("查询演出风格字典失败,styleId={},异常信息:{}", styleId, e.getMessage());
+                    }
+                }
+            }
+
+            return String.join("、", styleNames);
+        } catch (Exception e) {
+            log.error("构建演出风格字符串异常,performanceStyle={},异常信息:{}", performanceStyle, e.getMessage(), e);
+            return "";
+        }
+    }
+
+    /**
+     * 查询演出嘉宾列表
+     *
+     * @param staffConfigIds 员工配置ID字符串(逗号分隔)
+     * @return 演出嘉宾列表
+     */
+    private List<PerformanceGuestVo> queryGuestList(String staffConfigIds) {
+        List<PerformanceGuestVo> guestList = new ArrayList<>();
+
+        if (StringUtils.isEmpty(staffConfigIds)) {
+            return guestList;
+        }
+
+        try {
+            String[] ids = staffConfigIds.split(",");
+            List<Integer> staffIdList = new ArrayList<>();
+
+            // 解析所有有效的员工ID
+            for (String idStr : ids) {
+                if (StringUtils.isNotEmpty(idStr.trim())) {
+                    try {
+                        Integer staffId = Integer.parseInt(idStr.trim());
+                        if (staffId > 0) {
+                            staffIdList.add(staffId);
+                        }
+                    } catch (NumberFormatException e) {
+                        log.warn("解析员工配置ID失败,无效的ID:{}", idStr);
+                    }
+                }
+            }
+
+            if (staffIdList.isEmpty()) {
+                return guestList;
+            }
+
+            // 批量查询员工信息
+            List<StoreStaffConfig> staffList = storeStaffConfigMapper.selectBatchIds(staffIdList);
+
+            // 转换为VO列表
+            for (StoreStaffConfig staff : staffList) {
+                if (staff == null || !CommonConstant.DELETE_FLAG_UNDELETE.equals(staff.getDeleteFlag())) {
+                    continue;
+                }
+
+                PerformanceGuestVo guest = new PerformanceGuestVo();
+                guest.setStaffId(staff.getId());
+                guest.setName(staff.getName());
+                guest.setStaffImage(staff.getStaffImage());
+                guest.setStaffPosition(staff.getStaffPosition());
+                guest.setProficientProjects(staff.getProficientProjects());
+                guest.setLikeCount(staff.getLikeCount() != null ? staff.getLikeCount() : 0);
+                guestList.add(guest);
+            }
+
+            return guestList;
+        } catch (Exception e) {
+            log.error("查询演出嘉宾列表异常,staffConfigIds={},异常信息:{}", staffConfigIds, e.getMessage(), e);
+            return guestList;
+        }
+    }
+}
+