Prechádzať zdrojové kódy

【优化】支持登陆用户,直接读取昵称、部门等信息,也支持自定义字段

libin 1 rok pred
rodič
commit
c8da634ff0
37 zmenil súbory, kde vykonal 1114 pridanie a 61 odobranie
  1. 1 1
      yudao-module-guide/yudao-module-guide-api/src/main/java/cn/iocoder/yudao/module/guide/enums/ErrorCodeConstants.java
  2. 4 1
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/aftersale/vo/GuideAfterSalePageReqVO.java
  3. 40 4
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/order/GuideTradeOrderController.java
  4. 7 7
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/sightscategory/SightsCategoryController.java
  5. 113 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/subject/SubjectController.java
  6. 31 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/subject/vo/SubjectPageReqVO.java
  7. 63 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/subject/vo/SubjectRespVO.java
  8. 47 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/subject/vo/SubjectSaveReqVO.java
  9. 10 1
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/trip/TripController.java
  10. 3 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/trip/vo/TripPageReqVO.java
  11. 4 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/trip/vo/TripRespVO.java
  12. 3 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/trip/vo/TripSaveReqVO.java
  13. 7 13
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/users/UsersController.java
  14. 22 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/users/vo/UserUpdatePasswordReqVO.java
  15. 44 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/subject/AppSubjectController.java
  16. 44 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/subject/vo/AppSubjectRespVO.java
  17. 3 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/trip/vo/AppTripPageReqVO.java
  18. 77 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/dal/dataobject/subject/SubjectDO.java
  19. 4 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/dal/dataobject/trip/TripDO.java
  20. 2 1
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/dal/mysql/aftersale/GuideAfterSaleMapper.java
  21. 19 8
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/dal/mysql/favorite/GuideTripFavoriteMapper.java
  22. 50 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/dal/mysql/subject/SubjectMapper.java
  23. 55 14
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/dal/mysql/trip/TripMapper.java
  24. 79 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/service/subject/SubjectService.java
  25. 87 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/service/subject/SubjectServiceImpl.java
  26. 1 3
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/service/trip/TripService.java
  27. 2 4
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/service/trip/TripServiceImpl.java
  28. 7 1
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/service/users/UsersService.java
  29. 15 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/service/users/UsersServiceImpl.java
  30. 12 0
      yudao-module-guide/yudao-module-guide-biz/src/main/resources/mapper/subject/SubjectMapper.xml
  31. 142 0
      yudao-module-guide/yudao-module-guide-biz/src/test/java/cn/iocoder/yudao/module/guide/service/subject/SubjectServiceImplTest.java
  32. 7 1
      yudao-module-guide/yudao-module-guide-statistics-biz/src/main/java/cn/iocoder/yudao/module/guide/statistics/controller/admin/guide/GuideStatisticsController.java
  33. 41 0
      yudao-module-guide/yudao-module-guide-statistics-biz/src/main/java/cn/iocoder/yudao/module/guide/statistics/controller/admin/guide/vo/GuideTopPageRespVO.java
  34. 6 2
      yudao-module-guide/yudao-module-guide-statistics-biz/src/main/java/cn/iocoder/yudao/module/guide/statistics/dal/mysql/guide/GuideStatisticsMapper.java
  35. 9 0
      yudao-module-guide/yudao-module-guide-statistics-biz/src/main/java/cn/iocoder/yudao/module/guide/statistics/service/guide/GuideStatisticsService.java
  36. 22 0
      yudao-module-guide/yudao-module-guide-statistics-biz/src/main/java/cn/iocoder/yudao/module/guide/statistics/service/guide/GuideStatisticsServiceImpl.java
  37. 31 0
      yudao-module-guide/yudao-module-guide-statistics-biz/src/main/resources/mapper/guide/GuideStatisticsMapper.xml

+ 1 - 1
yudao-module-guide/yudao-module-guide-api/src/main/java/cn/iocoder/yudao/module/guide/enums/ErrorCodeConstants.java

@@ -67,5 +67,5 @@ public interface ErrorCodeConstants {
     ErrorCode AFTER_SALE_CANCEL_FAIL_STATUS_NOT_APPLY_OR_AGREE_OR_BUYER_DELIVERY =
             new ErrorCode(9_00_010_012, "取消售后单失败,售后单状态不是【待审核】或【卖家同意】或【商家待收货】");
 
-
+    ErrorCode SUBJECT_NOT_EXISTS = new ErrorCode(9_00_020_011, "观光主题不存在");
 }

+ 4 - 1
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/aftersale/vo/GuideAfterSalePageReqVO.java

@@ -39,9 +39,12 @@ public class GuideAfterSalePageReqVO extends PageParam {
     @Schema(description = "订单编号", example = "18078")
     private String orderNo;
 
-    @Schema(description = "导游 id", example = "李四")
+    @Schema(description = "导游 id", example = "999")
     private Long guideId;
 
+    @Schema(description = "导游名", example = "guide001")
+    private String guideName;
+
     @Schema(description = "trip id", example = "李四")
     private Long tripId;
 

+ 40 - 4
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/order/GuideTradeOrderController.java

@@ -10,9 +10,11 @@ import cn.iocoder.yudao.module.guide.controller.admin.trip.vo.TripRespVO;
 import cn.iocoder.yudao.module.guide.dal.dataobject.order.GuideTradeOrderDO;
 import cn.iocoder.yudao.module.guide.dal.dataobject.order.GuideTradeOrderItemDO;
 import cn.iocoder.yudao.module.guide.dal.dataobject.order.GuideTradeOrderLogDO;
+import cn.iocoder.yudao.module.guide.dal.dataobject.users.UsersDO;
 import cn.iocoder.yudao.module.guide.service.order.GuideTradeOrderLogService;
 import cn.iocoder.yudao.module.guide.service.order.GuideTradeOrderQueryService;
 import cn.iocoder.yudao.module.guide.service.order.GuideTradeOrderUpdateService;
+import cn.iocoder.yudao.module.guide.service.users.UsersService;
 import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
 import io.swagger.v3.oas.annotations.Operation;
@@ -24,15 +26,13 @@ import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
+import java.util.*;
 import java.util.stream.Collectors;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
 
 @Tag(name = "管理后台 - 交易订单")
 @RestController
@@ -50,6 +50,8 @@ public class GuideTradeOrderController {
 
     @Resource
     private MemberUserApi memberUserApi;
+    @Resource
+    private UsersService usersService;
 
     @GetMapping("/page")
     @Operation(summary = "获得交易订单分页")
@@ -82,9 +84,43 @@ public class GuideTradeOrderController {
                     .collect(Collectors.toList());
             order.setItems(BeanUtils.toBean(items,GuideTradeOrderItemBaseVO.class));
         });
+        //如果是导游,那么只保留导游自己的情报
+        UsersDO user = usersService.getUsers(getLoginUserId());
+        if (user.getDeptId()==999){
+            filterGuideTradeOrderList(newOrders,getLoginUserId());
+        }
         return newOrders;
     }
 
+    private void filterGuideTradeOrderList(PageResult<GuideTradeOrderPageItemRespVO> orders,Long guideId) {
+        // 使用迭代器来避免ConcurrentModificationException
+        Iterator<GuideTradeOrderPageItemRespVO> iterator = orders.getList().iterator();
+
+        while (iterator.hasNext()) {
+            GuideTradeOrderPageItemRespVO orderPageItem = iterator.next();
+            List<GuideTradeOrderItemBaseVO> items = orderPageItem.getItems();
+
+            if (items != null && !items.isEmpty()) {
+                // 过滤出 deptID 为 999 的数据
+                List<GuideTradeOrderItemBaseVO> filteredItems = items.stream()
+                        .filter(item -> Objects.equals(item.getGuideId(), guideId))
+                        .collect(Collectors.toList());
+
+                // 如果过滤后的items为空,则移除该orderPageItem,否则更新items
+                // TODO setTotal数据不对,只是减少了当前导游的注文,需要后期改进SQL部分 把导游ID加到检索条件里
+                if (filteredItems.isEmpty()) {
+                    iterator.remove();
+                } else {
+                    orderPageItem.setItems(filteredItems);
+                    orders.setTotal(orders.getTotal()-1);
+                }
+            } else {
+                // 如果 items 是空的,移除该 orderPageItem
+                iterator.remove();
+                orders.setTotal(orders.getTotal()-1);
+            }
+        }
+    }
     @GetMapping("/summary")
     @Operation(summary = "获得交易订单统计")
     @PreAuthorize("@ss.hasPermission('trade:order:query')")

+ 7 - 7
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/sightscategory/SightsCategoryController.java

@@ -40,14 +40,14 @@ public class SightsCategoryController {
 
     @PostMapping("/create")
     @Operation(summary = "创建观光景点分类")
-    @PreAuthorize("@ss.hasPermission('guide:sights-category:create')")
+    @PreAuthorize("@ss.hasPermission('guide:sights:create')")
     public CommonResult<Long> createSightsCategory(@Valid @RequestBody SightsCategorySaveReqVO createReqVO) {
         return success(sightsCategoryService.createSightsCategory(createReqVO));
     }
 
     @PutMapping("/update")
     @Operation(summary = "更新观光景点分类")
-    @PreAuthorize("@ss.hasPermission('guide:sights-category:update')")
+    @PreAuthorize("@ss.hasPermission('guide:sights:update')")
     public CommonResult<Boolean> updateSightsCategory(@Valid @RequestBody SightsCategorySaveReqVO updateReqVO) {
         sightsCategoryService.updateSightsCategory(updateReqVO);
         return success(true);
@@ -56,7 +56,7 @@ public class SightsCategoryController {
     @DeleteMapping("/delete")
     @Operation(summary = "删除观光景点分类")
     @Parameter(name = "id", description = "编号", required = true)
-    @PreAuthorize("@ss.hasPermission('guide:sights-category:delete')")
+    @PreAuthorize("@ss.hasPermission('guide:sights:delete')")
     public CommonResult<Boolean> deleteSightsCategory(@RequestParam("id") Long id) {
         sightsCategoryService.deleteSightsCategory(id);
         return success(true);
@@ -65,7 +65,7 @@ public class SightsCategoryController {
     @GetMapping("/get")
     @Operation(summary = "获得观光景点分类")
     @Parameter(name = "id", description = "编号", required = true, example = "1024")
-    @PreAuthorize("@ss.hasPermission('guide:sights-category:query')")
+    @PreAuthorize("@ss.hasPermission('guide:sights:query')")
     public CommonResult<SightsCategoryRespVO> getSightsCategory(@RequestParam("id") Long id) {
         SightsCategoryDO sightsCategory = sightsCategoryService.getSightsCategory(id);
         return success(BeanUtils.toBean(sightsCategory, SightsCategoryRespVO.class));
@@ -73,7 +73,7 @@ public class SightsCategoryController {
 
     @GetMapping("/list")
     @Operation(summary = "获得观光景点分类列表")
-    @PreAuthorize("@ss.hasPermission('guide:sights-category:query')")
+    @PreAuthorize("@ss.hasPermission('guide:sights:query')")
     public CommonResult<List<SightsCategoryRespVO>> getSightsCategoryList(@Valid SightsCategoryListReqVO listReqVO) {
         List<SightsCategoryDO> list = sightsCategoryService.getSightsCategoryList(listReqVO);
         return success(BeanUtils.toBean(list, SightsCategoryRespVO.class));
@@ -81,7 +81,7 @@ public class SightsCategoryController {
 
     @GetMapping("/categorys")
     @Operation(summary = "获得观光景点分类列表")
-    @PreAuthorize("@ss.hasPermission('guide:sights-category:query')")
+    @PreAuthorize("@ss.hasPermission('guide:sights:query')")
     public CommonResult<List<SightsCategoryRespVO>> getSightsCategorys(@RequestParam List<Integer> ids) {
         List<SightsCategoryDO> list = sightsCategoryService.getSightsCategoryList(ids);
         return success(BeanUtils.toBean(list, SightsCategoryRespVO.class));
@@ -89,7 +89,7 @@ public class SightsCategoryController {
 
     @GetMapping("/export-excel")
     @Operation(summary = "导出观光景点分类 Excel")
-    @PreAuthorize("@ss.hasPermission('guide:sights-category:export')")
+    @PreAuthorize("@ss.hasPermission('guide:sights:export')")
     @ApiAccessLog(operateType = EXPORT)
     public void exportSightsCategoryExcel(@Valid SightsCategoryListReqVO listReqVO,
               HttpServletResponse response) throws IOException {

+ 113 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/subject/SubjectController.java

@@ -0,0 +1,113 @@
+package cn.iocoder.yudao.module.guide.controller.admin.subject;
+
+import cn.iocoder.yudao.module.guide.controller.admin.sightscategory.vo.SightsCategoryListReqVO;
+import cn.iocoder.yudao.module.guide.controller.admin.sightscategory.vo.SightsCategoryRespVO;
+import cn.iocoder.yudao.module.guide.dal.dataobject.sightscategory.SightsCategoryDO;
+import org.springframework.web.bind.annotation.*;
+import jakarta.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.security.access.prepost.PreAuthorize;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Operation;
+
+import jakarta.validation.constraints.*;
+import jakarta.validation.*;
+import jakarta.servlet.http.*;
+import java.util.*;
+import java.io.IOException;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+
+import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog;
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
+
+import cn.iocoder.yudao.module.guide.controller.admin.subject.vo.*;
+import cn.iocoder.yudao.module.guide.dal.dataobject.subject.SubjectDO;
+import cn.iocoder.yudao.module.guide.service.subject.SubjectService;
+
+@Tag(name = "管理后台 - 观光主题")
+@RestController
+@RequestMapping("/guide/subject")
+@Validated
+public class SubjectController {
+
+    @Resource
+    private SubjectService subjectService;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建观光主题")
+    @PreAuthorize("@ss.hasPermission('guide:subject:create')")
+    public CommonResult<Long> createSubject(@Valid @RequestBody SubjectSaveReqVO createReqVO) {
+        return success(subjectService.createSubject(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新观光主题")
+    @PreAuthorize("@ss.hasPermission('guide:subject:update')")
+    public CommonResult<Boolean> updateSubject(@Valid @RequestBody SubjectSaveReqVO updateReqVO) {
+        subjectService.updateSubject(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除观光主题")
+    @Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('guide:subject:delete')")
+    public CommonResult<Boolean> deleteSubject(@RequestParam("id") Long id) {
+        subjectService.deleteSubject(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得观光主题")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('guide:subject:query')")
+    public CommonResult<SubjectRespVO> getSubject(@RequestParam("id") Long id) {
+        SubjectDO subject = subjectService.getSubject(id);
+        return success(BeanUtils.toBean(subject, SubjectRespVO.class));
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得观光主题分页")
+    @PreAuthorize("@ss.hasPermission('guide:subject:query')")
+    public CommonResult<PageResult<SubjectRespVO>> getSubjectPage(@Valid SubjectPageReqVO pageReqVO) {
+        PageResult<SubjectDO> pageResult = subjectService.getSubjectPage(pageReqVO);
+        return success(BeanUtils.toBean(pageResult, SubjectRespVO.class));
+    }
+
+    @GetMapping("/list")
+    @Operation(summary = "获得观光主题列表")
+    @PreAuthorize("@ss.hasPermission('guide:subject:query')")
+    public CommonResult<List<SubjectRespVO>> getSubjectList(@Valid SubjectPageReqVO pageReqVO) {
+        List<SubjectDO> list = subjectService.getSubjectList(pageReqVO);
+        return success(BeanUtils.toBean(list, SubjectRespVO.class));
+    }
+
+    @GetMapping("/subjects")
+    @Operation(summary = "获得观光主题列表")
+    @PreAuthorize("@ss.hasPermission('guide:sights:query')")
+    public CommonResult<List<SubjectRespVO>> getSightsCategorys(@RequestParam List<Long> ids) {
+        List<SubjectDO> list = subjectService.getSubjectList(ids);
+        return success(BeanUtils.toBean(list, SubjectRespVO.class));
+    }
+    @GetMapping("/export-excel")
+    @Operation(summary = "导出观光主题 Excel")
+    @PreAuthorize("@ss.hasPermission('guide:subject:export')")
+    @ApiAccessLog(operateType = EXPORT)
+    public void exportSubjectExcel(@Valid SubjectPageReqVO pageReqVO,
+              HttpServletResponse response) throws IOException {
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        List<SubjectDO> list = subjectService.getSubjectPage(pageReqVO).getList();
+        // 导出 Excel
+        ExcelUtils.write(response, "观光主题.xls", "数据", SubjectRespVO.class,
+                        BeanUtils.toBean(list, SubjectRespVO.class));
+    }
+
+}

+ 31 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/subject/vo/SubjectPageReqVO.java

@@ -0,0 +1,31 @@
+package cn.iocoder.yudao.module.guide.controller.admin.subject.vo;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 观光主题分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class SubjectPageReqVO extends PageParam {
+
+    @Schema(description = "主题中文名称")
+    private String titleZh;
+
+    @Schema(description = "主题日文名称")
+    private String titleJa;
+
+    @Schema(description = "主题英文名称")
+    private String titleEn;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

+ 63 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/subject/vo/SubjectRespVO.java

@@ -0,0 +1,63 @@
+package cn.iocoder.yudao.module.guide.controller.admin.subject.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import java.util.*;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+import com.alibaba.excel.annotation.*;
+import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
+import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
+
+@Schema(description = "管理后台 - 观光主题 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class SubjectRespVO {
+
+    @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18328")
+    @ExcelProperty("编号")
+    private Long id;
+
+    @Schema(description = "主题中文名称", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("主题中文名称")
+    private String titleZh;
+
+    @Schema(description = "主题日文名称", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("主题日文名称")
+    private String titleJa;
+
+    @Schema(description = "主题英文名称", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("主题英文名称")
+    private String titleEn;
+
+    @Schema(description = "主题补充中文名称")
+    @ExcelProperty("主题补充中文名称")
+    private String subtitleZh;
+
+    @Schema(description = "主题补充日文名称")
+    @ExcelProperty("主题补充日文名称")
+    private String subtitleJa;
+
+    @Schema(description = "主题补充英文名称")
+    @ExcelProperty("主题补充英文名称")
+    private String subtitleEn;
+
+    @Schema(description = "移动端主题图", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn")
+    @ExcelProperty("移动端主题图")
+    private String picUrl;
+
+    @Schema(description = "分类排序")
+    @ExcelProperty("分类排序")
+    private Integer sort;
+
+    @Schema(description = "开启状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @ExcelProperty(value = "开启状态", converter = DictConvert.class)
+    @DictFormat("common_status") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
+    private Integer status;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+}

+ 47 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/subject/vo/SubjectSaveReqVO.java

@@ -0,0 +1,47 @@
+package cn.iocoder.yudao.module.guide.controller.admin.subject.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import jakarta.validation.constraints.*;
+
+@Schema(description = "管理后台 - 观光主题新增/修改 Request VO")
+@Data
+public class SubjectSaveReqVO {
+
+    @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18328")
+    private Long id;
+
+    @Schema(description = "主题中文名称", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotEmpty(message = "主题中文名称不能为空")
+    private String titleZh;
+
+    @Schema(description = "主题日文名称", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotEmpty(message = "主题日文名称不能为空")
+    private String titleJa;
+
+    @Schema(description = "主题英文名称", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotEmpty(message = "主题英文名称不能为空")
+    private String titleEn;
+
+    @Schema(description = "主题补充中文名称")
+    private String subtitleZh;
+
+    @Schema(description = "主题补充日文名称")
+    private String subtitleJa;
+
+    @Schema(description = "主题补充英文名称")
+    private String subtitleEn;
+
+    @Schema(description = "移动端主题图", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn")
+    @NotEmpty(message = "移动端主题图不能为空")
+    private String picUrl;
+
+    @Schema(description = "主题排序")
+    private Integer sort;
+
+    @Schema(description = "开启状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+    @NotNull(message = "开启状态不能为空")
+    private Integer status;
+
+}

+ 10 - 1
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/trip/TripController.java

@@ -1,5 +1,7 @@
 package cn.iocoder.yudao.module.guide.controller.admin.trip;
 
+import cn.iocoder.yudao.module.guide.dal.dataobject.users.UsersDO;
+import cn.iocoder.yudao.module.guide.service.users.UsersService;
 import org.springframework.web.bind.annotation.*;
 import jakarta.annotation.Resource;
 import org.springframework.validation.annotation.Validated;
@@ -8,7 +10,6 @@ import io.swagger.v3.oas.annotations.tags.Tag;
 import io.swagger.v3.oas.annotations.Parameter;
 import io.swagger.v3.oas.annotations.Operation;
 
-import jakarta.validation.constraints.*;
 import jakarta.validation.*;
 import jakarta.servlet.http.*;
 import java.util.*;
@@ -24,6 +25,7 @@ import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
 
 import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog;
 import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
+import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
 
 import cn.iocoder.yudao.module.guide.controller.admin.trip.vo.*;
 import cn.iocoder.yudao.module.guide.dal.dataobject.trip.TripDO;
@@ -40,6 +42,8 @@ public class TripController {
     @Resource
     private TripService tripService;
 
+    @Resource
+    private UsersService usersService;
     @PostMapping("/create")
     @Operation(summary = "创建旅程基本情报")
     @PreAuthorize("@ss.hasPermission('guide:trip:create')")
@@ -77,6 +81,11 @@ public class TripController {
     @Operation(summary = "获得旅程基本情报分页")
     @PreAuthorize("@ss.hasPermission('guide:trip:query')")
     public CommonResult<PageResult<TripRespVO>> getTripPage(@Valid TripPageReqVO pageReqVO) {
+
+        UsersDO user = usersService.getUsers(getLoginUserId());
+        if (user.getDeptId()==999){
+            pageReqVO.setGuideId(getLoginUserId());
+        }
         PageResult<TripDO> pageResult = tripService.getTripPage(pageReqVO);
         CommonResult<PageResult<TripRespVO>> returnV = success(BeanUtils.toBean(pageResult, TripRespVO.class));
         return returnV;

+ 3 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/trip/vo/TripPageReqVO.java

@@ -18,6 +18,9 @@ public class TripPageReqVO extends PageParam {
     @Schema(description = "导游编号", example = "18507")
     private Long guideId;
 
+    @Schema(description = "主题数组,以逗号分隔")
+    private List<Long> subjectIds;
+
     @Schema(description = "创建时间")
     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
     private LocalDateTime[] createTime;

+ 4 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/trip/vo/TripRespVO.java

@@ -20,6 +20,10 @@ public class TripRespVO {
     @ExcelProperty("旅程编号")
     private Long id;
 
+    @Schema(description = "景点主题数组,以逗号分隔")
+    @ExcelProperty("景点主题数组,以逗号分隔")
+    private List<Long> subjectIds;
+
     @Schema(description = "导游编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18507")
     @ExcelProperty("导游编号")
     private Long guideId;

+ 3 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/trip/vo/TripSaveReqVO.java

@@ -19,6 +19,9 @@ public class TripSaveReqVO {
     @Schema(description = "旅程编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20578")
     private Long id;
 
+    @Schema(description = "景点主题数组,以逗号分隔")
+    private List<Long> subjectIds;
+
     @Schema(description = "导游编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18507")
     @NotNull(message = "导游编号不能为空")
     private Long guideId;

+ 7 - 13
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/users/UsersController.java

@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.module.guide.controller.admin.users;
 
+
 import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
 import org.springframework.web.bind.annotation.*;
 import jakarta.annotation.Resource;
@@ -43,14 +44,12 @@ public class UsersController {
 
     @PostMapping("/create")
     @Operation(summary = "创建导游信息")
-    @PreAuthorize("@ss.hasPermission('guide:users:create')")
     public CommonResult<Long> createUsers(@Valid @RequestBody UsersSaveReqVO createReqVO) {
         return success(usersService.createUsers(createReqVO));
     }
 
     @PutMapping("/update")
     @Operation(summary = "更新导游信息")
-    @PreAuthorize("@ss.hasPermission('guide:users:update')")
     public CommonResult<Boolean> updateUsers(@Valid @RequestBody UsersSaveReqVO updateReqVO) {
         usersService.updateUsers(updateReqVO);
         return success(true);
@@ -59,16 +58,20 @@ public class UsersController {
     @DeleteMapping("/delete")
     @Operation(summary = "删除导游信息")
     @Parameter(name = "id", description = "编号", required = true)
-    @PreAuthorize("@ss.hasPermission('guide:users:delete')")
     public CommonResult<Boolean> deleteUsers(@RequestParam("id") Long id) {
         usersService.deleteUsers(id);
         return success(true);
     }
 
+    @PutMapping("/update-password")
+    @Operation(summary = "重置用户密码")
+    public CommonResult<Boolean> updateUserPassword(@Valid @RequestBody UserUpdatePasswordReqVO reqVO) {
+        usersService.updateUserPassword(reqVO.getId(), reqVO.getPassword());
+        return success(true);
+    }
     @GetMapping("/get")
     @Operation(summary = "获得导游信息")
     @Parameter(name = "id", description = "编号", required = true, example = "1024")
-    @PreAuthorize("@ss.hasPermission('guide:users:query')")
     public CommonResult<UsersRespVO> getUsers(@RequestParam("id") Long id) {
         UsersDO users = usersService.getUsers(id);
         return success(BeanUtils.toBean(users, UsersRespVO.class));
@@ -76,7 +79,6 @@ public class UsersController {
 
     @GetMapping("/page")
     @Operation(summary = "获得导游信息分页")
-    @PreAuthorize("@ss.hasPermission('guide:users:query')")
     public CommonResult<PageResult<UsersRespVO>> getUsersPage(@Valid UsersPageReqVO pageReqVO) {
         PageResult<UsersDO> pageResult = usersService.getUsersPage(pageReqVO);
         return success(BeanUtils.toBean(pageResult, UsersRespVO.class));
@@ -84,7 +86,6 @@ public class UsersController {
 
     @GetMapping("/export-excel")
     @Operation(summary = "导出导游信息 Excel")
-    @PreAuthorize("@ss.hasPermission('guide:users:export')")
     @ApiAccessLog(operateType = EXPORT)
     public void exportUsersExcel(@Valid UsersPageReqVO pageReqVO,
               HttpServletResponse response) throws IOException {
@@ -97,7 +98,6 @@ public class UsersController {
 
     @GetMapping("/get-count")
     @Operation(summary = "获得导游 count")
-    @PreAuthorize("@ss.hasPermission('guide:users:query')")
     public CommonResult<Long> getGuideCount() {
         return success(usersService.getCount());
     }
@@ -107,7 +107,6 @@ public class UsersController {
     @GetMapping("/comment/page")
     @Operation(summary = "获得导游评论分页")
     @Parameter(name = "guideId", description = "导游编号,关联 AdminUserDO 的 id 编号")
-    @PreAuthorize("@ss.hasPermission('guide:users:query')")
     public CommonResult<PageResult<CommentDO>> getCommentPage(PageParam pageReqVO,
                                                                                         @RequestParam("guideId") Long guideId) {
         return success(usersService.getCommentPage(pageReqVO, guideId));
@@ -115,14 +114,12 @@ public class UsersController {
 
     @PostMapping("/comment/create")
     @Operation(summary = "创建导游评论")
-    @PreAuthorize("@ss.hasPermission('guide:users:create')")
     public CommonResult<Long> createComment(@Valid @RequestBody CommentDO comment) {
         return success(usersService.createComment(comment));
     }
 
     @PutMapping("/comment/update")
     @Operation(summary = "更新导游评论")
-    @PreAuthorize("@ss.hasPermission('guide:users:update')")
     public CommonResult<Boolean> updateComment(@Valid @RequestBody CommentDO comment) {
         usersService.updateComment(comment);
         return success(true);
@@ -131,7 +128,6 @@ public class UsersController {
     @DeleteMapping("/comment/delete")
     @Parameter(name = "id", description = "编号", required = true)
     @Operation(summary = "删除导游评论")
-    @PreAuthorize("@ss.hasPermission('guide:users:delete')")
     public CommonResult<Boolean> deleteComment(@RequestParam("id") Long id) {
         usersService.deleteComment(id);
         return success(true);
@@ -140,7 +136,6 @@ public class UsersController {
 	@GetMapping("/comment/get")
 	@Operation(summary = "获得导游评论")
 	@Parameter(name = "id", description = "编号", required = true)
-    @PreAuthorize("@ss.hasPermission('guide:users:query')")
 	public CommonResult<CommentDO> getComment(@RequestParam("id") Long id) {
 	    return success(usersService.getComment(id));
 	}
@@ -148,7 +143,6 @@ public class UsersController {
     @GetMapping("/comment/self/get")
     @Operation(summary = "获得导游自我评论")
 //    @Parameter(name = "guideId", description = "导游编号", required = true)
-    @PreAuthorize("@ss.hasPermission('guide:users:query')")
     public CommonResult<CommentDO> getSelfComment() {
         // 获得用户基本信息
 //        AdminUserDO user = userService.getUser(getLoginUserId());

+ 22 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/users/vo/UserUpdatePasswordReqVO.java

@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.guide.controller.admin.users.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import org.hibernate.validator.constraints.Length;
+
+@Schema(description = "管理后台 - 用户更新密码 Request VO")
+@Data
+public class UserUpdatePasswordReqVO {
+
+    @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    @NotNull(message = "用户编号不能为空")
+    private Long id;
+
+    @Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456")
+    @NotEmpty(message = "密码不能为空")
+    @Length(min = 4, max = 16, message = "密码长度为 4-16 位")
+    private String password;
+
+}

+ 44 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/subject/AppSubjectController.java

@@ -0,0 +1,44 @@
+package cn.iocoder.yudao.module.guide.controller.app.subject;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.guide.controller.app.subject.vo.AppSubjectRespVO;
+import cn.iocoder.yudao.module.guide.dal.dataobject.subject.SubjectDO;
+
+import cn.iocoder.yudao.module.guide.service.subject.SubjectService;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
+
+@Tag(name = "用户 App -  - 观光景点主题")
+@RestController
+@RequestMapping("/guide/subject")
+@Validated
+public class AppSubjectController {
+
+    @Resource
+    private SubjectService subjectService;
+
+    @GetMapping("/page")
+    @Operation(summary = "获得旅程主题分页")
+    public CommonResult<PageResult<AppSubjectRespVO>> getSubjectPage(@Valid PageParam pageParam) {
+        PageResult<SubjectDO> pageResult = subjectService.getAppSubjectPage(pageParam);
+        return success(BeanUtils.toBean(pageResult, AppSubjectRespVO.class));
+    }
+
+
+
+}

+ 44 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/subject/vo/AppSubjectRespVO.java

@@ -0,0 +1,44 @@
+package cn.iocoder.yudao.module.guide.controller.app.subject.vo;
+
+import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
+import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
+import cn.iocoder.yudao.module.guide.dal.dataobject.sights.SightsDO;
+import cn.iocoder.yudao.module.guide.dal.dataobject.trip.TripI18nExtensionDO;
+import cn.iocoder.yudao.module.guide.dal.dataobject.users.UsersDO;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Schema(description = "App - 旅程主题 Response VO")
+@Data
+public class AppSubjectRespVO {
+
+    @Schema(description = "编号", example = "18328")
+    private Long id;
+
+    @Schema(description = "主题中文名称")
+    private String titleZh;
+
+    @Schema(description = "主题日文名称")
+    private String titleJa;
+
+    @Schema(description = "主题英文名称")
+    private String titleEn;
+
+    @Schema(description = "主题补充中文名称")
+    private String subtitleZh;
+
+    @Schema(description = "主题补充日文名称")
+    private String subtitleJa;
+
+    @Schema(description = "主题补充英文名称")
+    private String subtitleEn;
+
+    @Schema(description = "移动端主题图")
+    @ExcelProperty("移动端主题图")
+    private String picUrl;
+
+}

+ 3 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/trip/vo/AppTripPageReqVO.java

@@ -37,4 +37,7 @@ public class AppTripPageReqVO extends PageParam {
     @Schema(description = "景点编号")
     private Long sightId;
 
+    @Schema(description = "景点主题编号")
+    private Long subjectId;
+
 }

+ 77 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/dal/dataobject/subject/SubjectDO.java

@@ -0,0 +1,77 @@
+package cn.iocoder.yudao.module.guide.dal.dataobject.subject;
+
+import lombok.*;
+import java.util.*;
+import java.time.LocalDateTime;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.*;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+
+/**
+ * 观光主题 DO
+ *
+ * @author GuideSystem
+ */
+@TableName("guide_subject")
+@KeySequence("guide_subject_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class SubjectDO extends BaseDO {
+
+    /**
+     * 编号
+     */
+    @TableId
+    private Long id;
+    /**
+     * 主题中文名称
+     */
+    private String titleZh;
+    /**
+     * 主题日文名称
+     */
+    private String titleJa;
+    /**
+     * 主题英文名称
+     */
+    private String titleEn;
+    /**
+     * 主题XX名称
+     */
+    private String titleOther;
+    /**
+     * 主题补充中文名称
+     */
+    private String subtitleZh;
+    /**
+     * 主题补充日文名称
+     */
+    private String subtitleJa;
+    /**
+     * 主题补充英文名称
+     */
+    private String subtitleEn;
+    /**
+     * 主题补充XX名称
+     */
+    private String subtitleOther;
+    /**
+     * 移动端主题图
+     */
+    private String picUrl;
+    /**
+     * 主题排序
+     */
+    private Integer sort;
+    /**
+     * 开启状态
+     *
+     * 枚举 {@link TODO common_status 对应的类}
+     */
+    private Integer status;
+
+}

+ 4 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/dal/dataobject/trip/TripDO.java

@@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.guide.dal.dataobject.sights.SightsI18nExtensionDO
 import cn.iocoder.yudao.module.guide.dal.dataobject.users.UsersDO;
 import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileRespVO;
 import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
+import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.*;
 import java.util.*;
@@ -29,6 +30,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
 @Builder
 @NoArgsConstructor
 @AllArgsConstructor
+
 public class TripDO extends BaseDO {
 
     /**
@@ -43,6 +45,8 @@ public class TripDO extends BaseDO {
 
     private String picUrl;
 
+    @TableField(value = "subject_ids", typeHandler = JacksonTypeHandler.class)
+    private List<Long> subjectIds;
     /**
      * 旅程开始时间
      */

+ 2 - 1
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/dal/mysql/aftersale/GuideAfterSaleMapper.java

@@ -23,7 +23,8 @@ public interface GuideAfterSaleMapper extends BaseMapperX<GuideAfterSaleDO> {
                 .eqIfPresent(GuideAfterSaleDO::getType, reqVO.getType())
                 .eqIfPresent(GuideAfterSaleDO::getWay, reqVO.getWay())
                 .likeIfPresent(GuideAfterSaleDO::getOrderNo, reqVO.getOrderNo())
-                .likeIfPresent(GuideAfterSaleDO::getGuideId, reqVO.getOrderNo())
+                .eqIfPresent(GuideAfterSaleDO::getGuideId, reqVO.getGuideId())
+                .likeIfPresent(GuideAfterSaleDO::getGuideName, reqVO.getGuideName())
                 .betweenIfPresent(GuideAfterSaleDO::getBookingDate, reqVO.getCreateTime())
                 .betweenIfPresent(GuideAfterSaleDO::getCreateTime, reqVO.getCreateTime())
                 .orderByDesc(GuideAfterSaleDO::getId));

+ 19 - 8
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/dal/mysql/favorite/GuideTripFavoriteMapper.java

@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.module.guide.dal.mysql.favorite;
 
+import cn.hutool.core.collection.ListUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
@@ -9,29 +10,39 @@ import cn.iocoder.yudao.module.guide.dal.dataobject.favorite.GuideTripFavoriteDO
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import org.apache.ibatis.annotations.Mapper;
 
+import java.util.List;
+
 @Mapper
 public interface GuideTripFavoriteMapper extends BaseMapperX<GuideTripFavoriteDO> {
 
     default GuideTripFavoriteDO selectByUserIdAndGuideId(Long userId, Long guideId) {
-        return selectOne(GuideTripFavoriteDO::getUserId, userId,
+        List<GuideTripFavoriteDO> list = selectList(GuideTripFavoriteDO::getUserId, userId,
                 GuideTripFavoriteDO::getGuideId, guideId);
+        if (list != null && !list.isEmpty()) {
+            return list.get(0);  // 返回第一个元素
+        }
+        return null;
+
     }
 
     default GuideTripFavoriteDO selectByUserIdAndTripId(Long userId, Long tripId) {
-        return selectOne(GuideTripFavoriteDO::getUserId, userId,
+        List<GuideTripFavoriteDO> list = selectList(GuideTripFavoriteDO::getUserId, userId,
                 GuideTripFavoriteDO::getTripId, tripId);
+        if (list != null && !list.isEmpty()) {
+            return list.get(0);  // 返回第一个元素
+        }
+        return null;
     }
 
     default GuideTripFavoriteDO selectByUserIdAndSightsId(Long userId, Long sightsId) {
-        return selectOne(GuideTripFavoriteDO::getUserId, userId,
+        List<GuideTripFavoriteDO> list = selectList(GuideTripFavoriteDO::getUserId, userId,
                 GuideTripFavoriteDO::getSightsId, sightsId);
+        if (list != null && !list.isEmpty()) {
+            return list.get(0);  // 返回第一个元素
+        }
+        return null;
     }
 
-//    default PageResult<GuideTripFavoriteDO> selectPageByUserId(FavoriteReqVO reqVO) {
-//        return selectPage(reqVO, new LambdaQueryWrapperX<GuideTripFavoriteDO>()
-//                .eqIfPresent(GuideTripFavoriteDO::getUserId, reqVO.getUserId())
-//                .orderByDesc(GuideTripFavoriteDO::getId));
-//    }
 
     default PageResult<GuideTripFavoriteDO> selectPageByUserId(Long userId, AppGuideTripPageReqVO reqVO) {
         return selectPage(reqVO, new LambdaQueryWrapperX<GuideTripFavoriteDO>()

+ 50 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/dal/mysql/subject/SubjectMapper.java

@@ -0,0 +1,50 @@
+package cn.iocoder.yudao.module.guide.dal.mysql.subject;
+
+import java.util.*;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.module.guide.controller.admin.sightscategory.vo.SightsCategoryListReqVO;
+import cn.iocoder.yudao.module.guide.dal.dataobject.sightscategory.SightsCategoryDO;
+import cn.iocoder.yudao.module.guide.dal.dataobject.subject.SubjectDO;
+import org.apache.ibatis.annotations.Mapper;
+import cn.iocoder.yudao.module.guide.controller.admin.subject.vo.*;
+
+/**
+ * 观光主题 Mapper
+ *
+ * @author GuideSystem
+ */
+@Mapper
+public interface SubjectMapper extends BaseMapperX<SubjectDO> {
+
+    default PageResult<SubjectDO> selectPage(SubjectPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<SubjectDO>()
+                .eqIfPresent(SubjectDO::getTitleZh, reqVO.getTitleZh())
+                .eqIfPresent(SubjectDO::getTitleJa, reqVO.getTitleJa())
+                .eqIfPresent(SubjectDO::getTitleEn, reqVO.getTitleEn())
+                .betweenIfPresent(SubjectDO::getCreateTime, reqVO.getCreateTime())
+                .orderByDesc(SubjectDO::getId));
+    }
+    default List<SubjectDO> selectList(SubjectPageReqVO reqVO) {
+        return selectList(new LambdaQueryWrapperX<SubjectDO>()
+                .eqIfPresent(SubjectDO::getTitleZh, reqVO.getTitleZh())
+                .eqIfPresent(SubjectDO::getTitleJa, reqVO.getTitleJa())
+                .eqIfPresent(SubjectDO::getTitleEn, reqVO.getTitleEn())
+                .betweenIfPresent(SubjectDO::getCreateTime, reqVO.getCreateTime())
+                .orderByDesc(SubjectDO::getId));
+    }
+    default List<SubjectDO> selectList(List<Long> ids) {
+        return selectList(new LambdaQueryWrapperX<SubjectDO>()
+                .in(SubjectDO::getId, ids)
+                .orderByDesc(SubjectDO::getId));
+    }
+
+    default PageResult<SubjectDO> selectAppPage(PageParam pageParam) {
+        return selectPage(pageParam, new LambdaQueryWrapperX<SubjectDO>()
+                .eq(SubjectDO::getStatus, 0)
+                .orderByDesc(SubjectDO::getSort));
+    }
+}

+ 55 - 14
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/dal/mysql/trip/TripMapper.java

@@ -16,6 +16,7 @@ import cn.iocoder.yudao.module.guide.dal.dataobject.trip.TripSightsDO;
 import org.apache.ibatis.annotations.Mapper;
 import cn.iocoder.yudao.module.guide.controller.admin.trip.vo.*;
 import org.apache.ibatis.annotations.Param;
+import org.springframework.util.StringUtils;
 
 /**
  * 旅程基本情报 Mapper
@@ -26,10 +27,18 @@ import org.apache.ibatis.annotations.Param;
 public interface TripMapper extends BaseMapperX<TripDO> {
 
     default PageResult<TripDO> selectPage(TripPageReqVO reqVO) {
-        return selectPage(reqVO, new LambdaQueryWrapperX<TripDO>()
-                .eqIfPresent(TripDO::getGuideId, reqVO.getGuideId())
+
+        LambdaQueryWrapperX<TripDO> tripMapper = new LambdaQueryWrapperX<TripDO>();
+        if (Objects.nonNull(reqVO.getSubjectIds())) {
+            for (Long selectedId : reqVO.getSubjectIds()) {
+                tripMapper.or().like(TripDO::getSubjectIds, selectedId.toString());
+            }
+        }
+
+        tripMapper.eqIfPresent(TripDO::getGuideId, reqVO.getGuideId())
                 .betweenIfPresent(TripDO::getCreateTime, reqVO.getCreateTime())
-                .orderByDesc(TripDO::getId));
+                .orderByDesc(TripDO::getId);
+        return selectPage(reqVO, tripMapper);
     }
     default PageResult<TripDO> selectAppPage(@Param("appTripPageReqVO") AppTripPageReqVO appTripPageReqVO) {
         MPJLambdaWrapperX<TripDO> query = (MPJLambdaWrapperX<TripDO>) new MPJLambdaWrapperX<TripDO>();
@@ -40,19 +49,46 @@ public interface TripMapper extends BaseMapperX<TripDO> {
         query.eqIfExists(SightsDO::getId,appTripPageReqVO.getSightId())
                 .eqIfExists(TripDO::getCreator, appTripPageReqVO.getGuideId());
 
+//        if (Objects.nonNull(appTripPageReqVO.getCategoryIdList())) {
+//            for (Long selectedId : appTripPageReqVO.getCategoryIdList()) {
+//                query.or().like(SightsDO::getCategoryIds, selectedId.toString());
+//            }
+//        }
         if (Objects.nonNull(appTripPageReqVO.getCategoryIdList())) {
-            for (Long selectedId : appTripPageReqVO.getCategoryIdList()) {
-                query.or().like(SightsDO::getCategoryIds, selectedId.toString());
-            }
+            query.and(q -> {
+                boolean firstCondition = true;
+                for (Long selectedId : appTripPageReqVO.getCategoryIdList()) {
+                    if (firstCondition) {
+                        q.like(SightsDO::getCategoryIds, selectedId.toString());
+                        firstCondition = false;
+                    } else {
+                        q.or().like(SightsDO::getCategoryIds, selectedId.toString());
+                    }
+                }
+            });
+        }
+        if (Objects.nonNull(appTripPageReqVO.getSubjectId())){
+            query.likeIfExists(TripDO::getSubjectIds, appTripPageReqVO.getSubjectId().toString());
+        }
+        if (Objects.nonNull(appTripPageReqVO.getGeographicalId())) {
+            query.likeIfExists(SightsDO::getGeographicalIds , appTripPageReqVO.getGeographicalId().toString());
+        }
+//               query.likeIfExists(SightsI18nExtensionDO::getDescription, appTripPageReqVO.getKeyword())
+//                .or()
+//                .likeIfExists(SightsI18nExtensionDO::getTitle, appTripPageReqVO.getKeyword())
+//                .or()
+//                .likeIfExists(SightsI18nExtensionDO::getSubtitle, appTripPageReqVO.getKeyword())
+//                .or()
+//                .likeIfExists(TripI18nExtensionDO::getTitle, appTripPageReqVO.getKeyword());
+        if (StringUtils.hasText(appTripPageReqVO.getKeyword())) {
+            query.and(q -> q.likeIfExists(SightsI18nExtensionDO::getDescription, appTripPageReqVO.getKeyword())
+                    .or()
+                    .likeIfExists(SightsI18nExtensionDO::getTitle, appTripPageReqVO.getKeyword())
+                    .or()
+                    .likeIfExists(SightsI18nExtensionDO::getSubtitle, appTripPageReqVO.getKeyword())
+                    .or()
+                    .likeIfExists(TripI18nExtensionDO::getTitle, appTripPageReqVO.getKeyword()));
         }
-//        query.likeIfExists(SightsDO::getGeographicalIds , appTripPageReqVO.getGeographicalId().toString());
-               query.likeIfExists(SightsI18nExtensionDO::getDescription, appTripPageReqVO.getKeyword())
-                .or()
-                .likeIfExists(SightsI18nExtensionDO::getTitle, appTripPageReqVO.getKeyword())
-                .or()
-                .likeIfExists(SightsI18nExtensionDO::getSubtitle, appTripPageReqVO.getKeyword())
-                .or()
-                .likeIfExists(TripI18nExtensionDO::getTitle, appTripPageReqVO.getKeyword());
         return selectJoinPage(appTripPageReqVO, TripDO.class, query);
 
     }
@@ -62,4 +98,9 @@ public interface TripMapper extends BaseMapperX<TripDO> {
                 .eq(TripDO::getGuideId, guideId)
                 .orderByDesc(TripDO::getId));
     }
+    default List<TripDO> selectListBySubjectId(Long subjectId) {
+        return selectList(new LambdaQueryWrapperX<TripDO>()
+                .like(TripDO::getSubjectIds, subjectId)
+                .orderByDesc(TripDO::getId));
+    }
 }

+ 79 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/service/subject/SubjectService.java

@@ -0,0 +1,79 @@
+package cn.iocoder.yudao.module.guide.service.subject;
+
+import java.util.*;
+
+import cn.iocoder.yudao.module.guide.dal.dataobject.sightscategory.SightsCategoryDO;
+import jakarta.validation.*;
+import cn.iocoder.yudao.module.guide.controller.admin.subject.vo.*;
+import cn.iocoder.yudao.module.guide.dal.dataobject.subject.SubjectDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+
+/**
+ * 观光主题 Service 接口
+ *
+ * @author GuideSystem
+ */
+public interface SubjectService {
+
+    /**
+     * 创建观光主题
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Long createSubject(@Valid SubjectSaveReqVO createReqVO);
+
+    /**
+     * 更新观光主题
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateSubject(@Valid SubjectSaveReqVO updateReqVO);
+
+    /**
+     * 删除观光主题
+     *
+     * @param id 编号
+     */
+    void deleteSubject(Long id);
+
+    /**
+     * 获得观光主题
+     *
+     * @param id 编号
+     * @return 观光主题
+     */
+    SubjectDO getSubject(Long id);
+
+    /**
+     * 获得观光主题分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 观光主题分页
+     */
+    PageResult<SubjectDO> getSubjectPage(SubjectPageReqVO pageReqVO);
+
+    /**
+     * 获得观光主题列表
+     *
+     * @param pageReqVO 查询
+     * @return 观光主题列表
+     */
+    List<SubjectDO> getSubjectList(SubjectPageReqVO pageReqVO);
+    /**
+     * 获得观光主题列表
+     *
+     * @param ids 查询条件
+     * @return 观光主题列表
+     */
+    List<SubjectDO> getSubjectList(List<Long> ids);
+
+    /**
+     * 获得观光主题分页
+     *
+     * @param PageParam 分页查询
+     * @return 观光主题分页
+     */
+    PageResult<SubjectDO> getAppSubjectPage(PageParam pageParam);
+}

+ 87 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/service/subject/SubjectServiceImpl.java

@@ -0,0 +1,87 @@
+package cn.iocoder.yudao.module.guide.service.subject;
+
+import cn.iocoder.yudao.module.guide.dal.dataobject.sightscategory.SightsCategoryDO;
+import org.springframework.stereotype.Service;
+import jakarta.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.*;
+import cn.iocoder.yudao.module.guide.controller.admin.subject.vo.*;
+import cn.iocoder.yudao.module.guide.dal.dataobject.subject.SubjectDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+
+import cn.iocoder.yudao.module.guide.dal.mysql.subject.SubjectMapper;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.guide.enums.ErrorCodeConstants.*;
+
+/**
+ * 观光主题 Service 实现类
+ *
+ * @author GuideSystem
+ */
+@Service
+@Validated
+public class SubjectServiceImpl implements SubjectService {
+
+    @Resource
+    private SubjectMapper subjectMapper;
+
+    @Override
+    public Long createSubject(SubjectSaveReqVO createReqVO) {
+        // 插入
+        SubjectDO subject = BeanUtils.toBean(createReqVO, SubjectDO.class);
+        subjectMapper.insert(subject);
+        // 返回
+        return subject.getId();
+    }
+
+    @Override
+    public void updateSubject(SubjectSaveReqVO updateReqVO) {
+        // 校验存在
+        validateSubjectExists(updateReqVO.getId());
+        // 更新
+        SubjectDO updateObj = BeanUtils.toBean(updateReqVO, SubjectDO.class);
+        subjectMapper.updateById(updateObj);
+    }
+
+    @Override
+    public void deleteSubject(Long id) {
+        // 校验存在
+        validateSubjectExists(id);
+        // 删除
+        subjectMapper.deleteById(id);
+    }
+
+    private void validateSubjectExists(Long id) {
+        if (subjectMapper.selectById(id) == null) {
+            throw exception(SUBJECT_NOT_EXISTS);
+        }
+    }
+
+    @Override
+    public SubjectDO getSubject(Long id) {
+        return subjectMapper.selectById(id);
+    }
+
+    @Override
+    public PageResult<SubjectDO> getSubjectPage(SubjectPageReqVO pageReqVO) {
+        return subjectMapper.selectPage(pageReqVO);
+    }
+    @Override
+    public List<SubjectDO> getSubjectList(SubjectPageReqVO pageReqVO) {
+        return subjectMapper.selectList(pageReqVO);
+    }
+    @Override
+    public List<SubjectDO> getSubjectList(List<Long> ids) {
+        return subjectMapper.selectList(ids);
+    }
+
+    @Override
+    public PageResult<SubjectDO> getAppSubjectPage(PageParam pageParam) {
+        return subjectMapper.selectAppPage(pageParam);
+    }
+}

+ 1 - 3
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/service/trip/TripService.java

@@ -1,9 +1,6 @@
 package cn.iocoder.yudao.module.guide.service.trip;
 
-import java.util.*;
-
 import cn.iocoder.yudao.module.guide.controller.app.trip.vo.AppTripPageReqVO;
-import cn.iocoder.yudao.module.guide.dal.dataobject.sights.SightsDO;
 import jakarta.validation.*;
 import cn.iocoder.yudao.module.guide.controller.admin.trip.vo.*;
 import cn.iocoder.yudao.module.guide.dal.dataobject.trip.TripDO;
@@ -139,6 +136,7 @@ public interface TripService {
 	 */
     TripSightsDO getTripSights(Long id);
 
+
     PageResult<TripDO> getAppTripPage(AppTripPageReqVO appPageReqVO);
 
     TripDO getAppTrip(Long id);

+ 2 - 4
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/service/trip/TripServiceImpl.java

@@ -5,15 +5,12 @@ import cn.iocoder.yudao.module.guide.dal.dataobject.sights.SightsCommentDO;
 import cn.iocoder.yudao.module.guide.dal.dataobject.sights.SightsDO;
 import cn.iocoder.yudao.module.guide.dal.dataobject.sights.SightsI18nExtensionDO;
 import cn.iocoder.yudao.module.guide.dal.dataobject.sightscategory.SightsCategoryDO;
-import cn.iocoder.yudao.module.guide.dal.dataobject.users.CommentDO;
 import cn.iocoder.yudao.module.guide.dal.dataobject.users.UsersDO;
 import cn.iocoder.yudao.module.guide.dal.mysql.sights.SightsCommentMapper;
 import cn.iocoder.yudao.module.guide.dal.mysql.sights.SightsI18nExtensionMapper;
 import cn.iocoder.yudao.module.guide.dal.mysql.sights.SightsMapper;
 import cn.iocoder.yudao.module.guide.dal.mysql.sightscategory.SightsCategoryMapper;
 import cn.iocoder.yudao.module.guide.service.users.UsersService;
-import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
-import cn.iocoder.yudao.module.system.service.user.AdminUserService;
 import org.springframework.stereotype.Service;
 import jakarta.annotation.Resource;
 import org.springframework.validation.annotation.Validated;
@@ -35,7 +32,6 @@ import cn.iocoder.yudao.module.guide.dal.mysql.trip.TripI18nExtensionMapper;
 import cn.iocoder.yudao.module.guide.dal.mysql.trip.TripSightsMapper;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
 import static cn.iocoder.yudao.module.guide.enums.ErrorCodeConstants.*;
 
 /**
@@ -53,6 +49,7 @@ public class TripServiceImpl implements TripService {
     private TripI18nExtensionMapper tripI18nExtensionMapper;
     @Resource
     private TripSightsMapper tripSightsMapper;
+
     @Resource
     private SightsCategoryMapper sightsCategoryMapper;
     @Resource
@@ -157,6 +154,7 @@ public class TripServiceImpl implements TripService {
         tripI18nExtensionMapper.deleteByTripId(tripId);
     }
 
+
     // ==================== 子表(旅程详细情报) ====================
 
     @Override

+ 7 - 1
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/service/users/UsersService.java

@@ -38,7 +38,13 @@ public interface UsersService {
      * @param id 编号
      */
     void deleteUsers(Long id);
-
+    /**
+     * 修改密码
+     *
+     * @param id       用户编号
+     * @param password 密码
+     */
+    void updateUserPassword(Long id, String password);
     /**
      * 获得导游信息
      *

+ 15 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/service/users/UsersServiceImpl.java

@@ -9,6 +9,9 @@ import cn.iocoder.yudao.module.guide.dal.dataobject.trip.TripI18nExtensionDO;
 import cn.iocoder.yudao.module.guide.dal.mysql.trip.TripI18nExtensionMapper;
 import cn.iocoder.yudao.module.guide.dal.mysql.trip.TripMapper;
 import cn.iocoder.yudao.module.guide.dal.mysql.trip.TripSightsMapper;
+import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
+import com.mzt.logapi.context.LogRecordContext;
+import com.mzt.logapi.starter.annotation.LogRecord;
 import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.stereotype.Service;
 import jakarta.annotation.Resource;
@@ -28,6 +31,7 @@ import cn.iocoder.yudao.module.guide.dal.mysql.users.CommentMapper;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.module.guide.enums.ErrorCodeConstants.*;
+import static cn.iocoder.yudao.module.system.enums.LogRecordConstants.*;
 
 /**
  * 导游信息 Service 实现类
@@ -68,6 +72,17 @@ public class UsersServiceImpl implements UsersService {
         usersMapper.updateById(updateObj);
     }
 
+    @Override
+    public void updateUserPassword(Long id, String password) {
+        // 1. 校验用户存在
+        validateUsersExists(id);
+        // 2. 更新密码
+        UsersDO updateObj = new UsersDO();
+        updateObj.setId(id);
+        updateObj.setPassword(encodePassword(password)); // 加密密码
+        usersMapper.updateById(updateObj);
+
+    }
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void deleteUsers(Long id) {

+ 12 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/resources/mapper/subject/SubjectMapper.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="cn.iocoder.yudao.module.guide.dal.mysql.subject.SubjectMapper">
+
+    <!--
+        一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
+        无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
+        代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
+        文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
+     -->
+
+</mapper>

+ 142 - 0
yudao-module-guide/yudao-module-guide-biz/src/test/java/cn/iocoder/yudao/module/guide/service/subject/SubjectServiceImplTest.java

@@ -0,0 +1,142 @@
+package cn.iocoder.yudao.module.guide.service.subject;
+
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.mock.mockito.MockBean;
+
+import jakarta.annotation.Resource;
+
+import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
+
+import cn.iocoder.yudao.module.guide.controller.admin.subject.vo.*;
+import cn.iocoder.yudao.module.guide.dal.dataobject.subject.SubjectDO;
+import cn.iocoder.yudao.module.guide.dal.mysql.subject.SubjectMapper;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+
+import jakarta.annotation.Resource;
+import org.springframework.context.annotation.Import;
+import java.util.*;
+import java.time.LocalDateTime;
+
+import static cn.hutool.core.util.RandomUtil.*;
+import static cn.iocoder.yudao.module.guide.enums.ErrorCodeConstants.*;
+import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;
+import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
+import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
+import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+/**
+ * {@link SubjectServiceImpl} 的单元测试类
+ *
+ * @author GuideSystem
+ */
+@Import(SubjectServiceImpl.class)
+public class SubjectServiceImplTest extends BaseDbUnitTest {
+
+    @Resource
+    private SubjectServiceImpl subjectService;
+
+    @Resource
+    private SubjectMapper subjectMapper;
+
+    @Test
+    public void testCreateSubject_success() {
+        // 准备参数
+        SubjectSaveReqVO createReqVO = randomPojo(SubjectSaveReqVO.class).setId(null);
+
+        // 调用
+        Long subjectId = subjectService.createSubject(createReqVO);
+        // 断言
+        assertNotNull(subjectId);
+        // 校验记录的属性是否正确
+        SubjectDO subject = subjectMapper.selectById(subjectId);
+        assertPojoEquals(createReqVO, subject, "id");
+    }
+
+    @Test
+    public void testUpdateSubject_success() {
+        // mock 数据
+        SubjectDO dbSubject = randomPojo(SubjectDO.class);
+        subjectMapper.insert(dbSubject);// @Sql: 先插入出一条存在的数据
+        // 准备参数
+        SubjectSaveReqVO updateReqVO = randomPojo(SubjectSaveReqVO.class, o -> {
+            o.setId(dbSubject.getId()); // 设置更新的 ID
+        });
+
+        // 调用
+        subjectService.updateSubject(updateReqVO);
+        // 校验是否更新正确
+        SubjectDO subject = subjectMapper.selectById(updateReqVO.getId()); // 获取最新的
+        assertPojoEquals(updateReqVO, subject);
+    }
+
+    @Test
+    public void testUpdateSubject_notExists() {
+        // 准备参数
+        SubjectSaveReqVO updateReqVO = randomPojo(SubjectSaveReqVO.class);
+
+        // 调用, 并断言异常
+        assertServiceException(() -> subjectService.updateSubject(updateReqVO), SUBJECT_NOT_EXISTS);
+    }
+
+    @Test
+    public void testDeleteSubject_success() {
+        // mock 数据
+        SubjectDO dbSubject = randomPojo(SubjectDO.class);
+        subjectMapper.insert(dbSubject);// @Sql: 先插入出一条存在的数据
+        // 准备参数
+        Long id = dbSubject.getId();
+
+        // 调用
+        subjectService.deleteSubject(id);
+       // 校验数据不存在了
+       assertNull(subjectMapper.selectById(id));
+    }
+
+    @Test
+    public void testDeleteSubject_notExists() {
+        // 准备参数
+        Long id = randomLongId();
+
+        // 调用, 并断言异常
+        assertServiceException(() -> subjectService.deleteSubject(id), SUBJECT_NOT_EXISTS);
+    }
+
+    @Test
+    @Disabled  // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
+    public void testGetSubjectPage() {
+       // mock 数据
+       SubjectDO dbSubject = randomPojo(SubjectDO.class, o -> { // 等会查询到
+           o.setTitleZh(null);
+           o.setTitleJa(null);
+           o.setTitleEn(null);
+           o.setCreateTime(null);
+       });
+       subjectMapper.insert(dbSubject);
+       // 测试 titleZh 不匹配
+       subjectMapper.insert(cloneIgnoreId(dbSubject, o -> o.setTitleZh(null)));
+       // 测试 titleJa 不匹配
+       subjectMapper.insert(cloneIgnoreId(dbSubject, o -> o.setTitleJa(null)));
+       // 测试 titleEn 不匹配
+       subjectMapper.insert(cloneIgnoreId(dbSubject, o -> o.setTitleEn(null)));
+       // 测试 createTime 不匹配
+       subjectMapper.insert(cloneIgnoreId(dbSubject, o -> o.setCreateTime(null)));
+       // 准备参数
+       SubjectPageReqVO reqVO = new SubjectPageReqVO();
+       reqVO.setTitleZh(null);
+       reqVO.setTitleJa(null);
+       reqVO.setTitleEn(null);
+       reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+
+       // 调用
+       PageResult<SubjectDO> pageResult = subjectService.getSubjectPage(reqVO);
+       // 断言
+       assertEquals(1, pageResult.getTotal());
+       assertEquals(1, pageResult.getList().size());
+       assertPojoEquals(dbSubject, pageResult.getList().get(0));
+    }
+
+}

+ 7 - 1
yudao-module-guide/yudao-module-guide-statistics-biz/src/main/java/cn/iocoder/yudao/module/guide/statistics/controller/admin/guide/GuideStatisticsController.java

@@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
 import cn.iocoder.yudao.module.guide.statistics.controller.admin.common.vo.GuideDataComparisonRespVO;
 import cn.iocoder.yudao.module.guide.statistics.controller.admin.guide.vo.GuideStatisticsReqVO;
 import cn.iocoder.yudao.module.guide.statistics.controller.admin.guide.vo.GuideStatisticsRespVO;
+import cn.iocoder.yudao.module.guide.statistics.controller.admin.guide.vo.GuideTopPageRespVO;
 import cn.iocoder.yudao.module.guide.statistics.dal.dataobject.guide.GuideStatisticsDO;
 import cn.iocoder.yudao.module.guide.statistics.service.guide.GuideStatisticsService;
 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
@@ -33,6 +34,7 @@ import java.util.Set;
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
 
 @Tag(name = "管理后台 - 商品统计")
 @RestController
@@ -85,5 +87,9 @@ public class GuideStatisticsController {
                 item -> Optional.ofNullable(guideMap.get(item.getGuideId()))
                         .ifPresent(guide -> item.setNickName(guide.getNickname()).setPicUrl(guide.getAvatar()))));
     }
-
+    @GetMapping("/guide-toppage-data")
+    @Operation(summary = "获得导游统计明细(月维度)")
+    public CommonResult<GuideDataComparisonRespVO<GuideTopPageRespVO>> getGuideTopPageData() {
+        return success(guideStatisticsService.getGuideTopPageData(getLoginUserId()));
+    }
 }

+ 41 - 0
yudao-module-guide/yudao-module-guide-statistics-biz/src/main/java/cn/iocoder/yudao/module/guide/statistics/controller/admin/guide/vo/GuideTopPageRespVO.java

@@ -0,0 +1,41 @@
+
+package cn.iocoder.yudao.module.guide.statistics.controller.admin.guide.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "管理后台 - 导游首页统计 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class GuideTopPageRespVO {
+
+        @Schema(description = "编号,主键自增", requiredMode = Schema.RequiredMode.REQUIRED, example = "12393")
+        private Long id;
+
+
+        @Schema(description = "导游编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15114")
+        @ExcelProperty("导游编号")
+        private Long guideId;
+
+        @Schema(description = "浏览量", requiredMode = Schema.RequiredMode.REQUIRED, example = "17505")
+        @ExcelProperty("浏览量")
+        private Integer browseCount;
+
+
+        @Schema(description = "收藏数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20950")
+        @ExcelProperty("收藏数量")
+        private Integer favoriteCount;
+
+
+        @Schema(description = "支付件数", requiredMode = Schema.RequiredMode.REQUIRED, example = "15142")
+        @ExcelProperty("支付件数")
+        private Integer orderPayCount;
+
+        @Schema(description = "支付金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "11595")
+        @ExcelProperty("支付金额,单位:分")
+        private Integer orderPayPrice;
+
+
+}

+ 6 - 2
yudao-module-guide/yudao-module-guide-statistics-biz/src/main/java/cn/iocoder/yudao/module/guide/statistics/dal/mysql/guide/GuideStatisticsMapper.java

@@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX;
 import cn.iocoder.yudao.module.guide.statistics.controller.admin.guide.vo.GuideStatisticsReqVO;
 import cn.iocoder.yudao.module.guide.statistics.controller.admin.guide.vo.GuideStatisticsRespVO;
+import cn.iocoder.yudao.module.guide.statistics.controller.admin.guide.vo.GuideTopPageRespVO;
 import cn.iocoder.yudao.module.guide.statistics.dal.dataobject.guide.GuideStatisticsDO;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import org.apache.ibatis.annotations.Mapper;
@@ -70,11 +71,14 @@ public interface GuideStatisticsMapper extends BaseMapperX<GuideStatisticsDO> {
      * @return 统计
      */
     IPage<GuideStatisticsDO> selectStatisticsResultPageByTimeBetween(IPage<GuideStatisticsDO> page,
-                                                                       @Param("beginTime") LocalDateTime beginTime,
-                                                                       @Param("endTime") LocalDateTime endTime);
+                                                                     @Param("beginTime") LocalDateTime beginTime,
+                                                                     @Param("endTime") LocalDateTime endTime);
 
     default Long selectCountByTimeBetween(LocalDateTime beginTime, LocalDateTime endTime) {
         return selectCount(new LambdaQueryWrapperX<GuideStatisticsDO>().between(GuideStatisticsDO::getTime, beginTime, endTime));
     }
 
+    GuideTopPageRespVO selectGuideTopPageResult(@Param("guideId") Long guideId,
+                                                        @Param("beginTime") LocalDateTime beginTime,
+                                                        @Param("endTime") LocalDateTime endTime);
 }

+ 9 - 0
yudao-module-guide/yudao-module-guide-statistics-biz/src/main/java/cn/iocoder/yudao/module/guide/statistics/service/guide/GuideStatisticsService.java

@@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.common.pojo.SortablePageParam;
 import cn.iocoder.yudao.module.guide.statistics.controller.admin.common.vo.GuideDataComparisonRespVO;
 import cn.iocoder.yudao.module.guide.statistics.controller.admin.guide.vo.GuideStatisticsReqVO;
 import cn.iocoder.yudao.module.guide.statistics.controller.admin.guide.vo.GuideStatisticsRespVO;
+import cn.iocoder.yudao.module.guide.statistics.controller.admin.guide.vo.GuideTopPageRespVO;
 import cn.iocoder.yudao.module.guide.statistics.dal.dataobject.guide.GuideStatisticsDO;
 
 import java.util.List;
@@ -32,6 +33,14 @@ public interface GuideStatisticsService {
      * @return 统计数据对照
      */
     GuideDataComparisonRespVO<GuideStatisticsRespVO> getGuideStatisticsAnalyse(GuideStatisticsReqVO reqVO);
+    /**
+     * 获得商品状况统计分析
+     *
+     * @param Long 查询条件(导游ID)
+     * @return 统计数据对照
+     */
+    GuideDataComparisonRespVO<GuideTopPageRespVO> getGuideTopPageData(Long guideId);
+
 
     /**
      * 获得商品状况明细

+ 22 - 0
yudao-module-guide/yudao-module-guide-statistics-biz/src/main/java/cn/iocoder/yudao/module/guide/statistics/service/guide/GuideStatisticsServiceImpl.java

@@ -7,10 +7,12 @@ import cn.hutool.core.util.ArrayUtil;
 import cn.hutool.core.util.ObjUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.pojo.SortablePageParam;
+import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
 import cn.iocoder.yudao.framework.common.util.object.PageUtils;
 import cn.iocoder.yudao.module.guide.statistics.controller.admin.common.vo.GuideDataComparisonRespVO;
 import cn.iocoder.yudao.module.guide.statistics.controller.admin.guide.vo.GuideStatisticsReqVO;
 import cn.iocoder.yudao.module.guide.statistics.controller.admin.guide.vo.GuideStatisticsRespVO;
+import cn.iocoder.yudao.module.guide.statistics.controller.admin.guide.vo.GuideTopPageRespVO;
 import cn.iocoder.yudao.module.guide.statistics.dal.dataobject.guide.GuideStatisticsDO;
 import cn.iocoder.yudao.module.guide.statistics.dal.mysql.guide.GuideStatisticsMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -60,6 +62,26 @@ public class GuideStatisticsServiceImpl implements GuideStatisticsService {
         return new GuideDataComparisonRespVO<>(value, reference);
     }
 
+    @Override
+    public GuideDataComparisonRespVO<GuideTopPageRespVO> getGuideTopPageData(Long guideId) {
+
+
+        LocalDateTime monthDate = LocalDateTime.now().plusMonths(0);
+        // 当月的开始时间
+        LocalDateTime beginTime = LocalDateTimeUtils.beginOfMonth(monthDate);
+        LocalDateTime endTime = LocalDateTimeUtils.endOfMonth(monthDate);
+        // 统计数据
+        GuideTopPageRespVO value = guideStatisticsMapper.selectGuideTopPageResult(guideId,beginTime,endTime);
+        // 对照数据
+        monthDate = LocalDateTime.now().plusMonths(-1);
+        beginTime = LocalDateTimeUtils.beginOfMonth(monthDate);
+        endTime = LocalDateTimeUtils.endOfMonth(monthDate);
+
+        GuideTopPageRespVO reference = guideStatisticsMapper.selectGuideTopPageResult(guideId,beginTime,endTime);
+        return new GuideDataComparisonRespVO<>(value, reference);
+    }
+
+
     @Override
     public List<GuideStatisticsDO> getGuideStatisticsList(GuideStatisticsReqVO reqVO) {
         return guideStatisticsMapper.selectListByTimeBetween(reqVO);

+ 31 - 0
yudao-module-guide/yudao-module-guide-statistics-biz/src/main/resources/mapper/guide/GuideStatisticsMapper.xml

@@ -61,4 +61,35 @@
         ORDER BY system_users.id
     </select>
 
+    <select id="selectGuideTopPageResult"
+            resultType="cn.iocoder.yudao.module.guide.statistics.controller.admin.guide.vo.GuideTopPageRespVO">
+        SELECT system_users.id AS guide_id
+             -- 浏览量:一个用户可以有多次
+             , (SELECT COUNT(1)
+                FROM guide_browse_history
+                WHERE guide_id = system_users.id
+                  AND create_time BETWEEN #{beginTime} AND #{endTime}) AS browse_count
+             -- 收藏数量:按用户去重计数
+             , (SELECT COUNT(DISTINCT user_id)
+                FROM guide_trip_favorite
+                WHERE guide_id = system_users.id
+                  AND create_time BETWEEN #{beginTime} AND #{endTime}) AS favorite_count
+             -- 支付件数
+             , (SELECT COUNT(1)
+                FROM guide_trade_order_item item
+                         JOIN guide_trade_order o ON item.order_id = o.id
+                WHERE guide_id = system_users.id
+                  AND o.pay_status = TRUE
+                  AND item.booking_date BETWEEN #{beginTime} AND #{endTime}) AS order_pay_count
+             -- 支付金额
+             , (SELECT IFNULL(SUM(item.price), 0)
+                FROM guide_trade_order_item item
+                         JOIN guide_trade_order o ON item.order_id = o.id
+                WHERE guide_id = system_users.id
+                  AND o.pay_status = TRUE
+                  AND item.booking_date BETWEEN #{beginTime} AND #{endTime}) AS order_pay_price
+        FROM system_users
+        WHERE system_users.deleted = FALSE AND system_users.dept_id = 999 AND system_users.id = #{guideId}
+        ORDER BY system_users.id
+    </select>
 </mapper>