Ver Fonte

feet:商户端酒吧演出相关接口的实现和AI审核图文的功能

panzhilin há 2 dias atrás
pai
commit
bac477176c

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

@@ -0,0 +1,139 @@
+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;
+
+/**
+ * 演出信息实体类
+ * 对应表: bar_performance
+ *
+ * @author assistant
+ * @since 2025-12-17
+ */
+@Data
+@JsonInclude
+@TableName("bar_performance")
+@ApiModel(value = "BarPerformance对象", description = "演出信息")
+public class BarPerformance {
+
+    @ApiModelProperty(value = "演出ID(主键)")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @ApiModelProperty(value = "父演出ID(关联本表id,null为顶级演出)")
+    @TableField("parent_id")
+    private Integer parentId;
+
+    @ApiModelProperty(value = "关联门店ID(关联store_info.id)")
+    @TableField("store_id")
+    private Integer storeId;
+
+    @ApiModelProperty(value = "表演嘉宾ids,逗号分隔")
+    @TableField("staff_config_ids")
+    private String staffConfigIds;
+
+    @ApiModelProperty(value = "演出名称")
+    @TableField("performance_name")
+    private String performanceName;
+
+    @ApiModelProperty(value = "演出海报路径")
+    @TableField("performance_poster")
+    private String performancePoster;
+
+    @ApiModelProperty(value = "演出风格(字典表proficient_tag逗号分隔)")
+    @TableField("performance_style")
+    private String performanceStyle;
+
+    @ApiModelProperty(value = "演出类型(单选:0-特邀演出,1-常规演出)")
+    @TableField("performance_type")
+    private Integer performanceType;
+
+    @ApiModelProperty(value = "演出频次:0-单次 1-每天定时 2-每周定时")
+    @TableField("performance_frequency")
+    private String performanceFrequency;
+
+    @ApiModelProperty(value = "演出日期(0-周一,1-周二,2-周三,3-周四,4-周五,5-周六,6-周日,复选逗号分隔)")
+    @TableField("performance_week")
+    private String performanceWeek;
+
+    @ApiModelProperty(value = "演出日期开始时间")
+    @TableField("single_start_datetime")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date singleStartDatetime;
+
+    @ApiModelProperty(value = "演出日期结束时间")
+    @TableField("single_end_datetime")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date singleEndDatetime;
+
+    @ApiModelProperty(value = "演出时间开始日期")
+    @TableField("daily_start_date")
+    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
+    private Date dailyStartDate;
+
+    @ApiModelProperty(value = "演出时间结束日期")
+    @TableField("daily_end_date")
+    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
+    private Date dailyEndDate;
+
+    @ApiModelProperty(value = "图片")
+    @TableField("performance_detail")
+    private String performanceDetail;
+
+    @ApiModelProperty(value = "演出完整详情")
+    @TableField("performance_content")
+    private String performanceContent;
+
+    @ApiModelProperty(value = "演出须知(限300字)")
+    @TableField("performance_notice")
+    private String performanceNotice;
+
+    @ApiModelProperty(value = "审核状态:0-待审核 1-审核通过 2-审核拒绝")
+    @TableField("review_status")
+    private Integer reviewStatus;
+
+    @ApiModelProperty(value = "审核拒绝原因")
+    @TableField("reject_reason")
+    private String rejectReason;
+
+    @ApiModelProperty(value = "删除标记:0-未删除,1-已删除")
+    @TableField("delete_flag")
+    @TableLogic
+    private Integer deleteFlag;
+
+    @ApiModelProperty(value = "隐藏标记:0-不隐藏,1-隐藏")
+    @TableField("hidden")
+    private Integer hidden;
+
+    @ApiModelProperty(value = "上线状态:0-下线,1-上线")
+    @TableField("online_status")
+    private Integer onlineStatus;
+
+    @ApiModelProperty(value = "状态:0禁用,1启用")
+    @TableField("status")
+    private Integer status;
+
+    @ApiModelProperty(value = "创建人")
+    @TableField("created_user_id")
+    private Integer createdUserId;
+
+    @ApiModelProperty(value = "更新人")
+    @TableField("updated_user_id")
+    private Integer updatedUserId;
+
+    @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 = "更新时间")
+    @TableField(value = "updated_time", fill = FieldFill.UPDATE)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date updatedTime;
+}

+ 33 - 0
alien-entity/src/main/java/shop/alien/entity/store/dto/BarPerformanceOnlineStatusDto.java

@@ -0,0 +1,33 @@
+package shop.alien.entity.store.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 酒吧演出上线状态设置DTO
+ * 用于接收设置演出上线状态的请求参数
+ *
+ * @author assistant
+ * @since 2025-12-19
+ */
+@Data
+@ApiModel(value = "BarPerformanceOnlineStatusDto对象", description = "酒吧演出上线状态设置DTO")
+public class BarPerformanceOnlineStatusDto implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 演出ID
+     */
+    @ApiModelProperty(value = "演出ID", required = true)
+    private Integer id;
+
+    /**
+     * 上线状态(0-下线,1-上线)
+     */
+    @ApiModelProperty(value = "上线状态(0-下线,1-上线)", required = true)
+    private Integer onlineStatus;
+}
+

+ 201 - 0
alien-entity/src/main/java/shop/alien/entity/store/vo/BarPerformanceDetailVo.java

@@ -0,0 +1,201 @@
+package shop.alien.entity.store.vo;
+
+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 shop.alien.entity.store.BarPerformance;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 酒吧演出详情VO
+ * 包含演出基本信息和表演嘉宾列表
+ *
+ * @author assistant
+ * @since 2025-12-19
+ */
+@Data
+@JsonInclude
+@ApiModel(value = "BarPerformanceDetailVo对象", description = "酒吧演出详情")
+public class BarPerformanceDetailVo implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 演出ID(主键)
+     */
+    @ApiModelProperty(value = "演出ID(主键)")
+    private Integer id;
+
+    /**
+     * 父演出ID(关联本表id,null为顶级演出)
+     */
+    @ApiModelProperty(value = "父演出ID(关联本表id,null为顶级演出)")
+    private Integer parentId;
+
+    /**
+     * 关联门店ID(关联store_info.id)
+     */
+    @ApiModelProperty(value = "关联门店ID(关联store_info.id)")
+    private Integer storeId;
+
+    /**
+     * 表演嘉宾ids,逗号分隔
+     */
+    @ApiModelProperty(value = "表演嘉宾ids,逗号分隔")
+    private String staffConfigIds;
+
+    /**
+     * 演出名称
+     */
+    @ApiModelProperty(value = "演出名称")
+    private String performanceName;
+
+    /**
+     * 演出海报路径
+     */
+    @ApiModelProperty(value = "演出海报路径")
+    private String performancePoster;
+
+    /**
+     * 演出风格(字典表proficient_tag逗号分隔)
+     */
+    @ApiModelProperty(value = "演出风格(字典表proficient_tag逗号分隔)")
+    private String performanceStyle;
+
+    /**
+     * 演出类型(单选:0-特邀演出,1-常规演出)
+     */
+    @ApiModelProperty(value = "演出类型(单选:0-特邀演出,1-常规演出)")
+    private Integer performanceType;
+
+    /**
+     * 演出频次:0-单次 1-每天定时 2-每周定时
+     */
+    @ApiModelProperty(value = "演出频次:0-单次 1-每天定时 2-每周定时")
+    private String performanceFrequency;
+
+    /**
+     * 演出日期(0-周一,1-周二,2-周三,3-周四,4-周五,5-周六,6-周日,复选逗号分隔)
+     */
+    @ApiModelProperty(value = "演出日期(0-周一,1-周二,2-周三,3-周四,4-周五,5-周六,6-周日,复选逗号分隔)")
+    private String performanceWeek;
+
+    /**
+     * 演出日期开始时间
+     */
+    @ApiModelProperty(value = "演出日期开始时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date singleStartDatetime;
+
+    /**
+     * 演出日期结束时间
+     */
+    @ApiModelProperty(value = "演出日期结束时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date singleEndDatetime;
+
+    /**
+     * 演出时间开始日期
+     */
+    @ApiModelProperty(value = "演出时间开始日期")
+    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
+    private Date dailyStartDate;
+
+    /**
+     * 演出时间结束日期
+     */
+    @ApiModelProperty(value = "演出时间结束日期")
+    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
+    private Date dailyEndDate;
+
+    /**
+     * 图片
+     */
+    @ApiModelProperty(value = "图片")
+    private String performanceDetail;
+
+    /**
+     * 演出完整详情
+     */
+    @ApiModelProperty(value = "演出完整详情")
+    private String performanceContent;
+
+    /**
+     * 演出须知(限300字)
+     */
+    @ApiModelProperty(value = "演出须知(限300字)")
+    private String performanceNotice;
+
+    /**
+     * 审核状态:0-待审核 1-审核通过 2-审核拒绝
+     */
+    @ApiModelProperty(value = "审核状态:0-待审核 1-审核通过 2-审核拒绝")
+    private Integer reviewStatus;
+
+    /**
+     * 审核拒绝原因
+     */
+    @ApiModelProperty(value = "审核拒绝原因")
+    private String rejectReason;
+
+    /**
+     * 删除标记:0-未删除,1-已删除
+     */
+    @ApiModelProperty(value = "删除标记:0-未删除,1-已删除")
+    private Integer deleteFlag;
+
+    /**
+     * 隐藏标记:0-不隐藏,1-隐藏
+     */
+    @ApiModelProperty(value = "隐藏标记:0-不隐藏,1-隐藏")
+    private Integer hidden;
+
+    /**
+     * 上线状态:0-下线,1-上线
+     */
+    @ApiModelProperty(value = "上线状态:0-下线,1-上线")
+    private Integer onlineStatus;
+
+    /**
+     * 状态:0禁用,1启用
+     */
+    @ApiModelProperty(value = "状态:0禁用,1启用")
+    private Integer status;
+
+    /**
+     * 创建人
+     */
+    @ApiModelProperty(value = "创建人")
+    private Integer createdUserId;
+
+    /**
+     * 更新人
+     */
+    @ApiModelProperty(value = "更新人")
+    private Integer updatedUserId;
+
+    /**
+     * 创建时间
+     */
+    @ApiModelProperty(value = "创建时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date createdTime;
+
+    /**
+     * 更新时间
+     */
+    @ApiModelProperty(value = "更新时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date updatedTime;
+
+    /**
+     * 表演嘉宾列表
+     */
+    @ApiModelProperty(value = "表演嘉宾列表")
+    private List<PerformerVo> performers;
+}
+

+ 8 - 9
alien-entity/src/main/java/shop/alien/mapper/LifeSysDeptMapper.java

@@ -1,16 +1,15 @@
 package shop.alien.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import org.apache.ibatis.annotations.Mapper;
-import shop.alien.entity.store.LifeSysDept;
+import shop.alien.entity.store.BarPerformance;
 
 /**
- * 部门表 Mapper 接口
+ * BarPerformanceMapper接口
+ * 对应数据库表:bar_performance
+ * 用于操作演出信息表
  *
- * @author system
- * @since 2025-01-XX
+ * @author AI Assistant
+ * @since 2025-12-17
  */
-@Mapper
-public interface LifeSysDeptMapper extends BaseMapper<LifeSysDept> {
-}
-
+public interface BarPerformanceMapper extends BaseMapper<BarPerformance> {
+}

+ 48 - 0
alien-store/src/main/java/shop/alien/store/config/AsyncConfig.java

@@ -0,0 +1,48 @@
+package shop.alien.store.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+import java.util.concurrent.Executor;
+
+/**
+ * 异步任务配置类
+ * 用于配置异步任务的线程池
+ *
+ * @author assistant
+ * @since 2025-12-19
+ */
+@Configuration
+@EnableAsync
+public class AsyncConfig {
+
+    /**
+     * 配置异步任务执行器
+     * 用于执行AI审核等异步任务
+     *
+     * @return 异步任务执行器
+     */
+    @Bean(name = "taskExecutor")
+    public Executor taskExecutor() {
+        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+        // 核心线程数
+        executor.setCorePoolSize(5);
+        // 最大线程数
+        executor.setMaxPoolSize(10);
+        // 队列容量
+        executor.setQueueCapacity(100);
+        // 线程名前缀
+        executor.setThreadNamePrefix("async-task-");
+        // 拒绝策略:调用者运行策略
+        executor.setRejectedExecutionHandler(new java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy());
+        // 等待所有任务结束后再关闭线程池
+        executor.setWaitForTasksToCompleteOnShutdown(true);
+        // 等待时间
+        executor.setAwaitTerminationSeconds(60);
+        executor.initialize();
+        return executor;
+    }
+}
+

+ 202 - 0
alien-store/src/main/java/shop/alien/store/controller/BarPerformanceController.java

@@ -0,0 +1,202 @@
+package shop.alien.store.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+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.BarPerformance;
+import shop.alien.store.service.BarPerformanceService;
+
+/**
+ * 酒吧演出Controller
+ * 提供酒吧演出的CRUD、审核、上下线等RESTful API接口
+ *
+ * @author assistant
+ * @since 2025-12-17
+ */
+@Slf4j
+@Api(tags = {"商户端-酒吧演出"})
+@CrossOrigin
+@RestController
+@RequestMapping("/store/bar/performance")
+@RequiredArgsConstructor
+public class BarPerformanceController {
+
+    private final BarPerformanceService barPerformanceService;
+
+    /**
+     * 获取酒吧演出列表(分页)
+     *
+     * @param page    分页页数
+     * @param size    分页条数
+     * @param status  演出状态
+     * @return 演出列表
+     */
+    @ApiOperation("获取酒吧演出列表")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "page", value = "分页页数", dataType = "int", paramType = "query", required = true),
+            @ApiImplicitParam(name = "size", value = "分页条数", dataType = "int", paramType = "query", required = true),
+            @ApiImplicitParam(name = "status", value = "演出状态", dataType = "String", paramType = "query", required = false)
+    })
+    @GetMapping("/list")
+    public R<IPage<BarPerformance>> getBarPerformanceList(
+            @RequestParam int page,
+            @RequestParam int size,
+            @RequestParam(required = false) String status) {
+        log.info("BarPerformanceController.getBarPerformanceList?page={}, size={}, status={}", page, size, status);
+        try {
+            IPage<BarPerformance> performanceList = barPerformanceService.getBarPerformanceList(page, size, status);
+            return R.data(performanceList);
+        } catch (Exception e) {
+            log.error("获取酒吧演出列表失败", e);
+            return R.fail("获取酒吧演出列表失败:" + e.getMessage());
+        }
+    }
+
+    /**
+     * 新增或更新酒吧演出
+     *
+     * @param barPerformance 演出信息
+     * @return 操作结果
+     */
+    @ApiOperation("新增或更新酒吧演出")
+    @PostMapping("/saveOrUpdate")
+    public R<Integer> addOrUpdateBarPerformance(@RequestBody BarPerformance barPerformance) {
+        log.info("BarPerformanceController.addOrUpdateBarPerformance?barPerformance={}", barPerformance);
+        try {
+            int result = barPerformanceService.addOrUpdateBarPerformance(barPerformance);
+            if (result > 0) {
+                return R.success("操作成功");
+            } else {
+                return R.fail("操作失败");
+            }
+        } catch (Exception e) {
+            log.error("新增或更新酒吧演出失败", e);
+            return R.fail("新增或更新酒吧演出失败:" + e.getMessage());
+        }
+    }
+
+    /**
+     * 获取酒吧演出详情
+     *
+     * @param id 演出ID
+     * @return 演出详情
+     */
+    @ApiOperation("获取酒吧演出详情")
+    @ApiImplicitParam(name = "id", value = "演出ID", dataType = "Integer", paramType = "query", required = true)
+    @GetMapping("/detail")
+    public R<BarPerformance> getBarPerformanceDetail(@RequestParam Integer id) {
+        log.info("BarPerformanceController.getBarPerformanceDetail?id={}", id);
+        try {
+            BarPerformance performance = barPerformanceService.getBarPerformanceDetail(id);
+            if (performance != null) {
+                return R.data(performance);
+            } else {
+                return R.fail("演出不存在");
+            }
+        } catch (Exception e) {
+            log.error("获取酒吧演出详情失败", e);
+            return R.fail("获取酒吧演出详情失败:" + e.getMessage());
+        }
+    }
+
+    /**
+     * 删除酒吧演出
+     *
+     * @param id 演出ID
+     * @return 操作结果
+     */
+    @ApiOperation("删除酒吧演出")
+    @ApiImplicitParam(name = "id", value = "演出ID", dataType = "Integer", paramType = "query", required = true)
+    @DeleteMapping("/delete")
+    public R<Integer> deleteBarPerformance(@RequestParam Integer id) {
+        log.info("BarPerformanceController.deleteBarPerformance?id={}", id);
+        try {
+            Integer result = barPerformanceService.deleteBarPerformance(id);
+            if (result > 0) {
+                return R.success("删除成功");
+            } else {
+                return R.fail("删除失败");
+            }
+        } catch (Exception e) {
+            log.error("删除酒吧演出失败", e);
+            return R.fail("删除酒吧演出失败:" + e.getMessage());
+        }
+    }
+
+    /**
+     * 设置演出上线下线状态
+     *
+     * @param id          演出ID
+     * @param onlineStatus 上线状态(0-下线,1-上线)
+     * @return 操作结果
+     */
+    @ApiOperation("设置演出上线状态")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "演出ID", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "onlineStatus", value = "上线状态(0-下线,1-上线)", dataType = "Integer", paramType = "query", required = true)
+    })
+    @PostMapping("/setOnlineStatus")
+    public R<Integer> setOnlineStatus(
+            @RequestParam Integer id,
+            @RequestParam Integer onlineStatus) {
+        log.info("BarPerformanceController.setOnlineStatus?id={}, onlineStatus={}", id, onlineStatus);
+        try {
+            Integer result = barPerformanceService.setOnlineStatus(id, onlineStatus);
+            if (result > 0) {
+                return R.success("设置成功");
+            } else {
+                return R.fail("设置失败");
+            }
+        } catch (Exception e) {
+            log.error("设置演出上线状态失败", e);
+            return R.fail("设置演出上线状态失败:" + e.getMessage());
+        }
+    }
+
+    /**
+     * 根据门店ID查询演出列表
+     *
+     * @param page    分页页数
+     * @param size    分页条数
+     * @param storeId 门店ID
+     * @param statusReview 审核状态(0-待审核 1-审核通过 2-审核拒绝)
+     * @param category 演出分类(all-全部, not_started-未开始, in_progress-进行中, ended-已结束)
+     * @param performanceName 演出名称(可选,支持模糊搜索)
+     * @return 演出列表
+     */
+    @ApiOperation("根据门店ID查询演出列表(支持按审核状态、分类和名称搜索)")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "page", value = "分页页数", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "size", value = "分页条数", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "storeId", value = "门店ID", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "statusReview", value = "审核状态(0-待审核 1-审核通过 2-审核拒绝)", dataType = "Integer", paramType = "query", required = false),
+            @ApiImplicitParam(name = "category", value = "演出分类(all-全部, not_started-未开始, in_progress-进行中, ended-已结束)", dataType = "String", paramType = "query", required = false),
+            @ApiImplicitParam(name = "performanceName", value = "演出名称(支持模糊搜索)", dataType = "String", paramType = "query", required = false)
+    })
+    @GetMapping("/listByStoreId")
+    public R<IPage<BarPerformance>> queryPerformanceListByStoreId(
+            @RequestParam Integer page,
+            @RequestParam Integer size,
+            @RequestParam Integer storeId,
+            @RequestParam(required = false) Integer statusReview,
+            @RequestParam(required = false) String category,
+            @RequestParam(required = false) String performanceName) {
+        log.info("BarPerformanceController.queryPerformanceListByStoreId?page={}, size={}, storeId={}, statusReview={}, category={}, performanceName={}", 
+                page, size, storeId, statusReview, category, performanceName);
+        try {
+            IPage<BarPerformance> performanceList = barPerformanceService.queryPerformanceListByStoreIdAndCategory(
+                    page, size, storeId, statusReview, category != null ? category : "all", performanceName);
+            return R.data(performanceList);
+        } catch (Exception e) {
+            log.error("根据门店ID查询演出列表失败", e);
+            return R.fail("根据门店ID查询演出列表失败:" + e.getMessage());
+        }
+    }
+
+}

+ 23 - 0
alien-store/src/main/java/shop/alien/store/service/BarPerformanceAuditService.java

@@ -0,0 +1,23 @@
+package shop.alien.store.service;
+
+import shop.alien.entity.store.BarPerformance;
+
+/**
+ * 酒吧演出审核服务接口
+ * 用于异步执行AI内容审核
+ *
+ * @author assistant
+ * @since 2025-12-19
+ */
+public interface BarPerformanceAuditService {
+
+    /**
+     * 异步执行AI内容审核
+     * 审核演出名称、演出详情、演出须知等文本内容以及演出海报、详情图片
+     *
+     * @param performanceId 演出ID
+     * @param barPerformance 演出信息
+     */
+    void asyncAuditBarPerformance(Integer performanceId, BarPerformance barPerformance);
+}
+

+ 81 - 0
alien-store/src/main/java/shop/alien/store/service/BarPerformanceService.java

@@ -0,0 +1,81 @@
+package shop.alien.store.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import shop.alien.entity.store.BarPerformance;
+
+/**
+ * 酒吧演出服务接口
+ * 提供酒吧演出的CRUD、审核、上下线等核心业务功能
+ *
+ * @author assistant
+ * @since 2025-12-17
+ */
+public interface BarPerformanceService {
+
+    /**
+     * 获取酒吧演出列表(分页)
+     *
+     * @param page    分页页数
+     * @param size    分页条数
+     * @param status  演出状态
+     * @return 演出列表
+     */
+    IPage<BarPerformance> getBarPerformanceList(int page, int size, String status);
+
+    /**
+     * 新增或更新酒吧演出
+     *
+     * @param barPerformance 演出信息
+     * @return 操作结果
+     */
+    int addOrUpdateBarPerformance(BarPerformance barPerformance);
+
+    /**
+     * 获取酒吧演出详情
+     *
+     * @param id 演出ID
+     * @return 演出详情
+     */
+    BarPerformance getBarPerformanceDetail(Integer id);
+
+    /**
+     * 删除酒吧演出
+     *
+     * @param id 演出ID
+     * @return 操作结果
+     */
+    Integer deleteBarPerformance(Integer id);
+
+    /**
+     * 设置演出上线状态
+     *
+     * @param id          演出ID
+     * @param onlineStatus 上线状态(0-下线,1-上线)
+     * @return 操作结果
+     */
+    Integer setOnlineStatus(Integer id, Integer onlineStatus);
+
+    /**
+     * 根据门店ID查询演出列表
+     *
+     * @param page    分页页数
+     * @param size    分页条数
+     * @param storeId 门店ID
+     * @param status  演出状态
+     * @return 演出列表
+     */
+    IPage<BarPerformance> queryPerformanceListByStoreId(Integer page, Integer size, Integer storeId, String status);
+
+    /**
+     * 根据门店ID和分类查询演出列表
+     *
+     * @param page    分页页数
+     * @param size    分页条数
+     * @param storeId 门店ID
+     * @param statusReview 审核状态(0-待审核 1-审核通过 2-审核拒绝)
+     * @param category 演出分类(all-全部, not_started-未开始, in_progress-进行中, ended-已结束)
+     * @param performanceName 演出名称(可选,支持模糊搜索)
+     * @return 演出列表
+     */
+    IPage<BarPerformance> queryPerformanceListByStoreIdAndCategory(Integer page, Integer size, Integer storeId, Integer statusReview, String category, String performanceName);
+}

+ 108 - 0
alien-store/src/main/java/shop/alien/store/service/impl/BarPerformanceAuditServiceImpl.java

@@ -0,0 +1,108 @@
+package shop.alien.store.service.impl;
+
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+import shop.alien.entity.store.BarPerformance;
+import shop.alien.mapper.BarPerformanceMapper;
+import shop.alien.store.service.BarPerformanceAuditService;
+import shop.alien.store.util.ai.AiContentModerationUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 酒吧演出审核服务实现类
+ * 负责异步执行AI内容审核
+ *
+ * @author assistant
+ * @since 2025-12-19
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class BarPerformanceAuditServiceImpl implements BarPerformanceAuditService {
+
+    private final BarPerformanceMapper barPerformanceMapper;
+    private final AiContentModerationUtil aiContentModerationUtil;
+
+    /**
+     * 异步执行AI内容审核
+     * 审核演出名称、演出详情、演出须知等文本内容以及演出海报、详情图片
+     *
+     * @param performanceId 演出ID
+     * @param barPerformance 演出信息
+     */
+    @Override
+    @Async("taskExecutor")
+    public void asyncAuditBarPerformance(Integer performanceId, BarPerformance barPerformance) {
+        try {
+            log.info("开始异步执行AI内容审核,演出ID:{}", performanceId);
+            
+            // 组装AI审核文本内容
+            StringBuilder textContent = new StringBuilder();
+            if (StringUtils.isNotEmpty(barPerformance.getPerformanceName())) {
+                textContent.append(barPerformance.getPerformanceName()).append(" ");
+            }
+            if (StringUtils.isNotEmpty(barPerformance.getPerformanceContent())) {
+                textContent.append(barPerformance.getPerformanceContent()).append(" ");
+            }
+            if (StringUtils.isNotEmpty(barPerformance.getPerformanceNotice())) {
+                textContent.append(barPerformance.getPerformanceNotice());
+            }
+            
+            // 组装图片URL列表
+            List<String> imageUrls = new ArrayList<>();
+            if (StringUtils.isNotEmpty(barPerformance.getPerformancePoster())) {
+                // 演出海报(可能有多张,逗号分隔)
+                String[] posterUrls = barPerformance.getPerformancePoster().split(",");
+                for (String url : posterUrls) {
+                    if (StringUtils.isNotEmpty(url.trim())) {
+                        imageUrls.add(url.trim());
+                    }
+                }
+            }
+            if (StringUtils.isNotEmpty(barPerformance.getPerformanceDetail())) {
+                // 演出详情图片(可能有多张,逗号分隔)
+                String[] detailUrls = barPerformance.getPerformanceDetail().split(",");
+                for (String url : detailUrls) {
+                    if (StringUtils.isNotEmpty(url.trim())) {
+                        imageUrls.add(url.trim());
+                    }
+                }
+            }
+            
+            // 调用AI审核接口
+            AiContentModerationUtil.AuditResult auditResult = aiContentModerationUtil.auditContent(
+                    textContent.toString().trim(), imageUrls);
+            
+            // 根据AI审核结果更新审核状态和拒绝原因
+            BarPerformance auditUpdate = new BarPerformance();
+            auditUpdate.setId(performanceId);
+            if (auditResult != null && auditResult.isPassed()) {
+                // 审核通过
+                auditUpdate.setReviewStatus(1);
+                auditUpdate.setRejectReason(null);
+                log.info("演出内容AI审核通过,演出ID:{}", performanceId);
+            } else {
+                // 审核失败
+                String reason = (auditResult != null && StringUtils.isNotEmpty(auditResult.getFailureReason()))
+                        ? auditResult.getFailureReason()
+                        : "审核未通过";
+                log.warn("演出内容AI审核失败,演出ID:{},原因:{}", performanceId, reason);
+                auditUpdate.setReviewStatus(2);
+                auditUpdate.setRejectReason(reason);
+            }
+            barPerformanceMapper.updateById(auditUpdate);
+            
+            log.info("AI内容审核完成,演出ID:{}", performanceId);
+            
+        } catch (Exception e) {
+            // AI审核异常不影响数据保存,记录日志即可
+            log.error("异步调用AI审核接口异常,演出ID:{}", performanceId, e);
+        }
+    }
+}
+

+ 489 - 0
alien-store/src/main/java/shop/alien/store/service/impl/BarPerformanceServiceImpl.java

@@ -0,0 +1,489 @@
+package shop.alien.store.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+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.mapper.BarPerformanceMapper;
+import shop.alien.store.service.BarPerformanceService;
+import shop.alien.store.util.ai.AiContentModerationUtil;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 酒吧演出服务实现类
+ * 实现酒吧演出的CRUD、审核、上下线等核心业务功能
+ *
+ * @author assistant
+ * @since 2025-12-17
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class BarPerformanceServiceImpl implements BarPerformanceService {
+
+    private final BarPerformanceMapper barPerformanceMapper;
+    private final AiContentModerationUtil aiContentModerationUtil;
+
+    @Override
+    public IPage<BarPerformance> getBarPerformanceList(int page, int size, String status) {
+        IPage<BarPerformance> performancePage = new Page<>(page, size);
+        QueryWrapper<BarPerformance> queryWrapper = new QueryWrapper<>();
+        // 根据状态查询演出
+        queryWrapper.like(StringUtils.isNotEmpty(status), "status", status);
+        // 只查询未删除的记录
+        queryWrapper.eq("delete_flag", 0);
+        // 按创建时间降序排序
+        queryWrapper.orderByDesc("created_time");
+        return barPerformanceMapper.selectPage(performancePage, queryWrapper);
+    }
+
+    @Override
+    public int addOrUpdateBarPerformance(BarPerformance barPerformance) {
+        // 1. 演出名称验证:必填且限20字
+        if (StringUtils.isEmpty(barPerformance.getPerformanceName())) {
+            throw new IllegalArgumentException("演出名称不能为空");
+        }
+        if (barPerformance.getPerformanceName().length() > 20) {
+            throw new IllegalArgumentException("演出名称长度不能超过20个字符");
+        }
+        
+        // 2. 演出海报验证:必填且限1张
+        if (StringUtils.isEmpty(barPerformance.getPerformancePoster())) {
+            throw new IllegalArgumentException("演出海报不能为空");
+        }
+        // 检查海报是否有多张(逗号分隔)
+        String[] posterImages = barPerformance.getPerformancePoster().split(",");
+        if (posterImages.length > 1) {
+            throw new IllegalArgumentException("演出海报最多只能上传1张");
+        }
+        
+        // 3. 演出类型和频次的关联验证:特邀演出(0)只能选单次(0)
+        if (barPerformance.getPerformanceType() != null && barPerformance.getPerformanceType() == 0) {
+            // 特邀演出
+            if (StringUtils.isEmpty(barPerformance.getPerformanceFrequency()) || !"0".equals(barPerformance.getPerformanceFrequency())) {
+                throw new IllegalArgumentException("特邀演出只能选择单次演出");
+            }
+        }
+        
+        // 4. 演出频次相关验证
+        String performanceFrequency = barPerformance.getPerformanceFrequency();
+        if (StringUtils.isEmpty(performanceFrequency)) {
+            throw new IllegalArgumentException("演出频次不能为空");
+        }
+        
+        // 获取今天的开始时间(用于时间验证)
+        java.util.Calendar cal = java.util.Calendar.getInstance();
+        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();
+        
+        switch (performanceFrequency) {
+            case "0": // 单次演出
+                if (barPerformance.getSingleStartDatetime() == null) {
+                    throw new IllegalArgumentException("单次演出必须填写开始时间");
+                }
+                if (barPerformance.getSingleEndDatetime() == null) {
+                    throw new IllegalArgumentException("单次演出必须填写结束时间");
+                }
+                // 验证开始时间必须是今天或以后
+                if (barPerformance.getSingleStartDatetime().before(todayStart)) {
+                    throw new IllegalArgumentException("开始时间必须是今天或以后");
+                }
+                // 确保开始时间早于结束时间
+                if (barPerformance.getSingleStartDatetime().after(barPerformance.getSingleEndDatetime())) {
+                    throw new IllegalArgumentException("开始时间不能晚于结束时间");
+                }
+                // 单次演出不需要周天数据,清除周天字段(设置为空字符串,确保数据库插入时包含该字段)
+                barPerformance.setPerformanceWeek("");
+                break;
+            case "1": // 每天定时
+                if (barPerformance.getDailyStartDate() == null) {
+                    throw new IllegalArgumentException("每天定时演出必须填写开始日期");
+                }
+                if (barPerformance.getDailyEndDate() == null) {
+                    throw new IllegalArgumentException("每天定时演出必须填写结束日期");
+                }
+                // 验证开始日期必须是今天或以后
+                if (barPerformance.getDailyStartDate().before(todayStart)) {
+                    throw new IllegalArgumentException("开始日期必须是今天或以后");
+                }
+                // 确保开始日期早于或等于结束日期
+                if (barPerformance.getDailyStartDate().after(barPerformance.getDailyEndDate())) {
+                    throw new IllegalArgumentException("开始日期不能晚于结束日期");
+                }
+                // 验证时间字段(复用single_start_datetime和single_end_datetime,只使用时间部分)
+                if (barPerformance.getSingleStartDatetime() == null) {
+                    throw new IllegalArgumentException("每天定时演出必须填写开始时间");
+                }
+                if (barPerformance.getSingleEndDatetime() == null) {
+                    throw new IllegalArgumentException("每天定时演出必须填写结束时间");
+                }
+                // 验证时间逻辑:开始时间必须早于结束时间(只比较时间部分,忽略日期部分)
+                if (!isTimeBefore(barPerformance.getSingleStartDatetime(), barPerformance.getSingleEndDatetime())) {
+                    throw new IllegalArgumentException("开始时间必须早于结束时间");
+                }
+                // 每天定时不需要周天数据,清除周天字段(设置为空字符串,确保数据库插入时包含该字段)
+                barPerformance.setPerformanceWeek("");
+                break;
+            case "2": // 每周定时
+                if (barPerformance.getDailyStartDate() == null) {
+                    throw new IllegalArgumentException("每周定时演出必须填写开始日期");
+                }
+                if (barPerformance.getDailyEndDate() == null) {
+                    throw new IllegalArgumentException("每周定时演出必须填写结束日期");
+                }
+                // 验证开始日期必须是今天或以后
+                if (barPerformance.getDailyStartDate().before(todayStart)) {
+                    throw new IllegalArgumentException("开始日期必须是今天或以后");
+                }
+                // 确保开始日期早于或等于结束日期
+                if (barPerformance.getDailyStartDate().after(barPerformance.getDailyEndDate())) {
+                    throw new IllegalArgumentException("开始日期不能晚于结束日期");
+                }
+                // 每周定时演出需要验证演出日期(周几)
+                if (StringUtils.isEmpty(barPerformance.getPerformanceWeek())) {
+                    throw new IllegalArgumentException("每周定时演出必须选择演出日期");
+                }
+                // 验证时间字段(复用single_start_datetime和single_end_datetime,只使用时间部分)
+                if (barPerformance.getSingleStartDatetime() == null) {
+                    throw new IllegalArgumentException("每周定时演出必须填写开始时间");
+                }
+                if (barPerformance.getSingleEndDatetime() == null) {
+                    throw new IllegalArgumentException("每周定时演出必须填写结束时间");
+                }
+                // 验证时间逻辑:开始时间必须早于结束时间(只比较时间部分,忽略日期部分)
+                if (!isTimeBefore(barPerformance.getSingleStartDatetime(), barPerformance.getSingleEndDatetime())) {
+                    throw new IllegalArgumentException("开始时间必须早于结束时间");
+                }
+                break;
+            default:
+                throw new IllegalArgumentException("演出频次类型无效");
+        }
+
+        // 5. 图文详情图片验证:最多9张
+        if (StringUtils.isNotEmpty(barPerformance.getPerformanceDetail())) {
+            String[] detailImages = barPerformance.getPerformanceDetail().split(",");
+            if (detailImages.length > 9) {
+                throw new IllegalArgumentException("图文详情图片最多只能上传9张");
+            }
+            // 检查每张图片URL格式是否有效
+            for (String imageUrl : detailImages) {
+                if (StringUtils.isEmpty(imageUrl.trim())) {
+                    throw new IllegalArgumentException("图文详情图片URL不能为空");
+                }
+            }
+        }
+
+        // 6. 演出须知字数验证:限300字
+        if (StringUtils.isNotEmpty(barPerformance.getPerformanceNotice()) && barPerformance.getPerformanceNotice().length() > 300) {
+            throw new IllegalArgumentException("演出须知不能超过300个字符");
+        }
+        
+        // 7. 图文详情文字验证:限300字(如果有performanceContent字段)
+        if (StringUtils.isNotEmpty(barPerformance.getPerformanceContent()) && barPerformance.getPerformanceContent().length() > 300) {
+            throw new IllegalArgumentException("图文详情文字不能超过300个字符");
+        }
+
+        // 8. 图文内容审核(调用AI内容审核接口)- 新增或更新时都必须进行
+        // - 文本:名称 + 详情 + 须知 + 风格(如果有)
+        // - 图片:海报URL(如果有) + 图文详情图片URL(如果有)
+        String moderationText = buildModerationText(barPerformance);
+        List<String> imageUrls = new ArrayList<>();
+        if (StringUtils.isNotEmpty(barPerformance.getPerformancePoster())) {
+            imageUrls.add(barPerformance.getPerformancePoster());
+        }
+        // 添加图文详情图片到审核列表
+        if (StringUtils.isNotEmpty(barPerformance.getPerformanceDetail())) {
+            String[] detailImages = barPerformance.getPerformanceDetail().split(",");
+            for (String imageUrl : detailImages) {
+                if (StringUtils.isNotEmpty(imageUrl.trim())) {
+                    imageUrls.add(imageUrl.trim());
+                }
+            }
+        }
+        // 调用AI内容审核接口,如果检测到违规内容会抛出异常
+        AiContentModerationUtil.AuditResult auditResult = aiContentModerationUtil.auditContent(moderationText, imageUrls);
+        if (auditResult == null || !auditResult.isPassed()) {
+            String failureReason = (auditResult != null && StringUtils.isNotEmpty(auditResult.getFailureReason()))
+                    ? auditResult.getFailureReason()
+                    : "内容包含违规信息";
+            log.warn("酒吧演出内容审核失败:{}", failureReason);
+            throw new IllegalArgumentException("内容审核未通过:" + failureReason);
+        }
+        log.info("酒吧演出内容审核通过");
+        
+        Integer id = barPerformance.getId();
+        
+        if (id == null || id == 0) {
+            // 新增操作
+            Date nowDate = new Date(System.currentTimeMillis());
+            barPerformance.setCreatedTime(nowDate);
+            // 设置删除标记为0(未删除)
+            if (barPerformance.getDeleteFlag() == null) {
+                barPerformance.setDeleteFlag(0);
+            }
+            // 设置默认状态为待审核(0)
+            if (barPerformance.getStatus() == null) {
+                barPerformance.setStatus(0);
+            }
+            // 设置默认审核状态为待审核(0),对应数据库字段 review_status
+            if (barPerformance.getReviewStatus() == null) {
+                barPerformance.setReviewStatus(0);
+            }
+            // 设置默认上线状态为下线(0)
+            if (barPerformance.getOnlineStatus() == null) {
+                barPerformance.setOnlineStatus(0);
+            }
+            // 设置默认隐藏状态为不隐藏(0)
+            if (barPerformance.getHidden() == null) {
+                barPerformance.setHidden(0);
+            }
+            // 重置id,让数据库自动生成
+            barPerformance.setId(null);
+            // 确保 performance_week 不为 null(如果为 null 则设置为空字符串,避免数据库插入错误)
+            if (barPerformance.getPerformanceWeek() == null) {
+                barPerformance.setPerformanceWeek("");
+            }
+            return barPerformanceMapper.insert(barPerformance);
+        } else {
+            // 更新操作:先查询记录是否存在
+            BarPerformance existing = barPerformanceMapper.selectById(id);
+            if (existing == null) {
+                // 记录不存在,转为新增操作
+                barPerformance.setId(null);
+                Date nowDate = new Date(System.currentTimeMillis());
+                barPerformance.setCreatedTime(nowDate);
+                // 设置默认值
+                if (barPerformance.getDeleteFlag() == null) {
+                    barPerformance.setDeleteFlag(0);
+                }
+                if (barPerformance.getStatus() == null) {
+                    barPerformance.setStatus(0);
+                }
+                if (barPerformance.getReviewStatus() == null) {
+                    barPerformance.setReviewStatus(0);
+                }
+                if (barPerformance.getOnlineStatus() == null) {
+                    barPerformance.setOnlineStatus(0);
+                }
+                if (barPerformance.getHidden() == null) {
+                    barPerformance.setHidden(0);
+                }
+                // 确保 performance_week 不为 null(如果为 null 则设置为空字符串,避免数据库插入错误)
+                if (barPerformance.getPerformanceWeek() == null) {
+                    barPerformance.setPerformanceWeek("");
+                }
+                return barPerformanceMapper.insert(barPerformance);
+            } else {
+                // 记录存在,执行更新
+                return barPerformanceMapper.updateById(barPerformance);
+            }
+        }
+    }
+
+    @Override
+    public BarPerformance getBarPerformanceDetail(Integer id) {
+        if (id == null || id <= 0) {
+            return null;
+        }
+        
+        QueryWrapper<BarPerformance> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("id", id);
+        queryWrapper.eq("delete_flag", 0);
+        
+        return barPerformanceMapper.selectOne(queryWrapper);
+    }
+
+    @Override
+    public Integer deleteBarPerformance(Integer id) {
+        if (id == null || id <= 0) {
+            return 0;
+        }
+        // 使用 MyBatis-Plus 的逻辑删除,会自动将 deleteFlag 设置为 1
+        return barPerformanceMapper.deleteById(id);
+    }
+
+    @Override
+    public Integer setOnlineStatus(Integer id, Integer onlineStatus) {
+        if (id == null || onlineStatus == null) {
+            return 0;
+        }
+        
+        LambdaUpdateWrapper<BarPerformance> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
+        lambdaUpdateWrapper.eq(BarPerformance::getId, id);
+        lambdaUpdateWrapper.set(BarPerformance::getOnlineStatus, onlineStatus);
+        
+        return barPerformanceMapper.update(null, lambdaUpdateWrapper);
+    }
+
+    @Override
+    public IPage<BarPerformance> queryPerformanceListByStoreId(Integer page, Integer size, Integer storeId, String status) {
+        // 使用新的方法,支持按审核状态和分类筛选
+        // status参数转换为reviewStatus(对应数据库字段 review_status)
+        Integer reviewStatus = null;
+        if (StringUtils.isNotEmpty(status)) {
+            try {
+                reviewStatus = Integer.parseInt(status);
+            } catch (NumberFormatException e) {
+                // 忽略无效的状态值
+            }
+        }
+        return queryPerformanceListByStoreIdAndCategory(page, size, storeId, reviewStatus, "all", null);
+    }
+
+    @Override
+    public IPage<BarPerformance> queryPerformanceListByStoreIdAndCategory(Integer page, Integer size, Integer storeId, Integer reviewStatus, String category, String performanceName) {
+        if (page == null || size == null || storeId == null || storeId <= 0) {
+            return new Page<>();
+        }
+        
+        IPage<BarPerformance> performancePage = new Page<>(page, size);
+        QueryWrapper<BarPerformance> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("store_id", storeId);
+        
+        // 按演出名称搜索(支持模糊搜索)
+        if (StringUtils.isNotEmpty(performanceName)) {
+            queryWrapper.like("performance_name", performanceName);
+        }
+        
+        // 按审核状态筛选(数据库字段 review_status)
+        if (reviewStatus != null) {
+            queryWrapper.eq("review_status", reviewStatus);
+        } else {
+            // 不查询草稿(review_status为null的记录)
+            queryWrapper.isNotNull("review_status");
+        }
+        
+        // 按演出分类筛选
+        if (StringUtils.isNotEmpty(category) && !"all".equals(category)) {
+            Date now = new Date();
+            // 获取今天的开始时间(00:00:00)
+            java.util.Calendar cal = java.util.Calendar.getInstance();
+            cal.setTime(now);
+            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();
+            
+            switch (category) {
+                case "not_started": // 未开始
+                    queryWrapper.and(wrapper -> {
+                        // 单次演出:开始时间 > 现在
+                        wrapper.or(w -> w.eq("performance_frequency", "0")
+                                .gt("single_start_datetime", now));
+                        // 定时演出:开始日期 > 今天 或 (开始日期 = 今天 但还未到演出时间)
+                        wrapper.or(w -> w.in("performance_frequency", "1", "2")
+                                .gt("daily_start_date", todayStart));
+                    });
+                    break;
+                case "in_progress": // 进行中
+                    queryWrapper.and(wrapper -> {
+                        // 单次演出:开始时间 <= 现在 AND 结束时间 >= 现在
+                        wrapper.or(w -> w.eq("performance_frequency", "0")
+                                .le("single_start_datetime", now)
+                                .ge("single_end_datetime", now));
+                        // 定时演出:开始日期 <= 今天 AND 结束日期 >= 今天
+                        wrapper.or(w -> w.in("performance_frequency", "1", "2")
+                                .le("daily_start_date", todayStart)
+                                .ge("daily_end_date", todayStart));
+                    });
+                    break;
+                case "ended": // 已结束
+                    queryWrapper.and(wrapper -> {
+                        // 单次演出:结束时间 < 现在
+                        wrapper.or(w -> w.eq("performance_frequency", "0")
+                                .lt("single_end_datetime", now));
+                        // 定时演出:结束日期 < 今天
+                        wrapper.or(w -> w.in("performance_frequency", "1", "2")
+                                .lt("daily_end_date", todayStart));
+                    });
+                    break;
+                default:
+                    // 其他情况,不添加额外条件
+                    break;
+            }
+        }
+        
+        queryWrapper.eq("delete_flag", 0);
+        // 按提交时间(创建时间)倒序排序
+        queryWrapper.orderByDesc("created_time");
+        
+        return barPerformanceMapper.selectPage(performancePage, queryWrapper);
+    }
+
+    /**
+     * 比较两个时间(只比较时间部分,忽略日期部分)
+     * 用于每天定时和每周定时演出的时间验证
+     * 
+     * @param time1 开始时间
+     * @param time2 结束时间
+     * @return true表示time1早于time2,false表示time1晚于或等于time2
+     */
+    private boolean isTimeBefore(Date time1, Date time2) {
+        if (time1 == null || time2 == null) {
+            return false;
+        }
+        java.util.Calendar cal1 = java.util.Calendar.getInstance();
+        cal1.setTime(time1);
+        int hour1 = cal1.get(java.util.Calendar.HOUR_OF_DAY);
+        int minute1 = cal1.get(java.util.Calendar.MINUTE);
+        int second1 = cal1.get(java.util.Calendar.SECOND);
+        
+        java.util.Calendar cal2 = java.util.Calendar.getInstance();
+        cal2.setTime(time2);
+        int hour2 = cal2.get(java.util.Calendar.HOUR_OF_DAY);
+        int minute2 = cal2.get(java.util.Calendar.MINUTE);
+        int second2 = cal2.get(java.util.Calendar.SECOND);
+        
+        // 比较小时
+        if (hour1 < hour2) {
+            return true;
+        } else if (hour1 > hour2) {
+            return false;
+        }
+        
+        // 小时相同,比较分钟
+        if (minute1 < minute2) {
+            return true;
+        } else if (minute1 > minute2) {
+            return false;
+        }
+        
+        // 分钟相同,比较秒
+        return second1 < second2;
+    }
+
+    private String buildModerationText(BarPerformance barPerformance) {
+        StringBuilder sb = new StringBuilder();
+        if (barPerformance == null) {
+            return "";
+        }
+        if (StringUtils.isNotEmpty(barPerformance.getPerformanceName())) {
+            sb.append("演出名称:").append(barPerformance.getPerformanceName()).append("\n");
+        }
+        if (StringUtils.isNotEmpty(barPerformance.getPerformanceStyle())) {
+            sb.append("演出风格:").append(barPerformance.getPerformanceStyle()).append("\n");
+        }
+        if (StringUtils.isNotEmpty(barPerformance.getPerformanceContent())) {
+            sb.append("演出详情:").append(barPerformance.getPerformanceContent()).append("\n");
+        }
+        if (StringUtils.isNotEmpty(barPerformance.getPerformanceNotice())) {
+            sb.append("演出须知:").append(barPerformance.getPerformanceNotice()).append("\n");
+        }
+        if (StringUtils.isNotEmpty(barPerformance.getPerformanceDetail())) {
+            sb.append("图文详情:").append(barPerformance.getPerformanceDetail()).append("\n");
+        }
+        return sb.toString();
+    }
+}

+ 6 - 6
alien-store/src/main/java/shop/alien/store/util/ai/AiContentModerationUtil.java

@@ -73,7 +73,7 @@ public class AiContentModerationUtil {
 
         } catch (Exception e) {
             log.error("审核内容异常", e);
-            return new AuditResult(false, "审核服务异常" + e.getMessage());
+            return new AuditResult(false, "审核异常");
         }
     }
 
@@ -121,16 +121,16 @@ public class AiContentModerationUtil {
                     return parseAuditResult(jsonResponse);
                 } else {
                     log.error("AI审核接口返回空响应");
-                    return new AuditResult(false, "审核服务返回空响应");
+                    return new AuditResult(false, "审核异常");
                 }
             } else {
                 log.error("AI审核接口调用失败,状态码:{}", response.getStatusCode());
-                return new AuditResult(false, "审核服务调用失败,状态码:" + response.getStatusCode());
+                return new AuditResult(false, "审核异常");
             }
 
         } catch (Exception e) {
             log.error("调用AI审核接口异常", e);
-            return new AuditResult(false, "审核服务调用异常" + e.getMessage());
+            return new AuditResult(false, "审核异常");
         }
     }
 
@@ -159,7 +159,7 @@ public class AiContentModerationUtil {
             com.alibaba.fastjson2.JSONArray results = jsonResponse.getJSONArray("results");
             if (results == null || results.isEmpty()) {
                 log.warn("AI审核接口返回结果为空");
-                return new AuditResult(false, "审核结果为空");
+                return new AuditResult(false, "审核异常");
             }
 
             // 检查是否有任何项目被标记为违规
@@ -199,7 +199,7 @@ public class AiContentModerationUtil {
 
         } catch (Exception e) {
             log.error("解析审核结果异常", e);
-            return new AuditResult(false, "解析审核结果异常" + e.getMessage());
+            return new AuditResult(false, "审核异常");
         }
     }
 }