Pārlūkot izejas kodu

Merge branch 'master' of http://git.zonelife.cn:3000/huangyang/national-motion-backend

# Conflicts:
#	national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/IDetailService.java
#	national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/impl/DetailServiceImpl.java
zhangxin 2 nedēļas atpakaļ
vecāks
revīzija
5feeaff1c2
13 mainītis faili ar 321 papildinājumiem un 124 dzēšanām
  1. 15 4
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/controller/AppDetailController.java
  2. 9 1
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/IDetailService.java
  3. 24 14
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/impl/DetailServiceImpl.java
  4. 5 5
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/vo/CourseInfoVO.java
  5. 1 1
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/vo/PlaceInfoVO.java
  6. 6 0
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/entity/AppSitePlace.java
  7. 10 32
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/entity/AppSitePriceRules.java
  8. 2 0
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/mapper/xml/AppCoursesMapper.xml
  9. 1 1
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/mapper/xml/AppCoursesPriceRulesMapper.xml
  10. 4 3
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/mapper/xml/AppSiteMapper.xml
  11. 13 5
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/mapper/xml/AppSitePlaceMapper.xml
  12. 51 45
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/mapper/xml/AppSitePriceRulesMapper.xml
  13. 180 13
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/service/impl/AppSitePlaceServiceImpl.java

+ 15 - 4
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/controller/AppDetailController.java

@@ -8,6 +8,7 @@ import org.jeecg.common.api.vo.Result;
 import org.jeecg.modules.app.service.IDetailService;
 import org.jeecg.modules.app.vo.CourseInfoVO;
 import org.jeecg.modules.app.vo.PlaceInfoVO;
+import org.jeecg.modules.system.app.entity.AppCategory;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
@@ -16,7 +17,7 @@ import org.springframework.web.bind.annotation.RestController;
 import javax.annotation.Resource;
 import java.util.List;
 @Slf4j
-@Tag(name = "App首页相关接口")
+@Tag(name = "App详情相关接口")
 @RestController
 @RequestMapping("/app/detail")
 public class AppDetailController {
@@ -52,13 +53,12 @@ public class AppDetailController {
      * @Author SheepHy
      * @Description 根据课程类型查询课程列表
      * @Date 9:52 2025/7/9
-     * @Param type 课程类型
      * @return List<PlaceInfoVO.CourseInfoVO>
      **/
     @GetMapping("/courseInfoVOList")
     @Operation(summary = "根据课程类型查询课程列表")
-    public Result<List<PlaceInfoVO.CourseInfoVO>> courseInfoVOList(@RequestParam @Schema(description="课程类型")String type, @RequestParam @Schema(description="课程ID")String id){
-        return Result.ok(detailService.courseInfoVOList(type, id));
+    public Result<List<PlaceInfoVO.CourseInfoVO>> courseInfoVOList(@RequestParam @Schema(description="类目id")String categoryId, @RequestParam @Schema(description="店铺ID")String id){
+        return Result.ok(detailService.courseInfoVOList(categoryId,id));
     }
 
     /**
@@ -73,4 +73,15 @@ public class AppDetailController {
     public Result<PlaceInfoVO.theGymnasiumIsCharteredVO> getPlaceInfoNoFixation(@RequestParam @Schema(description="门店ID")String id, @RequestParam @Schema(description="类目")String categoryId){
         return Result.ok(detailService.getPlaceInfoNoFixation(id, categoryId));
     }
+
+    /**
+     * @Author SheepHy
+     * @Description 获取所有类目
+     * @Date 10:14 2025/7/9
+     **/
+    @GetMapping("/getAllCategory")
+    @Operation(summary = "获取所有类目")
+    public Result<List<AppCategory>> getAllCategory(@RequestParam @Schema(description="门店ID")String id){
+        return Result.ok(detailService.getAllCategory(id));
+    }
 }

+ 9 - 1
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/IDetailService.java

@@ -3,6 +3,7 @@ package org.jeecg.modules.app.service;
 import org.jeecg.common.api.vo.Result;
 import org.jeecg.modules.app.vo.CourseInfoVO;
 import org.jeecg.modules.app.vo.PlaceInfoVO;
+import org.jeecg.modules.system.app.entity.AppCategory;
 import org.jeecg.modules.app.vo.stadium.StadiumConcertsVO;
 
 import java.util.List;
@@ -33,7 +34,7 @@ public interface IDetailService {
      * @Param type 课程类型
      * @return List<PlaceInfoVO.CourseInfoVO>
      **/
-    List<PlaceInfoVO.CourseInfoVO> courseInfoVOList(String type, String id);
+    List<PlaceInfoVO.CourseInfoVO> courseInfoVOList(String categoryId,String id);
     
     /** 
      * @Author SheepHy
@@ -45,4 +46,11 @@ public interface IDetailService {
     PlaceInfoVO.theGymnasiumIsCharteredVO getPlaceInfoNoFixation(String id, String categoryId);
 
     Result<List<StadiumConcertsVO>> findConcerts(String siteId, String categoryId);
+
+    /**
+     * @Author SheepHy
+     * @Description 获取所有类目
+     * @Date 10:14 2025/7/9
+     **/
+    List<AppCategory> getAllCategory(String id);
 }

+ 24 - 14
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/impl/DetailServiceImpl.java

@@ -74,17 +74,17 @@ public class DetailServiceImpl implements IDetailService {
             List<PlaceInfoVO.PlaceInfoMsgVO> placeInfoMsgVOS = new ArrayList<>();
             appSitePlaceMapper.selectList(Wrappers.<AppSitePlace>lambdaQuery().eq(AppSitePlace::getSiteId, id)
                     .eq(AppSitePlace::getType,0)).forEach(appSitePlace -> {
-                appSitePriceRulesMapper.selectList(Wrappers.<AppSitePriceRules>lambdaQuery()
-                        .eq(AppSitePriceRules::getSitePlaceId, id)
-                        .eq(AppSitePriceRules::getStatus, 0)
-                        .eq(AppSitePriceRules::getType,0)).forEach(appSitePriceRules -> {
-                    PlaceInfoVO.PlaceInfoMsgVO placeInfoMsgVO = new PlaceInfoVO.PlaceInfoMsgVO();
-                    placeInfoMsgVO.setName(appSite.getName())
-                            .setSales(getPlaceSales(id))
-                            .setOriginalPrice(appSitePriceRules.getOriginalPrice())
-                            .setSellingPrice(appSitePriceRules.getSellingPrice());
-                    placeInfoMsgVOS.add(placeInfoMsgVO);
-                });
+                PlaceInfoVO.PlaceInfoMsgVO placeInfoMsgVO = new PlaceInfoVO.PlaceInfoMsgVO();
+                placeInfoMsgVO.setName(appSitePlace.getName())
+                        .setSales(getPlaceSales(id))
+                        .setOriginalPrice(appSitePriceRulesMapper.selectOne(Wrappers.<AppSitePriceRules>lambdaQuery()
+                                .eq(AppSitePriceRules::getSitePlaceId, appSitePlace.getId())
+                                .last("limit 1").orderByDesc(AppSitePriceRules::getOriginalPrice)).getOriginalPrice())
+                        .setSellingPrice(appSitePriceRulesMapper.selectOne(Wrappers.<AppSitePriceRules>lambdaQuery()
+                                .eq(AppSitePriceRules::getSitePlaceId, appSitePlace.getId())
+                                .last("limit 1").orderByDesc(AppSitePriceRules::getSellingPrice)).getSellingPrice())
+                        .setCategory(getCategoryName(appSitePlace.getCategoryId()));
+                placeInfoMsgVOS.add(placeInfoMsgVO);
             });
             placeInfo.setPlaceInfoMsgVO(placeInfoMsgVOS);
             return placeInfo;
@@ -108,7 +108,7 @@ public class DetailServiceImpl implements IDetailService {
         appCoursesPriceRulesMapper.selectList(Wrappers.<AppCoursesPriceRules>lambdaQuery()
                 .eq(AppCoursesPriceRules::getCoursesId, courseInfoVO.getId())).forEach(appCourses -> {
             CourseInfoVO.CourseDetailVO courseDetailVO = new CourseInfoVO.CourseDetailVO();
-            BeanUtils.copyProperties(courseDetailVO, appCourses);
+            BeanUtils.copyProperties(appCourses,courseDetailVO);
             courseDetailVOList.add(courseDetailVO);
         });
         courseInfoVO.setCourseDetail(courseDetailVOList);
@@ -116,18 +116,20 @@ public class DetailServiceImpl implements IDetailService {
     }
 
     @Override
-    public List<PlaceInfoVO.CourseInfoVO> courseInfoVOList(String type, String id) {
+    public List<PlaceInfoVO.CourseInfoVO> courseInfoVOList(String categoryId,String id) {
         LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
         List<PlaceInfoVO.CourseInfoVO> courseInfoVOList = new ArrayList<>();
         appCoursesMapper.selectList(Wrappers.<AppCourses>lambdaQuery()
                 .eq(AppCourses::getSiteId, id)
+                .like(AppCourses::getCategoryId, categoryId)
                 .eq(AppCourses::getStatus, 0)
                 .eq(AppCourses::getDelFlag, 0)).forEach(appCourses -> {
             PlaceInfoVO.CourseInfoVO courseInfoVO = new PlaceInfoVO.CourseInfoVO();
-            BeanUtils.copyProperties(courseInfoVO, appCourses);
+            BeanUtils.copyProperties(appCourses, courseInfoVO);
             courseInfoVO.setSales(getCourseSalesCount(appCourses.getId()));
             courseInfoVO.setSalesYear(getCourseSales(appCourses.getId()));
             courseInfoVO.setPriceType(isFirstPurchase(user.getId()));
+            courseInfoVO.setAddress(appSiteMapper.selectById(appCourses.getSiteId()).getAddress());
             courseInfoVOList.add(courseInfoVO);
         });
         return courseInfoVOList;
@@ -167,6 +169,14 @@ public class DetailServiceImpl implements IDetailService {
         return Result.ok(stadiumConcertsVOS);
     }
 
+    @Override
+    public List<AppCategory> getAllCategory(String id) {
+        AppSite appSite = appSiteMapper.selectById(id);
+        return appCategoryMapper.selectList(Wrappers.<AppCategory>lambdaQuery()
+                .eq(AppCategory::getStatus,0).eq(AppCategory::getOrgCode,appSite.getOrgCode())
+                .eq(AppCategory::getDelFlag,0));
+    }
+
     /**
      * @return
      * @Author SheepHy

+ 5 - 5
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/vo/CourseInfoVO.java

@@ -43,11 +43,11 @@ public class CourseInfoVO {
     @Schema(description = "课时")
     private Integer classHour;
     @Schema(description = "限购次数")
-    private Integer limitNum;
+    private String limitNum;
     @Schema(description = "服务详情")
-    private Integer details;
+    private String details;
     @Schema(description = "适用人群")
-    private Integer fitPeople;
+    private String fitPeople;
     @Schema(description = "提示/须知")
     private String reminder;
     @Schema(description = "课程明细")
@@ -59,9 +59,9 @@ public class CourseInfoVO {
     @Schema(description="课程明细返回参数")
     public static class CourseDetailVO {
         @Schema(description = "课程id")
-        private String courseId;
+        private String id;
         @Schema(description = "课程名称")
-        private String courseName;
+        private String name;
         @Schema(description = "开始时间")
         private Date startTime;
         @Schema(description = "结束时间")

+ 1 - 1
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/vo/PlaceInfoVO.java

@@ -20,7 +20,7 @@ public class PlaceInfoVO {
     @Schema(description = "好评率")
     private BigDecimal goodRate;
     @Schema(description = "是否营业")
-    private Boolean isOpen;
+    private Boolean runStatus;
     @Schema(description = "封面")
     private String cover;
     @Schema(description = "地址")

+ 6 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/entity/AppSitePlace.java

@@ -53,6 +53,10 @@ public class AppSitePlace implements Serializable {
     @Excel(name = "名称", width = 15)
     @Schema(description = "名称")
     private String name;
+    /**运动类型*/
+    @Excel(name = "运动类型", width = 15)
+    @Schema(description = "运动类型")
+    private String CategoryId;
 	/**乐观锁*/
 	@Excel(name = "乐观锁", width = 15)
     @Schema(description = "乐观锁")
@@ -127,4 +131,6 @@ public class AppSitePlace implements Serializable {
     @Schema(description = "有效期;单位:天")
     private Integer indate;
 
+
+
 }

+ 10 - 32
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/entity/AppSitePriceRules.java

@@ -1,19 +1,20 @@
 package org.jeecg.modules.system.app.entity;
 
-import java.io.Serializable;
-import java.util.Date;
-import java.math.BigDecimal;
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.annotation.TableLogic;
-import lombok.Data;
+import com.baomidou.mybatisplus.annotation.TableName;
 import com.fasterxml.jackson.annotation.JsonFormat;
-import org.springframework.format.annotation.DateTimeFormat;
-import org.jeecgframework.poi.excel.annotation.Excel;
 import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
+import org.jeecgframework.poi.excel.annotation.Excel;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
 
 /**
  * @Description: 场地价格规则表
@@ -22,7 +23,7 @@ import lombok.experimental.Accessors;
  * @Version: V1.0
  */
 @Data
-@TableName("nm_site_peice_rules")
+@TableName("nm_site_price_rules")
 @Accessors(chain = true)
 @EqualsAndHashCode(callSuper = false)
 @Schema(description="场地价格规则表")
@@ -85,30 +86,7 @@ public class AppSitePriceRules implements Serializable {
     @Excel(name = "展示状态(0正常,1已定,2过期)", width = 15)
     @Schema(description = "展示状态(0正常,1已定,2过期)")
     private Integer viewStatus;
-    /**退款类型;0可退/到期自动退 1限时退 2不可退*/
-    @Excel(name = "退款类型;0可退/到期自动退 1限时退 2不可退", width = 15)
-    @Schema(description = "退款类型;0可退/到期自动退 1限时退 2不可退")
-    private Integer refundType;
-    /**体育馆包场提前退款时间;单位:分钟*/
-    @Excel(name = "体育馆包场提前退款时间;单位:分钟", width = 15)
-    @Schema(description = "体育馆包场提前退款时间;单位:分钟")
-    private Integer earlyRefundTime;
-    /**适用人数*/
-    @Excel(name = "适用人数", width = 15)
-    @Schema(description = "适用人数")
-    private Integer usableCount;
-    /**提示/须知*/
-    @Excel(name = "提示/须知", width = 15)
-    @Schema(description = "提示/须知")
-    private String reminder;
-    /**不可用日期;多个逗号分割*/
-    @Excel(name = "不可用日期;多个逗号分割", width = 15)
-    @Schema(description = "不可用日期;多个逗号分割")
-    private String downTime;
-    /**提前预约时间:0免预约 单位:时*/
-    @Excel(name = "提前预约时间:0免预约 单位:时", width = 15)
-    @Schema(description = "提前预约时间:0免预约 单位:时")
-    private Integer advanceTime;
+
     /**乐观锁*/
     @Excel(name = "乐观锁", width = 15)
     @Schema(description = "乐观锁")

+ 2 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/mapper/xml/AppCoursesMapper.xml

@@ -45,7 +45,9 @@
             a.cover,
             a.video,
             b.address,
+            a.details,
             a.site_id,
+            a.fit_people,
             a.start_time,
             a.end_time,
             COUNT( c.id ) AS classHour,

+ 1 - 1
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/mapper/xml/AppCoursesPriceRulesMapper.xml

@@ -2,6 +2,6 @@
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="org.jeecg.modules.system.app.mapper.AppCoursesPriceRulesMapper">
     <select id="selectRuleIdsByCourseId" resultType="string">
-        SELECT id FROM app_courses_price_rules WHERE courses_id = #{coursesId}
+        SELECT id FROM nm_courses_price_rules WHERE courses_id = #{coursesId}
     </select>
 </mapper>

+ 4 - 3
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/mapper/xml/AppSiteMapper.xml

@@ -63,15 +63,16 @@
     <select id="getPlaceInfo" resultType="org.jeecg.modules.app.vo.PlaceInfoVO">
         SELECT
             a.id,
-            b.depart_name,
+            b.depart_name AS name,
             a.good_rate,
             a.cover,
-            b.address,
+            a.address,
             a.type,
             a.facility,
+            a.run_status AS runStatus,
             a.teaching_day,
             a.no_teaching_day,
-            b.mobile,
+            b.mobile AS phone,
             a.video
         FROM
             nm_site a

+ 13 - 5
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/mapper/xml/AppSitePlaceMapper.xml

@@ -16,14 +16,22 @@
     <select id="getPlaceInfoNoFixation" resultType="org.jeecg.modules.app.vo.PlaceInfoVO$PlaceInfoGymMsgVO">
         SELECT
             a.id,
-            a.`name`,
+            a.name,
             a.advance_time,
-            b.original_price,
-            b.selling_price
+            MIN(b.original_price) AS original_price,
+            MAX(b.selling_price) AS selling_price
         FROM
             nm_site_place a
-                LEFT JOIN nm_site_peice_rules b ON a.id = b.site_place_id WHERE a.site_id = #{id} AND a.type != 0 ORDER BY
-            b.selling_price ASC
+                LEFT JOIN nm_site_price_rules b ON a.id = b.site_place_id
+        WHERE
+            a.site_id = #{id}
+          AND a.type != 0
+        GROUP BY
+            a.id,
+            a.name,
+            a.advance_time
+        ORDER BY
+            selling_price ASC;
     </select>
     <select id="findByConcerts" resultMap="ConcertsVOResult" >
         select b.site_place_id,a.name as site_place_name,

+ 51 - 45
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/mapper/xml/AppSitePriceRulesMapper.xml

@@ -3,52 +3,58 @@
 <mapper namespace="org.jeecg.modules.system.app.mapper.AppSitePriceRulesMapper">
     <select id="theGymnasiumIsCharteredInfo" resultType="org.jeecg.modules.app.vo.PlaceInfoVO$theGymnasiumIsCharteredInfoVO">
         WITH RECURSIVE dates AS (
-            SELECT
-                0 AS offset_day,
-                CURDATE() AS date_val,
-                DAYOFWEEK(CURDATE()) - 1 AS dow
-            UNION ALL
-            SELECT
-                offset_day + 1,
-                date_val + INTERVAL 1 DAY,
-            DAYOFWEEK(date_val + INTERVAL 1 DAY) - 1
-        FROM dates
-        WHERE offset_day &lt; 6
-            ),
-            earliest_slots AS (
         SELECT
-            sp.site_id,
-            r.start_time,
-            r.end_time,
-            r.selling_price,
-            r.day_of_week,
-            ROW_NUMBER() OVER (PARTITION BY r.day_of_week ORDER BY r.start_time) AS rn
-        FROM nm_site_peice_rules r
-            LEFT JOIN nm_site_place sp ON r.site_place_id = sp.id
-        WHERE r.view_status = 0
-          AND r.org_code = #{orgCode}
-          AND r.category_id = #{categoryId}
-            )
+        1 AS offset_day,
+        CURDATE() AS date_val,
+        DAYOFWEEK(
+        CURDATE()) - 1 AS dow UNION ALL
         SELECT
-            es.site_id AS id,
-            es.start_time AS startTime,
-            CONCAT(es.start_time, '-', es.end_time) AS time_range,
-            es.selling_price AS sellingPrice,
-            CASE
-                WHEN dm.offset_day = 0 THEN CONCAT('今天(', DATE_FORMAT(dm.date_val, '%m-%d'), ')')
-                WHEN dm.offset_day = 1 THEN CONCAT('明天(', DATE_FORMAT(dm.date_val, '%m-%d'), ')')
-                WHEN dm.offset_day = 2 THEN CONCAT('后天(', DATE_FORMAT(dm.date_val, '%m-%d'), ')')
-                ELSE CONCAT(
-                        ELT(dm.dow + 1, '星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日'),
-                        '(', DATE_FORMAT(dm.date_val, '%m-%d'), ')'
-                     )
-                END AS date_label
-        FROM earliest_slots es
-                 JOIN (
-            SELECT offset_day, date_val, dow
-            FROM dates
-        ) AS dm ON es.day_of_week = dm.dow
-        WHERE es.rn = 1
-        ORDER BY dm.offset_day;
+        offset_day + 1,
+        date_val + INTERVAL 1 DAY,
+        DAYOFWEEK( date_val + INTERVAL 0 DAY )
+        FROM
+        dates
+        WHERE
+        offset_day &lt; 7
+        ),
+        earliest_slots AS (
+        SELECT
+        sp.site_id,
+        r.start_time,
+        r.end_time,
+        r.selling_price,
+        r.day_of_week,
+        ROW_NUMBER() OVER ( PARTITION BY r.day_of_week ORDER BY r.start_time ) AS rn
+        FROM
+        nm_site_price_rules r
+        LEFT JOIN nm_site_place sp ON r.site_place_id = sp.id
+        WHERE
+        r.view_status = 0
+        ) SELECT
+        es.site_id AS id,
+        es.start_time AS startTime,
+        CONCAT( es.start_time, '-', es.end_time ) AS time_range,
+        es.selling_price AS sellingPrice,
+        CASE
+
+        WHEN dm.offset_day = 1 THEN
+        CONCAT( '今  天 (', DATE_FORMAT( dm.date_val, '%m-%d' ), ')' )
+        WHEN dm.offset_day = 2 THEN
+        CONCAT( '明  天 (', DATE_FORMAT( dm.date_val, '%m-%d' ), ')' )
+        WHEN dm.offset_day = 3 THEN
+        CONCAT( '后  天 (', DATE_FORMAT( dm.date_val, '%m-%d' ), ')' ) ELSE CONCAT(
+        ELT( dm.dow, '星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日' ),
+        '(',
+        DATE_FORMAT( dm.date_val, '%m-%d' ),
+        ')'
+        )
+        END AS date_label
+        FROM
+        earliest_slots es
+        JOIN ( SELECT offset_day, date_val, dow FROM dates ) AS dm ON es.day_of_week = dm.dow
+        WHERE
+        es.rn = 1
+        ORDER BY
+        dm.offset_day;
     </select>
 </mapper>

+ 180 - 13
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/service/impl/AppSitePlaceServiceImpl.java

@@ -27,7 +27,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
-import java.util.List;
+import java.util.*;
 import java.util.stream.Collectors;
 
 import static org.jeecg.common.constant.CommonConstant.SC_INTERNAL_SERVER_ERROR_500;
@@ -64,13 +64,20 @@ public class AppSitePlaceServiceImpl extends ServiceImpl<AppSitePlaceMapper, App
         appSitePlace.setSiteId(site.getId());
         //时间段提取拼接
         List<AppSiteRuleDTO> siteRuleDTOS = placeDTO.getSiteRuleDTOS();
-        String  teachingDay= "";
-        String  noTeachingDay= "";
-        if (!siteRuleDTOS.isEmpty()) {
 
+        List<String>  teachingDay= new ArrayList<>() ;
+        List<String>   noTeachingDay= new ArrayList<>() ;
+        if (!siteRuleDTOS.isEmpty()) {
+            siteRuleDTOS.forEach(dto -> {
+                if (dto.getIsTeaching() == 0) {
+                    teachingDay.add(dto.getStartTime() + "-"+dto.getEndTime());
+                } else {
+                    noTeachingDay.add(dto.getStartTime() + "-"+dto.getEndTime());
+                }
+            });
         }
-        site.setTeachingDay(teachingDay);
-        site.setNoTeachingDay(noTeachingDay);
+        site.setTeachingDay(String.join(",", teachingDay));
+        site.setNoTeachingDay(String.join(",", noTeachingDay));
         int updateById = appSiteMapper.updateById(site);
         if (updateById < 1) {
             throw new JeecgBootException("学校补充信息更新失败");
@@ -101,6 +108,7 @@ public class AppSitePlaceServiceImpl extends ServiceImpl<AppSitePlaceMapper, App
         LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
         if (null == appSitePlaceCuDTO.getSiteId())
             throw new JeecgBootException("商户补充信息id不能为空", SC_INTERNAL_SERVER_ERROR_500);
+        AppSite site = appSiteMapper.selectById(appSitePlaceCuDTO.getSiteId());
         AppSitePlace dbPlace = baseMapper.selectById(appSitePlaceCuDTO.getSiteId());
         if (null == dbPlace) throw new JeecgBootException("数据不存在", SC_INTERNAL_SERVER_ERROR_500);
         //部门校验
@@ -108,9 +116,9 @@ public class AppSitePlaceServiceImpl extends ServiceImpl<AppSitePlaceMapper, App
         AppSitePlace appSitePlace = new AppSitePlace();
         BeanUtils.copyProperties(appSitePlaceCuDTO, appSitePlace);
         //不许更改项赋值
-        appSitePlace.setOrgCode(sysUser.getOrgCode());
-        appSitePlace.setTenantId(sysUser.getOrgId());
-        appSitePlace.setSiteId(appSitePlaceCuDTO.getSiteId());
+        appSitePlace.setOrgCode(site.getOrgCode());
+        appSitePlace.setTenantId(site.getTenantId());
+        appSitePlace.setSiteId(site.getId());
         int update = baseMapper.updateById(appSitePlace);
         if (update < 1) {
             throw new JeecgBootException("商户场所保存失败");
@@ -313,20 +321,179 @@ public class AppSitePlaceServiceImpl extends ServiceImpl<AppSitePlaceMapper, App
 
         return appSitePlaceUnfixedDTO;
     }
-
+//包场
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public Boolean savePack(AppSitePlaceDTO placeDTO) {
-        return null;
+        AppSitePlaceCuDTO placeCuDTO = placeDTO.getAppSitePlaceCuDTO();
+        List<AppSiteRuleDTO> siteRuleDTOS = placeDTO.getSiteRuleDTOS();
+        AppSite site = appSiteMapper.selectById(placeCuDTO.getSiteId());
+        placeDTO.getSiteCategoryDOTS().forEach(item -> {
+            AppCategory category = appCategoryMapper.selectById(item.getCategoryId());
+            for (int i = 0; i < item.getCount(); i++) {
+                AppSitePlace appSitePlace = new AppSitePlace();
+                BeanUtils.copyProperties(placeCuDTO,appSitePlace);
+                appSitePlace.setType(SitePlaceTypeEnum.PACKAGE.getCode());
+                appSitePlace.setName(category.getName()+(i+1));
+                appSitePlace.setOrgCode(site.getOrgCode());
+                appSitePlace.setTenantId(site.getTenantId());
+                int insert = baseMapper.insert(appSitePlace);
+                if (insert < 1) throw new JeecgBootException("包场保存失败", SC_INTERNAL_SERVER_ERROR_500);
+                siteRuleDTOS.stream().filter(rule -> rule.getCategoryId().equals(category.getId())).collect(Collectors.toList()).forEach(rule -> {
+                    AppSitePriceRules appSitePriceRules = new AppSitePriceRules();
+                    BeanUtils.copyProperties(rule,appSitePriceRules);
+                    appSitePriceRules.setSitePlaceId(appSitePlace.getId());
+                    appSitePriceRules.setOrgCode(appSitePlace.getOrgCode());
+                    appSitePriceRules.setTenantId(appSitePlace.getTenantId());
+                    int savePriceResult = appSitePriceRulesMapper.insert(appSitePriceRules);
+                    if (savePriceResult < 1) throw new JeecgBootException("包场价格保存失败", SC_INTERNAL_SERVER_ERROR_500);
+                });
+            }
+
+        });
+        return Boolean.TRUE;
     }
 
     @Override
     public Boolean editPack(AppSitePlaceDTO placeDTO) {
-        return null;
+        AppSitePlaceCuDTO placeCuDTO = placeDTO.getAppSitePlaceCuDTO();
+        List<AppSiteCategoryDOT> siteCategoryDOTS = placeDTO.getSiteCategoryDOTS();
+        List<AppSiteRuleDTO> siteRuleDTOS = placeDTO.getSiteRuleDTOS();
+
+        // 按 categoryId 分组价格规则
+        Map<String, List<AppSiteRuleDTO>> ruleMap = siteRuleDTOS.stream()
+                .collect(Collectors.groupingBy(AppSiteRuleDTO::getCategoryId));
+
+        AppSite site = appSiteMapper.selectById(placeCuDTO.getSiteId());
+        if (site == null) {
+            throw new JeecgBootException("商户门店不存在", SC_INTERNAL_SERVER_ERROR_500);
+        }
+
+        // 查询当前场地的所有包场场地
+        List<AppSitePlace> existingPlaces = baseMapper.selectList(Wrappers.<AppSitePlace>lambdaQuery()
+                .eq(AppSitePlace::getSiteId, site.getId())
+                .eq(AppSitePlace::getType, SitePlaceTypeEnum.PACKAGE.getCode()));
+
+        if (existingPlaces.isEmpty()) {
+            throw new JeecgBootException("包场数据不存在", SC_INTERNAL_SERVER_ERROR_500);
+        }
+
+        // 用于存储需要保留的场地ID
+        List<String> updatedPlaceIds = new ArrayList<>();
+
+        // 更新或新增场地
+        for (AppSiteCategoryDOT item : siteCategoryDOTS) {
+            String categoryId = item.getCategoryId();
+            int count = item.getCount();
+            List<AppSiteRuleDTO> rules = ruleMap.getOrDefault(categoryId, Collections.emptyList());
+
+            // 查询该分类已有的场地
+            List<AppSitePlace> categoryPlaces = existingPlaces.stream()
+                    .filter(p -> p.getCategoryId() != null && p.getCategoryId().equals(categoryId))
+                    .sorted(Comparator.comparing(AppSitePlace::getName)) // 按名称排序以确保顺序一致
+                    .collect(Collectors.toList());
+
+            AppCategory category = appCategoryMapper.selectById(categoryId);
+            if (category == null) {
+                throw new JeecgBootException("分类不存在", SC_INTERNAL_SERVER_ERROR_500);
+            }
+
+            // 扩展或裁剪场地数量
+            for (int i = 0; i < count; i++) {
+                AppSitePlace appSitePlace;
+                if (i < categoryPlaces.size()) {
+                    // 更新现有场地
+                    appSitePlace = categoryPlaces.get(i);
+                } else {
+                    // 创建新场地
+                    appSitePlace = new AppSitePlace();
+                    BeanUtils.copyProperties(placeCuDTO, appSitePlace);
+                    appSitePlace.setType(SitePlaceTypeEnum.PACKAGE.getCode());
+                    appSitePlace.setOrgCode(site.getOrgCode());
+                    appSitePlace.setTenantId(site.getTenantId());
+                    appSitePlace.setCategoryId(categoryId);
+                }
+
+                // 设置场地名称
+                appSitePlace.setName(category.getName() + (i + 1));
+                // 保存或更新场地
+                if (appSitePlace.getId() == null) {
+                    int insertResult = baseMapper.insert(appSitePlace);
+                    if (insertResult < 1) {
+                        throw new JeecgBootException("包场场地创建失败", SC_INTERNAL_SERVER_ERROR_500);
+                    }
+                } else {
+                    int updateResult = baseMapper.updateById(appSitePlace);
+                    if (updateResult < 1) {
+                        throw new JeecgBootException("包场场地更新失败", SC_INTERNAL_SERVER_ERROR_500);
+                    }
+                }
+
+                // 更新价格规则
+                List<AppSitePriceRules> priceRules = rules.stream()
+                        .map(rule -> {
+                            AppSitePriceRules priceRule = new AppSitePriceRules();
+                            BeanUtils.copyProperties(rule, priceRule);
+                            priceRule.setSitePlaceId(appSitePlace.getId());
+                            priceRule.setOrgCode(site.getOrgCode());
+                            priceRule.setTenantId(site.getTenantId());
+                            return priceRule;
+                        })
+                        .collect(Collectors.toList());
+
+                // 删除旧的价格规则
+                appSitePriceRulesMapper.delete(Wrappers.<AppSitePriceRules>lambdaQuery()
+                        .eq(AppSitePriceRules::getSitePlaceId, appSitePlace.getId()));
+
+                // 插入新的价格规则
+                for (AppSitePriceRules priceRule : priceRules) {
+                    int insertResult = appSitePriceRulesMapper.insert(priceRule);
+                    if (insertResult < 1) {
+                        throw new JeecgBootException("包场价格规则保存失败", SC_INTERNAL_SERVER_ERROR_500);
+                    }
+                }
+
+                updatedPlaceIds.add(appSitePlace.getId());
+            }
+        }
+
+        // 删除不再需要的场地
+        for (AppSitePlace existingPlace : existingPlaces) {
+            if (!updatedPlaceIds.contains(existingPlace.getId())) {
+                int deleteResult = baseMapper.deleteById(existingPlace.getId());
+                if (deleteResult < 1) {
+                    throw new JeecgBootException("包场场地删除失败", SC_INTERNAL_SERVER_ERROR_500);
+                }
+
+                // 删除对应的价格规则
+                appSitePriceRulesMapper.delete(Wrappers.<AppSitePriceRules>lambdaQuery()
+                        .eq(AppSitePriceRules::getSitePlaceId, existingPlace.getId()));
+            }
+        }
+
+        return Boolean.TRUE;
     }
 
     @Override
     public AppSitePlaceDTO queryPackById(String id) {
-        return null;
+        AppSitePlace dbPlace = baseMapper.selectById(id);
+        if (null == dbPlace) throw new JeecgBootException("包场数据不存在", SC_INTERNAL_SERVER_ERROR_500);
+        AppSitePlaceCuDTO placeCuDTO = new AppSitePlaceCuDTO();
+        BeanUtils.copyProperties(dbPlace, placeCuDTO);
+        List<AppSiteRuleDTO> collect = appSitePriceRulesMapper.selectList(Wrappers.<AppSitePriceRules>lambdaQuery().eq(AppSitePriceRules::getSitePlaceId, id)).stream().map(rule -> {
+            AppSiteRuleDTO appSiteRuleDTO = new AppSiteRuleDTO();
+            BeanUtils.copyProperties(rule, appSiteRuleDTO);
+            return appSiteRuleDTO;
+        }).collect(Collectors.toList());
+        Map<String, List<AppSiteRuleDTO>> collect1 = collect.stream().collect(Collectors.groupingBy(AppSiteRuleDTO::getCategoryId));
+        List<AppSiteCategoryDOT> appSiteCategoryDOTs = collect1.entrySet().stream().map(entry -> {
+            AppSiteCategoryDOT appSiteCategoryDOT = new AppSiteCategoryDOT();
+            appSiteCategoryDOT.setCategoryId(entry.getKey());
+            appSiteCategoryDOT.setCount(entry.getValue().size());
+            return appSiteCategoryDOT;
+        }).collect(Collectors.toList());
+
+        return new AppSitePlaceDTO(placeCuDTO, collect,appSiteCategoryDOTs);
     }
 
     @Override