Explorar el Código

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

libin hace 1 año
padre
commit
2cb7992ded
Se han modificado 100 ficheros con 5112 adiciones y 27 borrados
  1. 5 0
      pom.xml
  2. 4 0
      yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/Area.java
  3. 469 1
      yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/resources/area.csv
  4. BIN
      yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/resources/ip2region.xdb
  5. 5 1
      yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java
  6. 1 0
      yudao-module-guide/pom.xml
  7. 40 0
      yudao-module-guide/yudao-module-guide-api/src/main/java/cn/iocoder/yudao/module/guide/api/order/GuideTradeOrderApi.java
  8. 97 0
      yudao-module-guide/yudao-module-guide-api/src/main/java/cn/iocoder/yudao/module/guide/api/order/dto/TradeOrderRespDTO.java
  9. 51 4
      yudao-module-guide/yudao-module-guide-api/src/main/java/cn/iocoder/yudao/module/guide/enums/ErrorCodeConstants.java
  10. 16 0
      yudao-module-guide/yudao-module-guide-api/src/main/java/cn/iocoder/yudao/module/guide/enums/MessageTemplateConstants.java
  11. 48 0
      yudao-module-guide/yudao-module-guide-api/src/main/java/cn/iocoder/yudao/module/guide/enums/TimeRangeTypeEnum.java
  12. 42 0
      yudao-module-guide/yudao-module-guide-api/src/main/java/cn/iocoder/yudao/module/guide/enums/aftersale/AfterSaleOperateTypeEnum.java
  13. 95 0
      yudao-module-guide/yudao-module-guide-api/src/main/java/cn/iocoder/yudao/module/guide/enums/aftersale/AfterSaleStatusEnum.java
  14. 37 0
      yudao-module-guide/yudao-module-guide-api/src/main/java/cn/iocoder/yudao/module/guide/enums/aftersale/AfterSaleTypeEnum.java
  15. 37 0
      yudao-module-guide/yudao-module-guide-api/src/main/java/cn/iocoder/yudao/module/guide/enums/aftersale/AfterSaleWayEnum.java
  16. 38 0
      yudao-module-guide/yudao-module-guide-api/src/main/java/cn/iocoder/yudao/module/guide/enums/order/TradeOrderCancelTypeEnum.java
  17. 49 0
      yudao-module-guide/yudao-module-guide-api/src/main/java/cn/iocoder/yudao/module/guide/enums/order/TradeOrderItemAfterSaleStatusEnum.java
  18. 57 0
      yudao-module-guide/yudao-module-guide-api/src/main/java/cn/iocoder/yudao/module/guide/enums/order/TradeOrderOperateTypeEnum.java
  19. 38 0
      yudao-module-guide/yudao-module-guide-api/src/main/java/cn/iocoder/yudao/module/guide/enums/order/TradeOrderRefundStatusEnum.java
  20. 116 0
      yudao-module-guide/yudao-module-guide-api/src/main/java/cn/iocoder/yudao/module/guide/enums/order/TradeOrderStatusEnum.java
  21. 57 0
      yudao-module-guide/yudao-module-guide-api/src/main/java/cn/iocoder/yudao/module/guide/enums/order/TradeOrderTypeEnum.java
  22. 48 0
      yudao-module-guide/yudao-module-guide-biz/pom.xml
  23. 42 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/api/order/GuideTradeOrderApiImpl.java
  24. 135 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/aftersale/GuideAfterSaleController.java
  25. 33 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/aftersale/TradeAfterSaleController.http
  26. 102 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/aftersale/vo/GuideAfterSaleBaseVO.java
  27. 51 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/aftersale/vo/GuideAfterSaleDetailRespVO.java
  28. 20 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/aftersale/vo/GuideAfterSaleDisagreeReqVO.java
  29. 56 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/aftersale/vo/GuideAfterSalePageReqVO.java
  30. 19 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/aftersale/vo/GuideAfterSaleRefuseReqVO.java
  31. 29 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/aftersale/vo/GuideAfterSaleRespPageItemVO.java
  32. 36 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/aftersale/vo/log/GuideAfterSaleLogRespVO.java
  33. 4 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/base/member/package-info.java
  34. 22 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/base/member/user/MemberUserRespVO.java
  35. 4 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/base/package-info.java
  36. 22 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/base/product/property/ProductPropertyValueDetailRespVO.java
  37. 39 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/history/GuideBrowseHistoryController.java
  38. 40 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/history/vo/GuideBrowseHistoryPageReqVO.java
  39. 42 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/history/vo/GuideBrowseHistoryRespVO.java
  40. 133 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/order/GuideTradeOrderController.java
  41. 151 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/order/vo/GuideTradeOrderBaseVO.java
  42. 22 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/order/vo/GuideTradeOrderDeliveryReqVO.java
  43. 48 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/order/vo/GuideTradeOrderDetailRespVO.java
  44. 81 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/order/vo/GuideTradeOrderItemBaseVO.java
  45. 30 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/order/vo/GuideTradeOrderPageItemRespVO.java
  46. 64 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/order/vo/GuideTradeOrderPageReqVO.java
  47. 20 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/order/vo/GuideTradeOrderRemarkReqVO.java
  48. 22 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/order/vo/GuideTradeOrderSummaryRespVO.java
  49. 32 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/order/vo/GuideTradeOrderUpdateAddressReqVO.java
  50. 19 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/order/vo/GuideTradeOrderUpdatePriceReqVO.java
  51. 82 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/schedule/ScheduleController.java
  52. 36 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/schedule/vo/SchedulePageReqVO.java
  53. 40 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/schedule/vo/ScheduleRespVO.java
  54. 33 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/schedule/vo/ScheduleSaveReqVO.java
  55. 77 16
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/sights/SightsController.java
  56. 7 1
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/sights/vo/SightsPageReqVO.java
  57. 20 1
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/sights/vo/SightsRespVO.java
  58. 6 3
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/sights/vo/SightsSaveReqVO.java
  59. 8 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/sightscategory/SightsCategoryController.java
  60. 190 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/trip/TripController.java
  61. 25 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/trip/vo/TripPageReqVO.java
  62. 54 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/trip/vo/TripRespVO.java
  63. 51 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/trip/vo/TripSaveReqVO.java
  64. 24 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/trip/vo/TripSightsSaveVO.java
  65. 158 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/users/UsersController.java
  66. 37 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/users/vo/UsersPageReqVO.java
  67. 111 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/users/vo/UsersRespVO.java
  68. 98 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/users/vo/UsersSaveReqVO.java
  69. 4 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/base/package-info.java
  70. 22 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/base/property/AppProductPropertyValueDetailRespVO.java
  71. 42 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/cart/AppCartController.http
  72. 87 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/cart/AppGuideCartController.java
  73. 25 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/cart/vo/AppGuideCartAddReqVO.java
  74. 23 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/cart/vo/AppGuideCartListRespVO.java
  75. 29 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/cart/vo/AppGuideCartResetReqVO.java
  76. 21 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/cart/vo/AppGuideCartUpdateBookingDateReqVO.java
  77. 21 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/cart/vo/AppGuideCartUpdateSelectedReqVO.java
  78. 105 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/favorite/AppGuideTripFavoriteController.java
  79. 19 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/favorite/vo/AppFavoriteBatchReqVO.java
  80. 22 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/favorite/vo/AppFavoriteReqVO.java
  81. 38 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/favorite/vo/AppFavoriteRespVO.java
  82. 10 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/favorite/vo/AppGuideTripPageReqVO.java
  83. 100 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/history/AppGuideBrowseHistoryController.java
  84. 18 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/history/vo/AppGuideBrowseHistoryDeleteReqVO.java
  85. 24 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/history/vo/AppGuideBrowseHistoryPageReqVO.java
  86. 37 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/history/vo/AppGuideBrowseHistoryRespVO.java
  87. 94 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/must/AppGuideMustController.java
  88. 10 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/must/vo/AppGuideMustPageReqVO.java
  89. 15 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/must/vo/AppGuideMustReqVO.java
  90. 25 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/must/vo/AppGuideMustRespVO.java
  91. 180 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/order/AppGuideTradeOrderController.java
  92. 23 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/order/vo/AppGuideOrderExpressTrackRespDTO.java
  93. 22 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/order/vo/AppGuideTradeOrderCreateReqVO.java
  94. 16 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/order/vo/AppGuideTradeOrderCreateRespVO.java
  95. 148 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/order/vo/AppGuideTradeOrderDetailRespVO.java
  96. 56 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/order/vo/AppGuideTradeOrderPageItemRespVO.java
  97. 20 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/order/vo/AppGuideTradeOrderPageReqVO.java
  98. 46 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/order/vo/AppGuideTradeOrderSettlementRespVO.java
  99. 47 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/order/vo/OrderSettlementReqVO.java
  100. 38 0
      yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/order/vo/item/AppGuideTradeOrderItemCommentCreateReqVO.java

+ 5 - 0
pom.xml

@@ -150,6 +150,11 @@
             <name>aliyun</name>
             <url>https://maven.aliyun.com/repository/public</url>
         </repository>
+        <repository>
+            <id>central</id>
+            <url>https://repo1.maven.org/maven2</url>
+        </repository>
+
     </repositories>
 
 </project>

+ 4 - 0
yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/Area.java

@@ -27,6 +27,10 @@ public class Area {
      * 编号 - 中国
      */
     public static final Integer ID_CHINA = 1;
+    /**
+     * 编号 - 日本
+     */
+    public static final Integer ID_JAPAN = 5;
 
     /**
      * 编号

+ 469 - 1
yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/resources/area.csv

@@ -3659,4 +3659,472 @@ id,name,type,parentId
 659008,可克达拉市,4,659000
 659009,昆玉市,4,659000
 659010,胡杨河市,4,659000
-659011,新星市,4,659000
+659011,新星市,4,659000
+901000,北海道,2,5
+901100,道南 (Southern Hokkaido),3,901000
+901101,函館,4,901100
+901102,松前,4,901100
+901103,七飯,4,901100
+901200,道西 (Western Hokkaido),3,901000
+901201,小樽,4,901200
+901202,札幌,4,901200
+901203,倶知安・ニセコ,4,901200
+901204,積丹,4,901200
+901300,道央 (Central Hokkaido),3,901000
+901301,登別,4,901300
+901302,洞爺湖・壮瞥,4,901300
+901303,旭川,4,901300
+901304,富良野,4,901300
+901305,上川,4,901300
+901306,東川,4,901300
+901307,美瑛,4,901300
+901308,占冠,4,901300
+901400,道北 (Northern Hokkaido),3,901000
+901401,稚内,4,901400
+901402,豊富・幌延,4,901400
+901403,礼文,4,901400
+901404,利尻町,4,901400
+901500,道東 (Eastern Hokkaido),3,901000
+901501,網走,4,901500
+901502,紋別,4,901500
+901503,斜里・羅臼,4,901500
+901504,釧路,4,901500
+901505,弟子屈,4,901500
+901506,根室,4,901500
+901507,別海,4,901500
+902000,東北,2,5
+902100,青森県,3,902000
+902101,青森,4,902100
+902102,むつ市・大間・東通,4,902100
+902103,弘前,4,902100
+902104,十和田市・秋田県小坂,4,902100
+902200,岩手県,3,902000
+902201,盛岡,4,902200
+902202,葛巻,4,902200
+902203,花巻,4,902200
+902204,遠野,4,902200
+902205,奥州,4,902200
+902206,平泉,4,902200
+902207,一関,4,902200
+902208,三陸海岸,4,902200
+902209,岩泉,4,902200
+902300,宮城県,3,902000
+902301,仙台,4,902300
+902302,松島・塩竈・東松島市,4,902300
+902303,大崎市鳴子地区,4,902300
+902400,秋田県,3,902000
+902401,男鹿,4,902400
+902402,横手,4,902400
+902403,大仙市,4,902400
+902404,北部を除く仙北市,4,902400
+902500,山形県,3,902000
+902501,南東部を除く山形,4,902500
+902502,東部を除く上山,4,902500
+902503,鶴岡・庄内町・西川,4,902500
+902600,福島県,3,902000
+902601,会津若松,4,902600
+902602,喜多方,4,902600
+902603,猪苗代町・北塩原・磐梯町,4,902600
+902604,いわき市,4,902600
+902605,檜枝岐,4,902600
+903000,関東,2,5
+903100,茨城県,3,903000
+903101,水戸,4,903100
+903102,つくば,4,903100
+903103,大洗,4,903100
+903104,大子,4,903100
+903105,牛久,4,903100
+903200,栃木県,3,903000
+903201,宇都宮,4,903200
+903202,足利,4,903200
+903203,栃木,4,903200
+903204,佐野,4,903200
+903205,鹿沼,4,903200
+903206,真岡,4,903200
+903207,大田原,4,903200
+903208,那須塩原市・那須町,4,903200
+903209,日光,4,903200
+903210,足尾,4,903200
+903300,群馬県,3,903000
+903301,桐生・大間々,4,903300
+903302,草津,4,903300
+903303,渋川,4,903300
+903304,水上,4,903300
+903305,嬬恋・長野原,4,903300
+903400,埼玉県,3,903000
+903401,大宮,4,903400
+903402,川越,4,903400
+903403,所沢,4,903400
+903404,日高,4,903400
+903405,秩父・長瀞,4,903400
+903406,蓮田,4,903400
+903500,千葉県,3,903000
+903501,千葉市,4,903500
+903502,香取佐原,4,903500
+903503,船橋,4,903500
+903504,市川,4,903500
+903505,浦安,4,903500
+903506,成田,4,903500
+903507,木更津,4,903500
+903508,富津,4,903500
+903509,袖ケ浦,4,903500
+903510,市原,4,903500
+903511,銚子,4,903500
+903512,山武,4,903500
+903513,勝浦,4,903500
+903514,安房鴨川,4,903500
+903515,館山・南房総市,4,903500
+903516,大多喜,4,903500
+903600,東京都,3,903000
+903601,墨田,4,903600
+903602,上野,4,903600
+903603,浅草,4,903600
+903604,秋葉原,4,903600
+903605,丸の内・東京・銀座・築地,4,903600
+903606,後楽・水道橋,4,903600
+903607,九段下,4,903600
+903608,原宿,4,903600
+903609,渋谷,4,903600
+903610,芝公園,4,903600
+903611,浜松町,4,903600
+903612,神楽坂,4,903600
+903613,新宿,4,903600
+903614,両国,4,903600
+903615,羽田,4,903600
+903616,八王子,4,903600
+903617,奥多摩・檜原,4,903600
+903700,神奈川県,3,903000
+903701,横浜,4,903700
+903702,鎌倉,4,903700
+903703,逗子・葉山,4,903700
+903704,横須賀,4,903700
+903705,三崎,4,903700
+903706,藤沢・茅ヶ崎,4,903700
+903707,海老名市,4,903700
+903708,座間市,4,903700
+903709,伊勢原・秦野,4,903700
+903710,相模湖,4,903700
+903711,小田原,4,903700
+903712,大磯,4,903700
+903713,湯河原,4,903700
+903714,箱根,4,903700
+904000,甲信越,2,5
+904100,新潟県,3,904000
+904101,十日町・津南,4,904100
+904102,妙高赤倉,4,904100
+904103,越後湯沢,4,904100
+904104,佐渡,4,904100
+904105,村上,4,904100
+904106,弥彦村,4,904100
+904200,山梨県,3,904000
+904201,富士吉田,4,904200
+904202,河口湖・山中湖,4,904200
+904203,北杜市,4,904200
+904204,甲府市,4,904200
+904205,笛吹市,4,904200
+904206,身延,4,904200
+904300,長野県,3,904000
+904301,野辺山,4,904300
+904302,小諸,4,904300
+904303,長野,4,904300
+904304,小布施,4,904300
+904305,山ノ内,4,904300
+904306,弥彦村,4,904300
+904307,信濃町,4,904300
+904308,千曲市,4,904300
+904309,上田,4,904300
+904311,松本市,4,904300
+904312,安曇野,4,904300
+904313,白馬・小谷,4,904300
+904314,軽井沢,4,904300
+904315,駒ヶ根・宮田,4,904300
+904316,飯田,4,904300
+904317,阿智,4,904300
+904318,木曽町・王滝・木祖,4,904300
+904319,塩尻市楢川地区,4,904300
+904320,上松,4,904300
+904321,南木曽,4,904300
+904322,茅野・立科,4,904300
+904323,上諏訪・下諏訪,4,904300
+905000,中部地方,2,5
+905100,富山県,3,905000
+905101,黒部,4,905100
+905102,立山,4,905100
+905103,高岡,4,905100
+905200,石川県,3,905000
+905201,金沢,4,905200
+905202,七尾,4,905200
+905203,輪島・珠洲・能登町・穴水の奥能登,4,905200
+905204,羽咋・志賀・宝達志水,4,905200
+905205,加賀市,4,905200
+905300,福井県,3,905000
+905301,芦原,4,905300
+905302,福井,4,905300
+905303,永平寺町,4,905300
+905304,坂井市,4,905300
+905305,越前町,4,905300
+905306,敦賀,4,905300
+905307,美浜・若狭町,4,905300
+905308,小浜,4,905300
+905400,静岡県,3,905000
+905401,熱海,4,905400
+905402,三島,4,905400
+905403,沼津,4,905400
+905404,伊豆市,4,905400
+905405,伊東,4,905400
+905406,掛川,4,905400
+905407,静岡,4,905400
+905408,富士宮,4,905400
+905409,浜松,4,905400
+905500,岐阜県,3,905000
+905501,高根地区,4,905500
+905502,奥飛騨温泉郷地区,4,905500
+905503,下呂,4,905500
+905504,郡上,4,905500
+905600,愛知県,3,905000
+905601,名古屋,4,905600
+905602,瀬戸,4,905600
+905603,常滑,4,905600
+905604,半田,4,905600
+905605,南知多,4,905600
+905606,豊川,4,905600
+905607,岡崎,4,905600
+905608,蒲郡,4,905600
+905609,犬山,4,905600
+905610,豊田,4,905600
+905611,田原,4,905600
+906000,近畿,2,5
+906100,三重県,3,906000
+906101,桑名,4,906100
+906102,四日市,4,906100
+906103,鈴鹿・亀山,4,906100
+906104,伊賀上野・名張,4,906100
+906105,松阪,4,906100
+906106,伊勢,4,906100
+906107,鳥羽,4,906100
+906108,志摩,4,906100
+906109,尾鷲・熊野市,4,906100
+906200,滋賀県,3,906000
+906201,長浜,4,906200
+906202,彦根,4,906200
+906203,近江八幡,4,906200
+906204,甲賀,4,906200
+906205,大津,4,906200
+906300,京都府,3,906000
+906301,舞鶴,4,906300
+906302,京丹後,4,906300
+906303,宮津,4,906300
+906304,伊根,4,906300
+906305,京都,4,906300
+906306,宇治,4,906300
+906307,八幡,4,906300
+906308,亀岡,4,906300
+906400,大阪府,3,906000
+906401,大阪,4,906400
+906402,高槻,4,906400
+906403,箕面,4,906400
+906404,吹田,4,906400
+906405,堺,4,906400
+906406,河内長野,4,906400
+906500,兵庫県,3,906000
+906501,神戸,4,906500
+906502,姫路,4,906500
+906503,龍野,4,906500
+906504,赤穂,4,906500
+906505,佐用,4,906500
+906506,丹波篠山,4,906500
+906507,朝来,4,906500
+906508,豊岡,4,906500
+906509,養父,4,906500
+906510,香美,4,906500
+906511,新温泉,4,906500
+906512,志筑,4,906500
+906513,福良,4,906500
+906514,洲本,4,906500
+906600,奈良県,3,906000
+906601,奈良,4,906600
+906602,斑鳩,4,906600
+906603,橿原,4,906600
+906604,天理,4,906600
+906605,桜井,4,906600
+906606,明日香,4,906600
+906607,宇陀市,4,906600
+906608,葛城,4,906600
+906609,吉野,4,906600
+906700,和歌山県,3,906000
+906701,高野,4,906700
+906702,和歌山,4,906700
+906703,海南,4,906700
+906704,新宮,4,906700
+906705,紀伊田辺,4,906700
+906706,那智勝浦,4,906700
+906707,南紀白浜,4,906700
+906708,串本,4,906700
+906709,紀の川市,4,906700
+906710,岩出,4,906700
+907000,中国,2,5
+907100,鳥取県,3,907000
+907101,鳥取,4,907100
+907102,智頭,4,907100
+907103,若桜,4,907100
+907104,三朝,4,907100
+907105,湯梨浜,4,907100
+907106,倉吉市,4,907100
+907107,米子,4,907100
+907108,大山,4,907100
+907200,島根県,3,907000
+907201,松江,4,907200
+907202,出雲市,4,907200
+907203,大田,4,907200
+907204,益田,4,907200
+907205,津和野,4,907200
+907206,隠岐,4,907200
+907300,岡山県,3,907000
+907301,美作市,4,907300
+907302,岡山,4,907300
+907303,倉敷,4,907300
+907304,高梁,4,907300
+907305,備前市,4,907300
+907306,真庭市,4,907300
+907400,広島県,3,907000
+907401,福山,4,907400
+907402,尾道,4,907400
+907403,広島,4,907400
+907404,廿日市市宮島,4,907400
+907405,竹原,4,907400
+907406,呉,4,907400
+907500,山口県,3,907000
+907501,下関,4,907500
+907502,萩,4,907500
+907503,長門市,4,907500
+907504,山口,4,907500
+907505,防府,4,907500
+907506,岩国,4,907500
+907507,美祢,4,907500
+908000,四国,2,5
+908100,徳島県,3,908000
+908101,徳島,4,908100
+908102,鳴門,4,908100
+908103,脇町,4,908100
+908104,阿波池田,4,908100
+908200,香川県,3,908000
+908201,三本松,4,908200
+908202,小豆島,4,908200
+908203,直島町,4,908200
+908204,高松,4,908200
+908205,丸亀,4,908200
+908206,琴平,4,908200
+908300,愛媛県,3,908000
+908301,松山,4,908300
+908302,今治,4,908300
+908303,新居浜,4,908300
+908304,伊予西条・久万高原,4,908300
+908305,内子,4,908300
+908306,大洲,4,908300
+908307,宇和島,4,908300
+908400,高知県,3,908000
+908401,高知,4,908400
+908402,中村,4,908400
+908403,土佐清水,4,908400
+908404,香美市,4,908400
+909000,九州・沖縄,2,5
+909100,福岡県,3,909000
+909101,福岡,4,909100
+909102,宗像,4,909100
+909103,太宰府,4,909100
+909104,北九州市,4,909100
+909105,飯塚,4,909100
+909106,田川,4,909100
+909107,香春,4,909100
+909108,添田,4,909100
+909109,赤村,4,909100
+909110,筑前,4,909100
+909111,朝倉,4,909100
+909112,筑後,4,909100
+909113,柳川,4,909100
+909114,大牟田,4,909100
+909200,佐賀県,3,909000
+909201,佐賀,4,909200
+909202,唐津,4,909200
+909203,伊万里,4,909200
+909204,有田町,4,909200
+909205,鹿島,4,909200
+909206,神埼・吉野ヶ里,4,909200
+909207,武雄,4,909200
+909208,嬉野,4,909200
+909209,小城市,4,909200
+909300,長崎県,3,909000
+909301,長崎,4,909300
+909302,島原,4,909300
+909303,雲仙,4,909300
+909304,佐世保,4,909300
+909305,諫早,4,909300
+909306,平戸,4,909300
+909307,五島,4,909300
+909308,壱岐,4,909300
+909400,熊本県,3,909000
+909401,熊本,4,909400
+909402,阿蘇,4,909400
+909403,南小国・小国,4,909400
+909404,玉名,4,909400
+909405,菊池,4,909400
+909406,山鹿,4,909400
+909407,荒尾,4,909400
+909408,八代,4,909400
+909409,天草,4,909400
+909410,人吉・球磨村,4,909400
+909500,大分県,3,909000
+909501,中津,4,909500
+909502,豊後高田,4,909500
+909503,別府,4,909500
+909504,大分,4,909500
+909505,臼杵,4,909500
+909506,宇佐,4,909500
+909507,日田,4,909500
+909508,由布,4,909500
+909509,玖珠,4,909500
+909510,九重,4,909500
+909511,竹田,4,909500
+909512,佐伯,4,909500
+909600,宮崎県,3,909000
+909601,高千穂,4,909600
+909602,日之影,4,909600
+909603,五ヶ瀬,4,909600
+909604,椎葉,4,909600
+909605,延岡,4,909600
+909606,日向市,4,909600
+909607,都農,4,909600
+909608,高鍋,4,909600
+909609,木城,4,909600
+909610,西都,4,909600
+909611,新富,4,909600
+909612,綾,4,909600
+909613,宮崎,4,909600
+909614,加久藤,4,909600
+909615,都城,4,909600
+909616,日南,4,909600
+909617,串間,4,909600
+909700,鹿児島県,3,909000
+909701,鹿児島,4,909700
+909702,指宿,4,909700
+909703,南九州市,4,909700
+909704,霧島市,4,909700
+909705,出水市,4,909700
+909706,鹿屋,4,909700
+909707,肝付,4,909700
+909708,南大隅町,4,909700
+909709,屋久島,4,909700
+909710,西之表,4,909700
+909711,奄美,4,909700
+909712,いちき串木野市,4,909700
+909800,沖縄県,3,909000
+909801,那覇,4,909800
+909802,恩納,4,909800
+909803,中城,4,909800
+909804,うるま市,4,909800
+909805,読谷,4,909800
+909806,今帰仁,4,909800
+909807,南城市,4,909800
+909808,糸満市,4,909800
+909809,石垣島,4,909800
+909810,竹富町,4,909800

BIN
yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/resources/ip2region.xdb


+ 5 - 1
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java

@@ -93,7 +93,11 @@ public interface BaseMapperX<T> extends MPJBaseMapper<T> {
         return selectOne(new LambdaQueryWrapper<T>().eq(field1, value1).eq(field2, value2)
                 .eq(field3, value3));
     }
-
+    default T selectOne(SFunction<T, ?> field1, Object value1, SFunction<T, ?> field2, Object value2,
+                        SFunction<T, ?> field3, Object value3,SFunction<T, ?> field4, Object value4) {
+        return selectOne(new LambdaQueryWrapper<T>().eq(field1, value1).eq(field2, value2)
+                .eq(field3, value3).eq(field4, value4));
+    }
     default Long selectCount() {
         return selectCount(new QueryWrapper<>());
     }

+ 1 - 0
yudao-module-guide/pom.xml

@@ -19,6 +19,7 @@
     <modules>
         <module>yudao-module-guide-api</module>
         <module>yudao-module-guide-biz</module>
+        <module>yudao-module-guide-statistics-biz</module>
     </modules>
 
 </project>

+ 40 - 0
yudao-module-guide/yudao-module-guide-api/src/main/java/cn/iocoder/yudao/module/guide/api/order/GuideTradeOrderApi.java

@@ -0,0 +1,40 @@
+package cn.iocoder.yudao.module.guide.api.order;
+
+import cn.iocoder.yudao.module.guide.api.order.dto.TradeOrderRespDTO;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 订单 API 接口
+ *
+ * @author HUIHUI
+ */
+public interface GuideTradeOrderApi {
+
+    /**
+     * 获得订单列表
+     *
+     * @param ids 订单编号数组
+     * @return 订单列表
+     */
+    List<TradeOrderRespDTO> getOrderList(Collection<Long> ids);
+
+    /**
+     * 获得订单
+     *
+     * @param id 订单编号
+     * @return 订单
+     */
+    TradeOrderRespDTO getOrder(Long id);
+
+    // TODO 芋艿:需要优化下;
+    /**
+     * 取消支付订单
+     *
+     * @param userId  用户编号
+     * @param orderId 订单编号
+     */
+    void cancelPaidOrder(Long userId, Long orderId);
+
+}

+ 97 - 0
yudao-module-guide/yudao-module-guide-api/src/main/java/cn/iocoder/yudao/module/guide/api/order/dto/TradeOrderRespDTO.java

@@ -0,0 +1,97 @@
+package cn.iocoder.yudao.module.guide.api.order.dto;
+
+import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
+import cn.iocoder.yudao.module.guide.enums.order.TradeOrderCancelTypeEnum;
+import cn.iocoder.yudao.module.guide.enums.order.TradeOrderStatusEnum;
+import cn.iocoder.yudao.module.guide.enums.order.TradeOrderTypeEnum;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * 订单信息 Response DTO
+ *
+ * @author HUIHUI
+ */
+@Data
+public class TradeOrderRespDTO {
+
+    // ========== 订单基本信息 ==========
+    /**
+     * 订单编号,主键自增
+     */
+    private Long id;
+    /**
+     * 订单流水号
+     *
+     * 例如说,1146347329394184195
+     */
+    private String no;
+    /**
+     * 订单类型
+     *
+     * 枚举 {@link TradeOrderTypeEnum}
+     */
+    private Integer type;
+    /**
+     * 订单来源
+     *
+     * 枚举 {@link TerminalEnum}
+     */
+    private Integer terminal;
+    /**
+     * 用户编号
+     */
+    private Long userId;
+    /**
+     * 用户 IP
+     */
+    private String userIp;
+    /**
+     * 用户备注
+     */
+    private String userRemark;
+    /**
+     * 订单状态
+     *
+     * 枚举 {@link TradeOrderStatusEnum}
+     */
+    private Integer status;
+    /**
+     * 购买的商品数量
+     */
+    private Integer productCount;
+    /**
+     * 订单完成时间
+     */
+    private LocalDateTime finishTime;
+    /**
+     * 订单取消时间
+     */
+    private LocalDateTime cancelTime;
+    /**
+     * 取消类型
+     *
+     * 枚举 {@link TradeOrderCancelTypeEnum}
+     */
+    private Integer cancelType;
+    /**
+     * 商家备注
+     */
+    private String remark;
+    /**
+     * 是否评价
+     */
+    private Boolean commentStatus;
+
+    // ========== 价格 + 支付基本信息 ==========
+    /**
+     * 支付订单编号
+     */
+    private Long payOrderId;
+    /**
+     * 是否已支付
+     */
+    private Boolean payStatus;
+
+}

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

@@ -16,9 +16,56 @@ public interface ErrorCodeConstants {
 
     ErrorCode SIGHTS_CATEGORY_PARENT_IS_CHILD = new ErrorCode(9-00-000-007, "不能设置自己的子SightsCategory为父SightsCategory");
 
-    ErrorCode SIGHTS_NOT_EXISTS = new ErrorCode(9-00-002-001, "观光景点基本信息不存在");
-    ErrorCode SIGHTS_I18N_EXTENSION_NOT_EXISTS = new ErrorCode(9-00-002-002, "观光景点对语言扩充信息不存在");
+    ErrorCode SIGHTS_NOT_EXISTS = new ErrorCode(9-00-002-001, "观光景点不存在");
+    ErrorCode SIGHTS_COMMENT_NOT_EXISTS = new ErrorCode(9-00-002-002, "观光景点评论不存在");
+    ErrorCode SIGHTS_I18N_EXTENSION_NOT_EXISTS = new ErrorCode(9-00-002-003, "观光景点多语言扩充信息不存在");
+
+    ErrorCode TRIP_NOT_EXISTS = new ErrorCode(9-00-004-001, "旅程基本情报不存在");
+    ErrorCode TRIP_I18N_EXTENSION_NOT_EXISTS = new ErrorCode(9-00-004-002, "旅程多语言扩充信息不存在");
+    ErrorCode TRIP_SIGHTS_NOT_EXISTS = new ErrorCode(9-00-004-003, "旅程详细情报不存在");
+
+    ErrorCode USERS_NOT_EXISTS = new ErrorCode(9-00-005-001, "导游信息不存在");
+    ErrorCode COMMENT_NOT_EXISTS = new ErrorCode(9-00-005-002, "导游评论不存在");
+    ErrorCode SCHEDULE_NOT_EXISTS = new ErrorCode(9-00-006-001, "预约旅程日程管理情报不存在");
+    ErrorCode GUIDE_CARD_ITEM_NOT_FOUND = new ErrorCode(9_00_007_001, "购物车项不存在");
+
+    ErrorCode ORDER_ITEM_NOT_FOUND = new ErrorCode(9_00_008_010, "交易订单项不存在");
+    ErrorCode ORDER_NOT_FOUND = new ErrorCode(9_00_008_011, "交易订单不存在");
+
+
+    ErrorCode ORDER_ITEM_UPDATE_AFTER_SALE_STATUS_FAIL = new ErrorCode(9_00_008_012, "交易订单项更新售后状态失败,请重试");
+    ErrorCode ORDER_UPDATE_PAID_STATUS_NOT_UNPAID = new ErrorCode(9_00_008_013, "交易订单更新支付状态失败,订单不是【未支付】状态");
+    ErrorCode ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR = new ErrorCode(9_00_008_014, "交易订单更新支付状态失败,支付单编号不匹配");
+    ErrorCode ORDER_UPDATE_PAID_FAIL_PAY_ORDER_STATUS_NOT_SUCCESS = new ErrorCode(9_00_008_015, "交易订单更新支付状态失败,支付单状态不是【支付成功】状态");
+    ErrorCode ORDER_UPDATE_PAID_FAIL_PAY_PRICE_NOT_MATCH = new ErrorCode(9_00_008_016, "交易订单更新支付状态失败,支付单金额不匹配");
+    ErrorCode ORDER_DELIVERY_FAIL_STATUS_NOT_UNDELIVERED = new ErrorCode(9_00_008_017, "交易订单发货失败,订单不是【待发货】状态");
+    ErrorCode ORDER_RECEIVE_FAIL_STATUS_NOT_DELIVERED = new ErrorCode(9_00_008_018, "交易订单收货失败,订单不是【待收货】状态");
+    ErrorCode ORDER_COMMENT_FAIL_STATUS_NOT_COMPLETED = new ErrorCode(9_00_008_019, "创建交易订单项的评价失败,订单不是【已完成】状态");
+    ErrorCode ORDER_COMMENT_STATUS_NOT_FALSE = new ErrorCode(9_00_008_020, "创建交易订单项的评价失败,订单已评价");
+    ErrorCode ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID = new ErrorCode(9_00_008_021, "交易订单取消失败,订单不是【待支付】状态");
+    ErrorCode ORDER_DELETE_FAIL_STATUS_NOT_CANCEL = new ErrorCode(9_00_008_022, "交易订单删除失败,订单不是【已取消】状态");
+    ErrorCode ORDER_UPDATE_PRICE_FAIL_PAID = new ErrorCode(9_00_008_023, "支付订单调价失败,原因:支付订单已付款,不能调价");
+
+    ErrorCode ORDER_SETTLEMENT_FAIL_FOUND = new ErrorCode(9_00_008_024, "已经有相同的订单存在");
+    ErrorCode ORDER_SETTLEMENT_FAIL_SAMEDATE = new ErrorCode(9_00_008_025, "相同日期已经被其他人预约");
+
+    ErrorCode ORDER_ITEM_FAIL_EXISTS = new ErrorCode(9_00_008_025, "订单中有重复预约");
+    ErrorCode FAVORITE_EXISTS = new ErrorCode(9_00_009_000, "已经被收藏");
+    ErrorCode FAVORITE_NOT_EXISTS = new ErrorCode(9_00_009_001, "收藏不存在");
+
+    ErrorCode AFTER_SALE_NOT_FOUND = new ErrorCode(9_00_010_001, "售后单不存在");
+    ErrorCode AFTER_SALE_CREATE_FAIL_REFUND_PRICE_ERROR = new ErrorCode(9_00_010_002, "申请退款金额错误");
+    ErrorCode AFTER_SALE_CREATE_FAIL_ORDER_STATUS_CANCELED = new ErrorCode(9_00_010_003, "订单已关闭,无法申请售后");
+    ErrorCode AFTER_SALE_CREATE_FAIL_ORDER_STATUS_NO_PAID = new ErrorCode(9_00_010_004, "订单未支付,无法申请售后");
+    ErrorCode AFTER_SALE_CREATE_FAIL_ORDER_STATUS_NO_DELIVERED = new ErrorCode(9_00_010_005, "订单未发货,无法申请【退货退款】售后");
+    ErrorCode AFTER_SALE_CREATE_FAIL_ORDER_ITEM_APPLIED = new ErrorCode(9_00_010_006, "订单项已申请售后,无法重复申请");
+    ErrorCode AFTER_SALE_AUDIT_FAIL_STATUS_NOT_APPLY = new ErrorCode(9_00_010_007, "审批失败,售后状态不处于审批中");
+    ErrorCode AFTER_SALE_UPDATE_STATUS_FAIL = new ErrorCode(9_00_010_008, "操作售后单失败,请刷新后重试");
+    ErrorCode AFTER_SALE_DELIVERY_FAIL_STATUS_NOT_SELLER_AGREE = new ErrorCode(9_00_010_009, "退货失败,售后单状态不处于【待买家退货】");
+    ErrorCode AFTER_SALE_CONFIRM_FAIL_STATUS_NOT_BUYER_DELIVERY = new ErrorCode(9_00_010_010, "确认收货失败,售后单状态不处于【待确认收货】");
+    ErrorCode AFTER_SALE_REFUND_FAIL_STATUS_NOT_WAIT_REFUND = new ErrorCode(9_00_010_011, "退款失败,售后单状态不是【待退款】");
+    ErrorCode AFTER_SALE_CANCEL_FAIL_STATUS_NOT_APPLY_OR_AGREE_OR_BUYER_DELIVERY =
+            new ErrorCode(9_00_010_012, "取消售后单失败,售后单状态不是【待审核】或【卖家同意】或【商家待收货】");
+
 
-    ErrorCode SIGHTS_COMMENT_NOT_EXISTS = new ErrorCode(9-00-004-001, "观光景点评论不存在");
-    ErrorCode SIGHTS4COMMENT_NOT_EXISTS = new ErrorCode(9-00-005-001, "观光景点评价不存在");
 }

+ 16 - 0
yudao-module-guide/yudao-module-guide-api/src/main/java/cn/iocoder/yudao/module/guide/enums/MessageTemplateConstants.java

@@ -0,0 +1,16 @@
+package cn.iocoder.yudao.module.guide.enums;
+
+// TODO @芋艿:枚举
+/**
+ * 通知模板枚举类
+ *
+ * @author HUIHUI
+ */
+public interface MessageTemplateConstants {
+
+    String ORDER_DELIVERY = "order_delivery"; // 短信模版编号
+
+    String BROKERAGE_WITHDRAW_AUDIT_APPROVE = "brokerage_withdraw_audit_approve"; // 佣金提现(审核通过)
+    String BROKERAGE_WITHDRAW_AUDIT_REJECT = "brokerage_withdraw_audit_reject"; // 佣金提现(审核不通过)
+
+}

+ 48 - 0
yudao-module-guide/yudao-module-guide-api/src/main/java/cn/iocoder/yudao/module/guide/enums/TimeRangeTypeEnum.java

@@ -0,0 +1,48 @@
+package cn.iocoder.yudao.module.guide.enums;
+
+import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * 时间范围类型的枚举
+ *
+ * @author owen
+ */
+@AllArgsConstructor
+@Getter
+public enum TimeRangeTypeEnum implements IntArrayValuable {
+
+    /**
+     * 天
+     */
+    DAY(1),
+    /**
+     * 周
+     */
+    WEEK(7),
+    /**
+     * 月
+     */
+    MONTH(30),
+    /**
+     * 年
+     */
+    YEAR(365),
+    ;
+
+    public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TimeRangeTypeEnum::getType).toArray();
+
+    /**
+     * 类型
+     */
+    private final Integer type;
+
+    @Override
+    public int[] array() {
+        return ARRAYS;
+    }
+
+}

+ 42 - 0
yudao-module-guide/yudao-module-guide-api/src/main/java/cn/iocoder/yudao/module/guide/enums/aftersale/AfterSaleOperateTypeEnum.java

@@ -0,0 +1,42 @@
+package cn.iocoder.yudao.module.guide.enums.aftersale;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * 售后操作类型的枚举
+ *
+ * @author 陈賝
+ * @since 2023/6/13 13:53
+ */
+@RequiredArgsConstructor
+@Getter
+public enum AfterSaleOperateTypeEnum {
+//    MEMBER_CREATE(10, "会员申请退款"),
+//    ADMIN_AGREE_APPLY(11, "商家同意退款"),
+//    ADMIN_DISAGREE_APPLY(12, "商家拒绝退款"),
+//    MEMBER_DELIVERY(20, "会员填写退货物流信息,快递公司:{deliveryName},快递单号:{logisticsNo}"),
+//    ADMIN_AGREE_RECEIVE(21, "商家收货"),
+//    ADMIN_DISAGREE_RECEIVE(22, "商家拒绝收货,原因:{reason}"),
+//    ADMIN_REFUND(30, "商家退款"),
+//    MEMBER_CANCEL(40, "会员取消退款"),
+    MEMBER_CREATE(10, "会員が返金を申請する"),
+    ADMIN_AGREE_APPLY(11, "ガイドが返金に同意する"),
+    ADMIN_DISAGREE_APPLY(12, "ガイドが返金を拒否する"),
+//    MEMBER_DELIVERY(20, "会员填写退货物流信息,快递公司:{deliveryName},快递单号:{logisticsNo}"),
+//    ADMIN_AGREE_RECEIVE(21, "商家收货"),
+//    ADMIN_DISAGREE_RECEIVE(22, "商家拒绝收货,原因:{reason}"),
+    ADMIN_REFUND(30, "ガイドが返金する"),
+    MEMBER_CANCEL(40, "会員が返金申請をキャンセルする"),
+    ;
+
+    /**
+     * 操作类型
+     */
+    private final Integer type;
+    /**
+     * 操作描述
+     */
+    private final String content;
+
+}

+ 95 - 0
yudao-module-guide/yudao-module-guide-api/src/main/java/cn/iocoder/yudao/module/guide/enums/aftersale/AfterSaleStatusEnum.java

@@ -0,0 +1,95 @@
+package cn.iocoder.yudao.module.guide.enums.aftersale;
+
+import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import static cn.hutool.core.util.ArrayUtil.firstMatch;
+
+/**
+ * 售后状态的枚举
+ *
+ * <a href="https://www.processon.com/view/link/63731a270e3e742ce7b7c194">状态流转</a>
+ *
+ * @author 芋道源码
+ */
+@AllArgsConstructor
+@Getter
+public enum AfterSaleStatusEnum implements IntArrayValuable {
+
+    /**
+     * 【申请售后】
+     */
+    APPLY(10,"申请中", "会员申请退款"), // 有赞的状态提示:退款申请待商家处理
+    /**
+     * 卖家通过售后;【商品待退货】
+     */
+    SELLER_AGREE(20, "卖家通过", "商家同意退款"), // 有赞的状态提示:请退货并填写物流信息
+    /**
+     * 买家已退货,等待卖家收货;【商家待收货】
+     */
+    BUYER_DELIVERY(30,"待卖家收货", "会员填写退货物流信息"), // 有赞的状态提示:退货退款申请待商家处理
+    /**
+     * 卖家已收货,等待平台退款;等待退款【等待退款】
+     */
+    WAIT_REFUND(40, "等待平台退款", "商家收货"), // 有赞的状态提示:无(有赞无该状态)
+    /**
+     * 完成退款【退款成功】
+     */
+    COMPLETE(50, "完成", "商家确认退款"), // 有赞的状态提示:退款成功
+    /**
+     * 【买家取消】
+     */
+    BUYER_CANCEL(61, "买家取消售后", "会员取消退款"), // 有赞的状态提示:退款关闭
+    /**
+     * 卖家拒绝售后;商家拒绝【商家拒绝】
+     */
+    SELLER_DISAGREE(62,"卖家拒绝", "商家拒绝退款"), // 有赞的状态提示:商家不同意退款申请
+    /**
+     * 卖家拒绝收货,终止售后;【商家拒收货】
+     */
+    SELLER_REFUSE(63,"卖家拒绝收货", "商家拒绝收货"), // 有赞的状态提示:商家拒绝收货,不同意退款
+    ;
+
+    public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(AfterSaleStatusEnum::getStatus).toArray();
+
+    /**
+     * 进行中的售后状态
+     *
+     * 不包括已经结束的状态
+     */
+    public static final Collection<Integer> APPLYING_STATUSES = Arrays.asList(
+            APPLY.getStatus(),
+            SELLER_AGREE.getStatus(),
+            BUYER_DELIVERY.getStatus(),
+            WAIT_REFUND.getStatus()
+    );
+
+    /**
+     * 状态
+     */
+    private final Integer status;
+    /**
+     * 状态名
+     */
+    private final String name;
+    /**
+     * 操作内容
+     *
+     * 目的:记录售后日志的内容
+     */
+    private final String content;
+
+    @Override
+    public int[] array() {
+        return ARRAYS;
+    }
+
+    public static AfterSaleStatusEnum valueOf(Integer status) {
+        return firstMatch(value -> value.getStatus().equals(status), values());
+    }
+
+}

+ 37 - 0
yudao-module-guide/yudao-module-guide-api/src/main/java/cn/iocoder/yudao/module/guide/enums/aftersale/AfterSaleTypeEnum.java

@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.module.guide.enums.aftersale;
+
+import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Arrays;
+
+/**
+ * 交易售后 - 类型
+ *
+ * @author 芋道源码
+ */
+@RequiredArgsConstructor
+@Getter
+public enum AfterSaleTypeEnum implements IntArrayValuable {
+
+    IN_SALE(10, "售中退款"), // 交易完成前买家申请退款
+    AFTER_SALE(20, "售后退款"); // 交易完成后买家申请退款
+
+    public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(AfterSaleTypeEnum::getType).toArray();
+
+    /**
+     * 类型
+     */
+    private final Integer type;
+    /**
+     * 类型名
+     */
+    private final String name;
+
+    @Override
+    public int[] array() {
+        return ARRAYS;
+    }
+
+}

+ 37 - 0
yudao-module-guide/yudao-module-guide-api/src/main/java/cn/iocoder/yudao/module/guide/enums/aftersale/AfterSaleWayEnum.java

@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.module.guide.enums.aftersale;
+
+import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Arrays;
+
+/**
+ * 交易售后 - 方式
+ *
+ * @author Sin
+ */
+@RequiredArgsConstructor
+@Getter
+public enum AfterSaleWayEnum implements IntArrayValuable {
+
+    REFUND(10, "仅退款"),
+    RETURN_AND_REFUND(20, "退货退款");
+
+    public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(AfterSaleWayEnum::getWay).toArray();
+
+    /**
+     * 方式
+     */
+    private final Integer way;
+    /**
+     * 方式名
+     */
+    private final String name;
+
+    @Override
+    public int[] array() {
+        return ARRAYS;
+    }
+
+}

+ 38 - 0
yudao-module-guide/yudao-module-guide-api/src/main/java/cn/iocoder/yudao/module/guide/enums/order/TradeOrderCancelTypeEnum.java

@@ -0,0 +1,38 @@
+package cn.iocoder.yudao.module.guide.enums.order;
+
+import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Arrays;
+
+/**
+ * 交易订单 - 关闭类型
+ *
+ * @author Sin
+ */
+@RequiredArgsConstructor
+@Getter
+public enum TradeOrderCancelTypeEnum implements IntArrayValuable {
+
+    PAY_TIMEOUT(10, "超时未支付"),
+    AFTER_SALE_CLOSE(20, "退款关闭"),
+    MEMBER_CANCEL(30, "买家取消");
+
+    public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TradeOrderCancelTypeEnum::getType).toArray();
+
+    /**
+     * 关闭类型
+     */
+    private final Integer type;
+    /**
+     * 关闭类型名
+     */
+    private final String name;
+
+    @Override
+    public int[] array() {
+        return ARRAYS;
+    }
+
+}

+ 49 - 0
yudao-module-guide/yudao-module-guide-api/src/main/java/cn/iocoder/yudao/module/guide/enums/order/TradeOrderItemAfterSaleStatusEnum.java

@@ -0,0 +1,49 @@
+package cn.iocoder.yudao.module.guide.enums.order;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Arrays;
+
+/**
+ * 交易订单项 - 售后状态
+ *
+ * @author 芋道源码
+ */
+@RequiredArgsConstructor
+@Getter
+public enum TradeOrderItemAfterSaleStatusEnum implements IntArrayValuable {
+
+    NONE(0, "未售后"),
+    APPLY(10, "售后中"),
+    SUCCESS(20, "售后成功");
+
+    public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TradeOrderItemAfterSaleStatusEnum::getStatus).toArray();
+
+    /**
+     * 状态值
+     */
+    private final Integer status;
+    /**
+     * 状态名
+     */
+    private final String name;
+
+    @Override
+    public int[] array() {
+        return ARRAYS;
+    }
+
+    /**
+     * 判断指定状态,是否正处于【未申请】状态
+     *
+     * @param status 指定状态
+     * @return 是否
+     */
+    public static boolean isNone(Integer status) {
+        return ObjectUtil.equals(status, NONE.getStatus());
+    }
+
+}

+ 57 - 0
yudao-module-guide/yudao-module-guide-api/src/main/java/cn/iocoder/yudao/module/guide/enums/order/TradeOrderOperateTypeEnum.java

@@ -0,0 +1,57 @@
+package cn.iocoder.yudao.module.guide.enums.order;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * 订单操作类型的枚举
+ *
+ * @author 陈賝
+ * @since 2023/7/6 15:31
+ */
+@RequiredArgsConstructor
+@Getter
+public enum TradeOrderOperateTypeEnum {
+
+//    MEMBER_CREATE(1, "用户下单"),
+//    ADMIN_UPDATE_PRICE(2, "订单价格 {oldPayPrice} 修改,实际支付金额为 {newPayPrice} 元"),
+//    MEMBER_PAY(10, "用户付款成功"),
+//    ADMIN_UPDATE_ADDRESS(11, "收货地址修改"),
+//    ADMIN_DELIVERY(20, "已发货,快递公司:{deliveryName},快递单号:{logisticsNo}"),
+//    MEMBER_RECEIVE(30, "用户已收货"),
+//    SYSTEM_RECEIVE(31, "到期未收货,系统自动确认收货"),
+//    ADMIN_PICK_UP_RECEIVE(32, "管理员自提收货"),
+//    MEMBER_COMMENT(33, "用户评价"),
+//    SYSTEM_COMMENT(34, "到期未评价,系统自动评价"),
+//    MEMBER_CANCEL(40, "取消订单"),
+//    SYSTEM_CANCEL(41, "到期未支付,系统自动取消订单"),
+//    // 42 预留:管理员取消订单
+//    ADMIN_CANCEL_AFTER_SALE(43, "订单全部售后,管理员自动取消订单"),
+//    MEMBER_DELETE(49, "删除订单"),
+    MEMBER_CREATE(1, "ユーザーが注文を行いました"),
+    ADMIN_UPDATE_PRICE(2, "注文価格 {oldPayPrice} が変更され、実際の支払額は {newPayPrice} 円です"),
+    MEMBER_PAY(10, "ユーザーの支払いが成功しました"),
+    ADMIN_UPDATE_ADDRESS(11, "配送先住所が変更されました"),
+    ADMIN_DELIVERY(20, "商品が発送されました。運送会社:{deliveryName}、追跡番号:{logisticsNo}"),
+    MEMBER_RECEIVE(30, "ユーザーが商品を受け取りました"),
+    SYSTEM_RECEIVE(31, "期限内に商品が受け取られなかったため、システムが自動的に受取を確認しました"),
+    ADMIN_PICK_UP_RECEIVE(32, "管理者が自ら商品を受け取りました"),
+    MEMBER_COMMENT(33, "ユーザーが評価しました"),
+    SYSTEM_COMMENT(34, "期限内に評価がされなかったため、システムが自動的に評価しました"),
+    MEMBER_CANCEL(40, "注文がキャンセルされました"),
+    SYSTEM_CANCEL(41, "期限内に支払いが完了しなかったため、システムが自動的に注文をキャンセルしました"),
+	// 42 予約:管理者による注文キャンセル — 预留:管理员取消订单
+    ADMIN_CANCEL_AFTER_SALE(43, "全てのアフターサービスが完了したため、管理者が自動的に注文をキャンセルしました"),
+    MEMBER_DELETE(49, "注文が削除されました"),
+    ;
+
+    /**
+     * 操作类型
+     */
+    private final Integer type;
+    /**
+     * 操作描述
+     */
+    private final String content;
+
+}

+ 38 - 0
yudao-module-guide/yudao-module-guide-api/src/main/java/cn/iocoder/yudao/module/guide/enums/order/TradeOrderRefundStatusEnum.java

@@ -0,0 +1,38 @@
+package cn.iocoder.yudao.module.guide.enums.order;
+
+import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Arrays;
+
+/**
+ * 交易订单 - 退款状态
+ *
+ * @author Sin
+ */
+@RequiredArgsConstructor
+@Getter
+public enum TradeOrderRefundStatusEnum implements IntArrayValuable {
+
+    NONE(0, "未退款"),
+    PART(10, "部分退款"),
+    ALL(20, "全部退款");
+
+    public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TradeOrderRefundStatusEnum::getStatus).toArray();
+
+    /**
+     * 状态值
+     */
+    private final Integer status;
+    /**
+     * 状态名
+     */
+    private final String name;
+
+    @Override
+    public int[] array() {
+        return ARRAYS;
+    }
+
+}

+ 116 - 0
yudao-module-guide/yudao-module-guide-api/src/main/java/cn/iocoder/yudao/module/guide/enums/order/TradeOrderStatusEnum.java

@@ -0,0 +1,116 @@
+package cn.iocoder.yudao.module.guide.enums.order;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
+import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Arrays;
+
+/**
+ * 交易订单 - 状态
+ *
+ * @author Sin
+ */
+@RequiredArgsConstructor
+@Getter
+public enum TradeOrderStatusEnum implements IntArrayValuable {
+
+    UNPAID(0, "待支付"),
+    UNDELIVERED(10, "支付完了"),
+    DELIVERED(20, "已发货"),
+    COMPLETED(30, "已完成"),
+    CANCELED(40, "已取消");
+
+    public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TradeOrderStatusEnum::getStatus).toArray();
+
+    /**
+     * 状态值
+     */
+    private final Integer status;
+    /**
+     * 状态名
+     */
+    private final String name;
+
+    @Override
+    public int[] array() {
+        return ARRAYS;
+    }
+
+    // ========== 问:为什么写了很多 isXXX 和 haveXXX 的判断逻辑呢? ==========
+    // ========== 答:方便找到某一类判断,哪些业务正在使用 ==========
+
+    /**
+     * 判断指定状态,是否正处于【未付款】状态
+     *
+     * @param status 指定状态
+     * @return 是否
+     */
+    public static boolean isUnpaid(Integer status) {
+        return ObjectUtil.equal(UNPAID.getStatus(), status);
+    }
+
+    /**
+     * 判断指定状态,是否正处于【待发货】状态
+     *
+     * @param status 指定状态
+     * @return 是否
+     */
+    public static boolean isUndelivered(Integer status) {
+        return ObjectUtil.equal(UNDELIVERED.getStatus(), status);
+    }
+
+    /**
+     * 判断指定状态,是否正处于【已发货】状态
+     *
+     * @param status 指定状态
+     * @return 是否
+     */
+    public static boolean isDelivered(Integer status) {
+        return ObjectUtil.equals(status, DELIVERED.getStatus());
+    }
+
+    /**
+     * 判断指定状态,是否正处于【已取消】状态
+     *
+     * @param status 指定状态
+     * @return 是否
+     */
+    public static boolean isCanceled(Integer status) {
+        return ObjectUtil.equals(status, CANCELED.getStatus());
+    }
+
+    /**
+     * 判断指定状态,是否正处于【已完成】状态
+     *
+     * @param status 指定状态
+     * @return 是否
+     */
+    public static boolean isCompleted(Integer status) {
+        return ObjectUtil.equals(status, COMPLETED.getStatus());
+    }
+
+    /**
+     * 判断指定状态,是否有过【已付款】状态
+     *
+     * @param status 指定状态
+     * @return 是否
+     */
+    public static boolean havePaid(Integer status) {
+        return ObjectUtils.equalsAny(status, UNDELIVERED.getStatus(),
+                DELIVERED.getStatus(), COMPLETED.getStatus());
+    }
+
+    /**
+     * 判断指定状态,是否有过【已发货】状态
+     *
+     * @param status 指定状态
+     * @return 是否
+     */
+    public static boolean haveDelivered(Integer status) {
+        return ObjectUtils.equalsAny(status, DELIVERED.getStatus(), COMPLETED.getStatus());
+    }
+
+}

+ 57 - 0
yudao-module-guide/yudao-module-guide-api/src/main/java/cn/iocoder/yudao/module/guide/enums/order/TradeOrderTypeEnum.java

@@ -0,0 +1,57 @@
+package cn.iocoder.yudao.module.guide.enums.order;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Arrays;
+
+/**
+ * 交易订单 - 类型
+ *
+ * @author Sin
+ */
+@RequiredArgsConstructor
+@Getter
+public enum TradeOrderTypeEnum implements IntArrayValuable {
+
+    NORMAL(0, "普通订单"),
+    SECKILL(1, "秒杀订单"),
+    BARGAIN(2, "砍价订单"),
+    COMBINATION(3, "拼团订单"),
+    ;
+
+    public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TradeOrderTypeEnum::getType).toArray();
+
+    /**
+     * 类型
+     */
+    private final Integer type;
+    /**
+     * 类型名
+     */
+    private final String name;
+
+    @Override
+    public int[] array() {
+        return ARRAYS;
+    }
+
+    public static boolean isNormal(Integer type) {
+        return ObjectUtil.equal(type, NORMAL.getType());
+    }
+
+    public static boolean isSeckill(Integer type) {
+        return ObjectUtil.equal(type, SECKILL.getType());
+    }
+
+    public static boolean isBargain(Integer type) {
+        return ObjectUtil.equal(type, BARGAIN.getType());
+    }
+
+    public static boolean isCombination(Integer type) {
+        return ObjectUtil.equal(type, COMBINATION.getType());
+    }
+
+}

+ 48 - 0
yudao-module-guide/yudao-module-guide-biz/pom.xml

@@ -59,5 +59,53 @@
             <groupId>cn.iocoder.boot</groupId>
             <artifactId>yudao-spring-boot-starter-excel</artifactId>
         </dependency>
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-module-system-biz</artifactId>
+            <version>2.0.1-snapshot</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-module-member-api</artifactId>
+            <version>2.0.1-snapshot</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-module-pay-api</artifactId>
+            <version>2.0.1-snapshot</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-module-trade-biz</artifactId>
+            <version>2.0.1-snapshot</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.stripe</groupId>
+            <artifactId>stripe-java</artifactId>
+            <version>26.5.1</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.tomcat</groupId>
+            <artifactId>annotations-api</artifactId>
+            <version>6.0.53</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-biz-pay</artifactId>
+            <version>2.0.1-snapshot</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-module-pay-biz</artifactId>
+            <version>2.0.1-snapshot</version>
+            <scope>compile</scope>
+        </dependency>
     </dependencies>
 </project>

+ 42 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/api/order/GuideTradeOrderApiImpl.java

@@ -0,0 +1,42 @@
+package cn.iocoder.yudao.module.guide.api.order;
+
+import cn.iocoder.yudao.module.guide.api.order.dto.TradeOrderRespDTO;
+import cn.iocoder.yudao.module.guide.service.order.GuideTradeOrderUpdateService;
+
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 订单 API 接口实现类
+ *
+ * @author HUIHUI
+ */
+@Service
+@Validated
+public class GuideTradeOrderApiImpl implements GuideTradeOrderApi {
+
+    @Resource
+    private GuideTradeOrderUpdateService tradeOrderUpdateService;
+
+    @Override
+    public List<TradeOrderRespDTO> getOrderList(Collection<Long> ids) {
+//        return TradeOrderConvert.INSTANCE.convertList04(tradeOrderQueryService.getOrderList(ids));
+    return null;
+    }
+
+    @Override
+    public TradeOrderRespDTO getOrder(Long id) {
+//        return TradeOrderConvert.INSTANCE.convert(tradeOrderQueryService.getOrder(id));
+        return null;
+    }
+
+    @Override
+    public void cancelPaidOrder(Long userId, Long orderId) {
+//        tradeOrderUpdateService.cancelPaidOrder(userId, orderId);
+    }
+
+}

+ 135 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/aftersale/GuideAfterSaleController.java

@@ -0,0 +1,135 @@
+package cn.iocoder.yudao.module.guide.controller.admin.aftersale;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.guide.controller.admin.aftersale.vo.GuideAfterSaleDetailRespVO;
+import cn.iocoder.yudao.module.guide.controller.admin.aftersale.vo.GuideAfterSaleDisagreeReqVO;
+import cn.iocoder.yudao.module.guide.controller.admin.aftersale.vo.GuideAfterSalePageReqVO;
+import cn.iocoder.yudao.module.guide.controller.admin.aftersale.vo.GuideAfterSaleRespPageItemVO;
+import cn.iocoder.yudao.module.guide.convert.aftersale.GuideAfterSaleConvert;
+import cn.iocoder.yudao.module.guide.dal.dataobject.aftersale.GuideAfterSaleDO;
+import cn.iocoder.yudao.module.guide.dal.dataobject.aftersale.GuideAfterSaleLogDO;
+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.service.aftersale.GuideAfterSaleLogService;
+import cn.iocoder.yudao.module.guide.service.aftersale.GuideAfterSaleService;
+import cn.iocoder.yudao.module.guide.service.order.GuideTradeOrderQueryService;
+import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
+import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
+import cn.iocoder.yudao.module.pay.api.notify.dto.PayRefundNotifyReqDTO;
+import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.AfterSaleDisagreeReqVO;
+import cn.iocoder.yudao.module.trade.convert.aftersale.AfterSaleConvert;
+import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleDO;
+import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleLogDO;
+import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
+import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
+import cn.iocoder.yudao.module.trade.service.aftersale.AfterSaleLogService;
+import cn.iocoder.yudao.module.trade.service.aftersale.AfterSaleService;
+import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
+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.annotation.security.PermitAll;
+import jakarta.validation.Valid;
+import lombok.extern.slf4j.Slf4j;
+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 static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
+import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
+
+@Tag(name = "管理后台 - 售后订单")
+@RestController
+@RequestMapping("/guide/trade/after-sale")
+@Validated
+@Slf4j
+public class GuideAfterSaleController {
+
+    @Resource
+    private GuideAfterSaleService afterSaleService;
+    @Resource
+    private GuideTradeOrderQueryService tradeOrderQueryService;
+    @Resource
+    private GuideAfterSaleLogService afterSaleLogService;
+    @Resource
+    private MemberUserApi memberUserApi;
+
+    @GetMapping("/page")
+    @Operation(summary = "获得售后订单分页")
+    @PreAuthorize("@ss.hasPermission('trade:after-sale:query')")
+    public CommonResult<PageResult<GuideAfterSaleRespPageItemVO>> getAfterSalePage(@Valid GuideAfterSalePageReqVO pageVO) {
+        // 查询售后
+        PageResult<GuideAfterSaleDO> pageResult = afterSaleService.getAfterSalePage(pageVO);
+        if (CollUtil.isEmpty(pageResult.getList())) {
+            return success(PageResult.empty());
+        }
+        // 查询会员
+        Map<Long, MemberUserRespDTO> memberUsers = memberUserApi.getUserMap(
+                convertSet(pageResult.getList(), GuideAfterSaleDO::getUserId));
+        return success(GuideAfterSaleConvert.INSTANCE.convertPage(pageResult, memberUsers));
+    }
+
+    @GetMapping("/get-detail")
+    @Operation(summary = "获得售后订单详情")
+    @Parameter(name = "id", description = "售后编号", required = true, example = "1")
+    @PreAuthorize("@ss.hasPermission('trade:after-sale:query')")
+    public CommonResult<GuideAfterSaleDetailRespVO> getOrderDetail(@RequestParam("id") Long id) {
+        // 查询订单
+        GuideAfterSaleDO afterSale = afterSaleService.getAfterSale(id);
+        if (afterSale == null) {
+            return success(null);
+        }
+
+        // 查询订单
+        GuideTradeOrderDO order = tradeOrderQueryService.getOrder(afterSale.getOrderId());
+        // 查询订单项
+        GuideTradeOrderItemDO orderItem = tradeOrderQueryService.getOrderItem(afterSale.getOrderItemId());
+        // 拼接数据
+        MemberUserRespDTO user = memberUserApi.getUser(afterSale.getUserId());
+        List<GuideAfterSaleLogDO> logs = afterSaleLogService.getAfterSaleLogList(afterSale.getId());
+        return success(GuideAfterSaleConvert.INSTANCE.convert(afterSale, order, orderItem, user, logs));
+    }
+
+    @PutMapping("/agree")
+    @Operation(summary = "同意售后")
+    @Parameter(name = "id", description = "售后编号", required = true, example = "1")
+    @PreAuthorize("@ss.hasPermission('trade:after-sale:agree')")
+    public CommonResult<Boolean> agreeAfterSale(@RequestParam("id") Long id) {
+        afterSaleService.agreeAfterSale(getLoginUserId(), id);
+        return success(true);
+    }
+    @PutMapping("/disagree")
+    @Operation(summary = "拒绝售后")
+    @PreAuthorize("@ss.hasPermission('trade:after-sale:disagree')")
+    public CommonResult<Boolean> disagreeAfterSale(@RequestBody GuideAfterSaleDisagreeReqVO confirmReqVO) {
+        afterSaleService.disagreeAfterSale(getLoginUserId(), confirmReqVO);
+        return success(true);
+    }
+    @PutMapping("/refund")
+    @Operation(summary = "确认退款")
+    @Parameter(name = "id", description = "售后编号", required = true, example = "1")
+    @PreAuthorize("@ss.hasPermission('trade:after-sale:refund')")
+    public CommonResult<Boolean> refundAfterSale(@RequestParam("id") Long id) {
+        afterSaleService.refundAfterSale(getLoginUserId(), getClientIP(), id);
+        return success(true);
+    }
+
+    @PostMapping("/update-refunded")
+    @Operation(summary = "更新售后订单为已退款") // 由 pay-module 支付服务,进行回调,可见 PayNotifyJob
+    @PermitAll // 无需登录,安全由 PayDemoOrderService 内部校验实现
+    public CommonResult<Boolean> updateAfterRefund(@RequestBody PayRefundNotifyReqDTO notifyReqDTO) {
+        // 目前业务逻辑,不需要做任何事情
+        // 当然,退款会有小概率会失败的情况,可以监控失败状态,进行告警
+        log.info("[updateAfterRefund][notifyReqDTO({})]", notifyReqDTO);
+        return success(true);
+    }
+
+}

+ 33 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/aftersale/TradeAfterSaleController.http

@@ -0,0 +1,33 @@
+### 获得交易售后分页 => 成功
+GET {{baseUrl}}/trade/after-sale/page?pageNo=1&pageSize=10
+Authorization: Bearer {{token}}
+tenant-id: {{adminTenentId}}
+
+### 同意售后 => 成功
+PUT {{baseUrl}}/trade/after-sale/agree?id=7
+Authorization: Bearer {{token}}
+tenant-id: {{adminTenentId}}
+Content-Type: application/json
+
+### 拒绝售后 => 成功
+PUT {{baseUrl}}/trade/after-sale/disagree
+Authorization: Bearer {{token}}
+tenant-id: {{adminTenentId}}
+Content-Type: application/json
+
+{
+  "id": 6,
+  "auditReason": "阿巴巴"
+}
+
+### 确认退款 => 成功
+PUT {{baseUrl}}/trade/after-sale/refund?id=6
+Authorization: Bearer {{token}}
+tenant-id: {{adminTenentId}}
+Content-Type: application/json
+
+### 确认收货 => 成功
+PUT {{baseUrl}}/trade/after-sale/receive?id=7
+Authorization: Bearer {{token}}
+tenant-id: {{adminTenentId}}
+Content-Type: application/json

+ 102 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/aftersale/vo/GuideAfterSaleBaseVO.java

@@ -0,0 +1,102 @@
+package cn.iocoder.yudao.module.guide.controller.admin.aftersale.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+/**
+* 交易售后 Base VO,提供给添加、修改、详细的子 VO 使用
+* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
+*/
+@Data
+public class GuideAfterSaleBaseVO {
+
+    @Schema(description = "售后流水号", requiredMode = Schema.RequiredMode.REQUIRED, example = "202211190847450020500077")
+    @NotNull(message = "售后流水号不能为空")
+    private String no;
+
+    @Schema(description = "售后状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
+    @NotNull(message = "售后状态不能为空")
+    private Integer status;
+
+    @Schema(description = "售后类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
+    @NotNull(message = "售后类型不能为空")
+    private Integer type;
+
+    @Schema(description = "售后方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
+    @NotNull(message = "售后方式不能为空")
+    private Integer way;
+
+    @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "30337")
+    @NotNull(message = "用户编号不能为空")
+    private Long userId;
+
+    @Schema(description = "申请原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "不喜欢")
+    @NotNull(message = "申请原因不能为空")
+    private String applyReason;
+
+    @Schema(description = "补充描述", example = "你说的对")
+    private String applyDescription;
+
+    @Schema(description = "补充凭证图片", example = "https://www.iocoder.cn/1.png")
+    private List<String> applyPicUrls;
+
+    @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18078")
+    @NotNull(message = "订单编号不能为空")
+    private Long orderId;
+
+    @Schema(description = "订单流水号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2022111917190001")
+    @NotNull(message = "订单流水号不能为空")
+    private String orderNo;
+
+    @Schema(description = "订单项编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "572")
+    @NotNull(message = "订单项编号不能为空")
+    private Long orderItemId;
+
+    @Schema(description = " guide编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2888")
+    private Long guideId;
+
+    @Schema(description = " trip id", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
+    private Long tripId;
+
+    @Schema(description = " Pic", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
+    private String picUrl;
+
+    @Schema(description = " Guide 名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
+    private String guideName;
+
+    @Schema(description = " trip 名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
+    private String tripTitle;
+
+    @Schema(description = " booking date", requiredMode = Schema.RequiredMode.REQUIRED, example = "15657")
+    private LocalDateTime bookingDate;
+
+    @Schema(description = "审批时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime auditTime;
+
+    @Schema(description = "审批人", example = "30835")
+    private Long auditUserId;
+
+    @Schema(description = "审批备注", example = "不香")
+    private String auditReason;
+
+    @Schema(description = "退款金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "18077")
+    @NotNull(message = "退款金额,单位:分不能为空")
+    private Integer refundPrice;
+
+    @Schema(description = "支付退款编号", example = "10271")
+    private Long payRefundId;
+
+    @Schema(description = "退款时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime refundTime;
+
+
+}

+ 51 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/aftersale/vo/GuideAfterSaleDetailRespVO.java

@@ -0,0 +1,51 @@
+package cn.iocoder.yudao.module.guide.controller.admin.aftersale.vo;
+
+import cn.iocoder.yudao.module.guide.controller.admin.aftersale.vo.log.GuideAfterSaleLogRespVO;
+import cn.iocoder.yudao.module.guide.controller.admin.order.vo.GuideTradeOrderBaseVO;
+import cn.iocoder.yudao.module.guide.controller.admin.order.vo.GuideTradeOrderItemBaseVO;
+import cn.iocoder.yudao.module.guide.controller.admin.users.vo.UsersRespVO;
+import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.log.AfterSaleLogRespVO;
+import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO;
+import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO;
+import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderBaseVO;
+import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderItemBaseVO;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+@Schema(description = "管理后台 - 售后订单的详情 Response VO")
+@Data
+public class GuideAfterSaleDetailRespVO extends GuideAfterSaleBaseVO {
+
+    @Schema(description = "售后编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    private Long id;
+
+
+
+    /**
+     * 订单基本信息
+     */
+    private GuideTradeOrderBaseVO order;
+    /**
+     * 订单项列表
+     */
+    private OrderItem orderItem;
+
+    /**
+     * 用户信息
+     */
+    private MemberUserRespVO user;
+
+    /**
+     * 售后日志
+     */
+    private List<GuideAfterSaleLogRespVO> logs;
+
+    @Schema(description = "管理后台 - 交易订单的详情的订单项目")
+    @Data
+    public static class OrderItem extends GuideTradeOrderItemBaseVO {
+
+    }
+
+}

+ 20 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/aftersale/vo/GuideAfterSaleDisagreeReqVO.java

@@ -0,0 +1,20 @@
+package cn.iocoder.yudao.module.guide.controller.admin.aftersale.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+@Schema(description = "管理后台 - 交易售后拒绝 Request VO")
+@Data
+public class GuideAfterSaleDisagreeReqVO {
+
+    @Schema(description = "售后编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    @NotNull(message = "售后编号不能为空")
+    private Long id;
+
+    @Schema(description = "审批备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "你猜")
+    @NotEmpty(message = "审批备注不能为空")
+    private String auditReason;
+
+}

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

@@ -0,0 +1,56 @@
+package cn.iocoder.yudao.module.guide.controller.admin.aftersale.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleStatusEnum;
+import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleTypeEnum;
+import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleWayEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+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 GuideAfterSalePageReqVO extends PageParam {
+
+    @Schema(description = "售后流水号", example = "202211190847450020500077")
+    private String no;
+
+    @Schema(description = "售后状态", example = "10")
+    @InEnum(value = AfterSaleStatusEnum.class, message = "售后状态必须是 {value}")
+    private Integer status;
+
+    @Schema(description = "售后类型", example = "20")
+    @InEnum(value = AfterSaleTypeEnum.class, message = "售后类型必须是 {value}")
+    private Integer type;
+
+    @Schema(description = "售后方式", example = "10")
+    @InEnum(value = AfterSaleWayEnum.class, message = "售后方式必须是 {value}")
+    private Integer way;
+
+    @Schema(description = "订单编号", example = "18078")
+    private String orderNo;
+
+    @Schema(description = "导游 id", example = "李四")
+    private Long guideId;
+
+    @Schema(description = "trip id", example = "李四")
+    private Long tripId;
+
+
+    @Schema(description = "booking date", example = "李四")
+    private LocalDateTime bookingDate;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

+ 19 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/aftersale/vo/GuideAfterSaleRefuseReqVO.java

@@ -0,0 +1,19 @@
+package cn.iocoder.yudao.module.guide.controller.admin.aftersale.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+@Schema(description = "管理后台 - 交易售后拒绝收货 Request VO")
+@Data
+public class GuideAfterSaleRefuseReqVO {
+
+    @Schema(description = "售后编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    @NotNull(message = "售后编号不能为空")
+    private Long id;
+
+    @Schema(description = "收货备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "你猜")
+    @NotNull(message = "收货备注不能为空")
+    private String refuseMemo;
+
+}

+ 29 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/aftersale/vo/GuideAfterSaleRespPageItemVO.java

@@ -0,0 +1,29 @@
+package cn.iocoder.yudao.module.guide.controller.admin.aftersale.vo;
+
+import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Schema(description = "管理后台 - 交易售后分页的每一条记录 Response VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class GuideAfterSaleRespPageItemVO extends GuideAfterSaleBaseVO {
+
+    @Schema(description = "售后编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "27630")
+    private Long id;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    private LocalDateTime createTime;
+
+    /**
+     * 用户信息
+     */
+    private MemberUserRespVO user;
+
+}

+ 36 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/aftersale/vo/log/GuideAfterSaleLogRespVO.java

@@ -0,0 +1,36 @@
+package cn.iocoder.yudao.module.guide.controller.admin.aftersale.vo.log;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 交易售后日志 Response VO")
+@Data
+public class GuideAfterSaleLogRespVO {
+
+    @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20669")
+    private Long id;
+
+    @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "22634")
+    private Long userId;
+
+    @Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+    private Integer userType;
+
+    @Schema(description = "售后编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3023")
+    private Long afterSaleId;
+
+    @Schema(description = "售后状态(之前)", example = "2")
+    private Integer beforeStatus;
+
+    @Schema(description = "售后状态(之后)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    private Integer afterStatus;
+
+    @Schema(description = "操作明细", requiredMode = Schema.RequiredMode.REQUIRED, example = "维权完成,退款金额:¥37776.00")
+    private String content;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    private LocalDateTime createTime;
+
+}

+ 4 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/base/member/package-info.java

@@ -0,0 +1,4 @@
+/**
+ * 占位符,可忽略
+ */
+package cn.iocoder.yudao.module.guide.controller.admin.base.member;

+ 22 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/base/member/user/MemberUserRespVO.java

@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.guide.controller.admin.base.member.user;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "管理后台 - 会员用户 Response VO")
+@Data
+public class MemberUserRespVO {
+
+    @Schema(description = "用户 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    private Long id;
+
+    @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码")
+    private String nickname;
+
+    @Schema(description = "用户头像", example = "https://www.iocoder.cn/xxx.png")
+    private String avatar;
+
+    @Schema(description = "电话", example = "13709090909")
+    private String mobile;
+
+}

+ 4 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/base/package-info.java

@@ -0,0 +1,4 @@
+/**
+ * 放置该模块通用的 VO 类
+ */
+package cn.iocoder.yudao.module.guide.controller.admin.base;

+ 22 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/base/product/property/ProductPropertyValueDetailRespVO.java

@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.guide.controller.admin.base.product.property;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "管理后台 - 商品属性值的明细 Response VO")
+@Data
+public class ProductPropertyValueDetailRespVO {
+
+    @Schema(description = "属性的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    private Long propertyId;
+
+    @Schema(description = "属性的名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "颜色")
+    private String propertyName;
+
+    @Schema(description = "属性值的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    private Long valueId;
+
+    @Schema(description = "属性值的名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "红色")
+    private String valueName;
+
+}

+ 39 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/history/GuideBrowseHistoryController.java

@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.module.guide.controller.admin.history;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.guide.controller.admin.history.vo.GuideBrowseHistoryPageReqVO;
+import cn.iocoder.yudao.module.guide.controller.admin.history.vo.GuideBrowseHistoryRespVO;
+import cn.iocoder.yudao.module.guide.dal.dataobject.history.GuideBrowseHistoryDO;
+import cn.iocoder.yudao.module.guide.service.history.GuideBrowseHistoryService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+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.RestController;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "管理后台 - 商品浏览记录")
+@RestController
+@RequestMapping("/guide/browse-history")
+@Validated
+public class GuideBrowseHistoryController {
+
+    @Resource
+    private GuideBrowseHistoryService guideBrowseHistoryService;
+
+    @GetMapping("/page")
+    @Operation(summary = "获得商品浏览记录分页")
+    @PreAuthorize("@ss.hasPermission('product:browse-history:query')")
+    public CommonResult<PageResult<GuideBrowseHistoryRespVO>> getBrowseHistoryPage(@Valid GuideBrowseHistoryPageReqVO pageReqVO) {
+        PageResult<GuideBrowseHistoryDO> pageResult = guideBrowseHistoryService.getBrowseHistoryPage(pageReqVO);
+        return success(BeanUtils.toBean(pageResult, GuideBrowseHistoryRespVO.class));
+    }
+
+}

+ 40 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/history/vo/GuideBrowseHistoryPageReqVO.java

@@ -0,0 +1,40 @@
+package cn.iocoder.yudao.module.guide.controller.admin.history.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.SortablePageParam;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+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 GuideBrowseHistoryPageReqVO extends SortablePageParam {
+
+    @Schema(description = "用户编号", example = "4314")
+    private Long userId;
+
+    @Schema(description = "用户是否删除", example = "false")
+    private Boolean userDeleted;
+
+    @Schema(description = "trip 编号",  example = "42")
+    private Long tripId;
+
+    @Schema(description = "guide 编号",  example = "42")
+    private Long guideId;
+
+    @Schema(description = "sights 编号",  example = "42")
+    private Long sightsId;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

+ 42 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/history/vo/GuideBrowseHistoryRespVO.java

@@ -0,0 +1,42 @@
+package cn.iocoder.yudao.module.guide.controller.admin.history.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 商品浏览记录 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class GuideBrowseHistoryRespVO {
+
+    @Schema(description = "记录编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "26055")
+    @ExcelProperty("记录编号")
+    private Long id;
+
+    @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4314")
+    @ExcelProperty("用户编号")
+    private Long userId;
+
+    @Schema(description = "用户是否删除", example = "false")
+    private Boolean userDeleted;
+
+    @Schema(description = "trip 编号",  example = "42")
+    @ExcelProperty("trip 编号")
+    private Long tripId;
+
+    @Schema(description = "guide 编号",  example = "42")
+    @ExcelProperty("guide 编号")
+    private Long guideId;
+
+    @Schema(description = "sights 编号",  example = "42")
+    @ExcelProperty("sights 编号")
+    private Long sightsId;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+}

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

@@ -0,0 +1,133 @@
+package cn.iocoder.yudao.module.guide.controller.admin.order;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.guide.controller.admin.base.member.user.MemberUserRespVO;
+import cn.iocoder.yudao.module.guide.controller.admin.order.vo.*;
+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.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.member.api.user.MemberUserApi;
+import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
+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 lombok.extern.slf4j.Slf4j;
+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.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;
+
+@Tag(name = "管理后台 - 交易订单")
+@RestController
+@RequestMapping("/guide/trade/order")
+@Validated
+@Slf4j
+public class GuideTradeOrderController {
+
+    @Resource
+    private GuideTradeOrderUpdateService guideTradeOrderUpdateService;
+    @Resource
+    private GuideTradeOrderQueryService guideTradeOrderQueryService;
+    @Resource
+    private GuideTradeOrderLogService guideTradeOrderLogService;
+
+    @Resource
+    private MemberUserApi memberUserApi;
+
+    @GetMapping("/page")
+    @Operation(summary = "获得交易订单分页")
+    @PreAuthorize("@ss.hasPermission('trade:order:query')")
+    public CommonResult<PageResult<GuideTradeOrderPageItemRespVO>> getOrderPage(GuideTradeOrderPageReqVO reqVO) {
+        // 查询订单
+        PageResult<GuideTradeOrderDO> pageResult = guideTradeOrderQueryService.getOrderPage(reqVO);
+        if (CollUtil.isEmpty(pageResult.getList())) {
+            return success(PageResult.empty());
+        }
+
+        // 查询用户信息
+        List<Long> userIds = CollUtil.distinct(convertList(pageResult.getList(), GuideTradeOrderDO::getUserId));
+        Map<Long, MemberUserRespDTO> userMap = memberUserApi.getUserMap(userIds);
+        // 查询订单项
+        List<GuideTradeOrderItemDO> orderItems = guideTradeOrderQueryService.getOrderItemListByOrderId(
+                convertSet(pageResult.getList(), GuideTradeOrderDO::getId));
+        // 最终组合
+        return success(enrichOrders(pageResult,  userMap,orderItems));
+    }
+    private PageResult<GuideTradeOrderPageItemRespVO> enrichOrders(PageResult<GuideTradeOrderDO> orders,
+                                                                   Map<Long, MemberUserRespDTO> userInfos,
+                                                                   List<GuideTradeOrderItemDO> orderItems) {
+
+        PageResult<GuideTradeOrderPageItemRespVO> newOrders = BeanUtils.toBean(orders, GuideTradeOrderPageItemRespVO.class);
+        newOrders.getList().forEach(order -> order.setUser(userInfos.get(order.getUserId())));
+        newOrders.getList().forEach(order -> {
+            List<GuideTradeOrderItemDO> items = orderItems.stream()
+                    .filter(item -> item.getOrderId().equals(order.getId()))
+                    .collect(Collectors.toList());
+            order.setItems(BeanUtils.toBean(items,GuideTradeOrderItemBaseVO.class));
+        });
+        return newOrders;
+    }
+
+    @GetMapping("/summary")
+    @Operation(summary = "获得交易订单统计")
+    @PreAuthorize("@ss.hasPermission('trade:order:query')")
+    public CommonResult<GuideTradeOrderSummaryRespVO> getOrderSummary(GuideTradeOrderPageReqVO reqVO) {
+        return success(guideTradeOrderQueryService.getOrderSummary(reqVO));
+    }
+
+    @GetMapping("/get-detail")
+    @Operation(summary = "获得交易订单详情")
+    @Parameter(name = "id", description = "订单编号", required = true, example = "1")
+    @PreAuthorize("@ss.hasPermission('trade:order:query')")
+    public CommonResult<GuideTradeOrderDetailRespVO> getOrderDetail(@RequestParam("id") Long id) {
+        // 查询订单
+        GuideTradeOrderDO order = guideTradeOrderQueryService.getOrder(id);
+        if (order == null) {
+            return success(null);
+        }
+        // 查询订单项
+        List<GuideTradeOrderItemDO> orderItems = guideTradeOrderQueryService.getOrderItemListByOrderId(id);
+
+        // 拼接数据
+        MemberUserRespDTO user = memberUserApi.getUser(order.getUserId());
+        List<GuideTradeOrderLogDO> orderLogs = guideTradeOrderLogService.getOrderLogListByOrderId(id);
+        return success(enrichOrderDetail(order, user,orderItems, orderLogs));
+    }
+    private GuideTradeOrderDetailRespVO enrichOrderDetail(GuideTradeOrderDO order,
+                                                          MemberUserRespDTO user,
+                                                          List<GuideTradeOrderItemDO> orderItems,
+                                                          List<GuideTradeOrderLogDO> logs) {
+
+        GuideTradeOrderDetailRespVO newOrder = BeanUtils.toBean(order, GuideTradeOrderDetailRespVO.class);
+        newOrder.setUser(BeanUtils.toBean(user, MemberUserRespVO.class));
+        newOrder.setItems(BeanUtils.toBean(orderItems,GuideTradeOrderItemBaseVO.class));
+        newOrder.setLogs(BeanUtils.toBean(logs,GuideTradeOrderDetailRespVO.OrderLog.class));
+
+        return newOrder;
+    }
+    @PutMapping("/update-remark")
+    @Operation(summary = "订单备注")
+    @PreAuthorize("@ss.hasPermission('trade:order:update')")
+    public CommonResult<Boolean> updateOrderRemark(@RequestBody GuideTradeOrderRemarkReqVO reqVO) {
+        guideTradeOrderUpdateService.updateOrderRemark(reqVO);
+        return success(true);
+    }
+
+}

+ 151 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/order/vo/GuideTradeOrderBaseVO.java

@@ -0,0 +1,151 @@
+package cn.iocoder.yudao.module.guide.controller.admin.order.vo;
+
+import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
+import cn.iocoder.yudao.module.guide.dal.dataobject.order.GuideTradeOrderItemDO;
+import cn.iocoder.yudao.module.guide.enums.order.TradeOrderCancelTypeEnum;
+import cn.iocoder.yudao.module.guide.enums.order.TradeOrderRefundStatusEnum;
+import cn.iocoder.yudao.module.guide.enums.order.TradeOrderStatusEnum;
+import cn.iocoder.yudao.module.guide.enums.order.TradeOrderTypeEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * 交易订单 Base VO,提供给添加、修改、详细的子 VO 使用
+ * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
+ */
+@Data
+public class GuideTradeOrderBaseVO {
+
+
+    // ========== 订单基本信息 ==========
+    /**
+     * 订单编号,主键自增
+     */
+    private Long id;
+    /**
+     * 订单流水号
+     *
+     * 例如说,1146347329394184195
+     */
+    private String no;
+    /**
+     * 订单类型
+     *
+     * 枚举 {@link TradeOrderTypeEnum}
+     */
+    private Integer type;
+    /**
+     * 订单来源
+     *
+     * 枚举 {@link TerminalEnum}
+     */
+    private Integer terminal;
+    /**
+     * 用户编号
+     *
+     * 关联 MemberUserDO 的 id 编号
+     */
+    private Long userId;
+    /**
+     * 用户 IP
+     */
+    private String userIp;
+    /**
+     * 用户备注
+     */
+    private String userRemark;
+    /**
+     * 订单状态
+     *
+     * 枚举 {@link TradeOrderStatusEnum}
+     */
+    private Integer status;
+    /**
+     * 购买的商品数量
+     */
+    private Integer productCount;
+    /**
+     * 订单完成时间
+     */
+    private LocalDateTime finishTime;
+    /**
+     * 订单取消时间
+     */
+    private LocalDateTime cancelTime;
+    /**
+     * 取消类型
+     *
+     * 枚举 {@link TradeOrderCancelTypeEnum}
+     */
+    private Integer cancelType;
+    /**
+     * 商家备注
+     */
+    private String remark;
+    /**
+     * 是否评价
+     *
+     * true - 已评价
+     * false - 未评价
+     */
+    private Boolean commentStatus;
+
+
+    /**
+     * 支付订单编号
+     *
+     * 对接 pay-module-biz 支付服务的支付订单编号,即 PayOrderDO 的 id 编号
+     */
+    private Long payOrderId;
+    /**
+     * 是否已支付
+     *
+     * true - 已经支付过
+     * false - 没有支付过
+     */
+    private Boolean payStatus;
+    /**
+     * 付款时间
+     */
+    private LocalDateTime payTime;
+    /**
+     * 支付渠道
+     *
+     * 对应 PayChannelEnum 枚举
+     */
+    private String payChannelCode;
+
+    /**
+     * 商品原价,单位:分
+     *
+     *
+     * 对应 taobao 的 trade.total_fee 字段
+     */
+    private Integer totalPrice;
+    /**
+     * 优惠金额,单位:分
+     *
+     * 对应 taobao 的 order.discount_fee 字段
+     */
+
+
+
+    // ========== 售后基本信息 ==========
+    /**
+     * 售后状态
+     *
+     * 枚举 {@link TradeOrderRefundStatusEnum}
+     */
+    private Integer refundStatus;
+    /**
+     * 退款金额,单位:分
+     *
+     * 也就说,一个订单最终产生多少金额的收入 = payPrice - refundPrice
+     */
+    private Integer refundPrice;
+
+    private LocalDateTime createTime;
+
+}

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

@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.guide.controller.admin.order.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+@Schema(description = "管理后台 - 订单发货 Request VO")
+@Data
+public class GuideTradeOrderDeliveryReqVO {
+
+    @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    @NotNull(message = "订单编号不能为空")
+    private Long id;
+
+    @Schema(description = "发货物流公司编号", example = "1")
+    @NotNull(message = "发货物流公司不能为空")
+    private Long logisticsId;
+
+    @Schema(description = "发货物流单号", example = "SF123456789")
+    private String logisticsNo;
+
+}

+ 48 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/order/vo/GuideTradeOrderDetailRespVO.java

@@ -0,0 +1,48 @@
+package cn.iocoder.yudao.module.guide.controller.admin.order.vo;
+
+import cn.iocoder.yudao.module.guide.controller.admin.base.member.user.MemberUserRespVO;
+import cn.iocoder.yudao.module.guide.controller.admin.base.product.property.ProductPropertyValueDetailRespVO;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Schema(description = "管理后台 - 交易订单的详情 Response VO")
+@Data
+public class GuideTradeOrderDetailRespVO extends GuideTradeOrderBaseVO {
+
+    /**
+     * 订单项列表
+     */
+    private List<GuideTradeOrderItemBaseVO> items;
+
+    /**
+     * 下单用户信息
+     */
+    private MemberUserRespVO user;
+
+    /**
+     * 操作日志列表
+     */
+    private List<OrderLog> logs;
+
+
+
+    @Schema(description = "管理后台 - 交易订单的操作日志")
+    @Data
+    public static class OrderLog {
+
+        @Schema(description = "操作详情", requiredMode = Schema.RequiredMode.REQUIRED, example = "订单发货")
+        private String content;
+
+        @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2023-06-01 10:50:20")
+        private LocalDateTime createTime;
+
+        @Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+        private Integer userType;
+
+    }
+
+
+}

+ 81 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/order/vo/GuideTradeOrderItemBaseVO.java

@@ -0,0 +1,81 @@
+package cn.iocoder.yudao.module.guide.controller.admin.order.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * 交易订单项 Base VO,提供给添加、修改、详细的子 VO 使用
+ * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
+ */
+@Data
+public class GuideTradeOrderItemBaseVO {
+
+    // ========== 订单项基本信息 ==========
+
+    /**
+     * 编号
+     */
+    private Long id;
+    /**
+     * 用户编号
+     *
+     * 关联 MemberUserDO 的 id 编号
+     */
+    private Long userId;
+    /**
+     * 订单编号
+     *
+     */
+    private Long orderId;
+    /**
+     * 购物车项编号
+     *
+     */
+    private Long cartId;
+
+    // ========== 商品基本信息; 冗余较多字段,减少关联查询 ==========
+    /**
+     * 商品 SPU 编号
+     *
+     * 关联 ProductSkuDO 的 spuId 编号
+     */
+    private Long tripId;
+
+    private LocalDateTime bookingDate;
+
+    /**
+     * 商品图片
+     */
+    private String picUrl;
+
+    /**
+     * 是否评价
+     *
+     * true - 已评价
+     * false - 未评价
+     */
+    private Boolean commentStatus;
+
+    // ========== 价格 + 支付基本信息 ==========
+
+    /**
+     * 商品原价(单),单位:分
+     *
+     * 对应 ProductSkuDO 的 price 字段
+     * 对应 taobao 的 order.price 字段
+     */
+    private Integer price;
+
+    private Long guideId;
+
+    private String guideName;
+
+    private String tripTitle;
+
+    private Long afterSaleId;
+    private Integer afterSaleStatus;
+
+    private Integer status;
+}

+ 30 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/order/vo/GuideTradeOrderPageItemRespVO.java

@@ -0,0 +1,30 @@
+package cn.iocoder.yudao.module.guide.controller.admin.order.vo;
+
+import cn.iocoder.yudao.module.guide.controller.admin.base.member.user.MemberUserRespVO;
+import cn.iocoder.yudao.module.guide.controller.admin.base.product.property.ProductPropertyValueDetailRespVO;
+import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+@Schema(description = "管理后台 - 交易订单的分页项 Response VO")
+@Data
+public class GuideTradeOrderPageItemRespVO extends GuideTradeOrderBaseVO {
+
+
+    @Schema(description = "订单项列表", requiredMode = Schema.RequiredMode.REQUIRED)
+    private List<GuideTradeOrderItemBaseVO> items;
+
+    @Schema(description = "用户信息", requiredMode = Schema.RequiredMode.REQUIRED)
+    private MemberUserRespDTO user;
+
+//    @Schema(description = "管理后台 - 交易订单的分页项的订单项目")
+//    @Data
+//    public static class Item extends GuideTradeOrderItemBaseVO {
+//
+//       private List<>
+//        private
+//
+//    }
+}

+ 64 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/order/vo/GuideTradeOrderPageReqVO.java

@@ -0,0 +1,64 @@
+package cn.iocoder.yudao.module.guide.controller.admin.order.vo;
+
+import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.framework.common.validation.Mobile;
+import cn.iocoder.yudao.module.guide.enums.order.TradeOrderStatusEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 交易订单的分页 Request VO")
+@Data
+public class GuideTradeOrderPageReqVO extends PageParam {
+
+    @Schema(description = "订单号", example = "88888888")
+    private String no;
+
+    @Schema(description = "用户编号", example = "1024")
+    private Long userId;
+
+    @Schema(description = "用户昵称", example = "小王")
+    private String userNickname;
+
+    @Schema(description = "用户手机号", example = "小王")
+    @Mobile
+    private String userMobile;
+
+    @Schema(description = "配送方式", example = "1")
+    private Integer deliveryType;
+
+    @Schema(description = "发货物流公司编号", example = "1")
+    private Long logisticsId;
+
+    @Schema(description = "自提门店编号", example = "[1,2]")
+    private List<Long> pickUpStoreIds;
+
+    @Schema(description = "自提核销码", example = "12345678")
+    private String pickUpVerifyCode;
+
+    @Schema(description = "订单类型", example = "1")
+    private Integer type;
+
+    @Schema(description = "订单状态", example = "1")
+    @InEnum(value = TradeOrderStatusEnum.class, message = "订单状态必须是 {value}")
+    private Integer status;
+
+    @Schema(description = "支付渠道", example = "wx_lite")
+    private String payChannelCode;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+    @Schema(description = "订单来源", example = "10")
+    @InEnum(value = TerminalEnum.class, message = "订单来源 {value}")
+    private Integer terminal;
+
+}

+ 20 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/order/vo/GuideTradeOrderRemarkReqVO.java

@@ -0,0 +1,20 @@
+package cn.iocoder.yudao.module.guide.controller.admin.order.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+@Schema(description = "管理后台 - 订单备注 Request VO")
+@Data
+public class GuideTradeOrderRemarkReqVO {
+
+    @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    @NotNull(message = "订单编号不能为空")
+    private Long id;
+
+    @Schema(description = "商家备注", example = "你猜一下")
+    @NotEmpty(message = "订单备注不能为空")
+    private String remark;
+
+}

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

@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.guide.controller.admin.order.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "管理后台 - 交易订单统计 Response VO")
+@Data
+public class GuideTradeOrderSummaryRespVO {
+
+    @Schema(description = "订单数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    private Long orderCount;
+
+    @Schema(description = "订单金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    private Long orderPayPrice;
+
+    @Schema(description = "退款单数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    private Long afterSaleCount;
+
+    @Schema(description = "退款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    private Long afterSalePrice;
+
+}

+ 32 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/order/vo/GuideTradeOrderUpdateAddressReqVO.java

@@ -0,0 +1,32 @@
+package cn.iocoder.yudao.module.guide.controller.admin.order.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+@Schema(description = "管理后台 - 订单修改地址 Request VO")
+@Data
+public class GuideTradeOrderUpdateAddressReqVO {
+
+    @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @NotNull(message = "订单编号不能为空")
+    private Long id;
+
+    @Schema(description = "收件人名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "z张三")
+    @NotEmpty(message = "收件人名称不能为空")
+    private String receiverName;
+
+    @Schema(description = "收件人手机", requiredMode = Schema.RequiredMode.REQUIRED, example = "19988188888")
+    @NotEmpty(message = "收件人手机不能为空")
+    private String receiverMobile;
+
+    @Schema(description = "收件人地区编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "7310")
+    @NotNull(message = "收件人地区编号不能为空")
+    private Integer receiverAreaId;
+
+    @Schema(description = "收件人详细地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "昆明市五华区xxx小区xxx")
+    @NotEmpty(message = "收件人详细地址不能为空")
+    private String receiverDetailAddress;
+
+}

+ 19 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/order/vo/GuideTradeOrderUpdatePriceReqVO.java

@@ -0,0 +1,19 @@
+package cn.iocoder.yudao.module.guide.controller.admin.order.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+@Schema(description = "管理后台 - 订单改价 Request VO")
+@Data
+public class GuideTradeOrderUpdatePriceReqVO {
+
+    @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    @NotNull(message = "订单编号不能为空")
+    private Long id;
+
+    @Schema(description = "订单调价,单位:分。正数,加价;负数,减价", requiredMode = Schema.RequiredMode.REQUIRED, example = "-100")
+    @NotNull(message = "订单调价价格不能为空")
+    private Integer adjustPrice;
+
+}

+ 82 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/schedule/ScheduleController.java

@@ -0,0 +1,82 @@
+package cn.iocoder.yudao.module.guide.controller.admin.schedule;
+
+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.schedule.vo.*;
+import cn.iocoder.yudao.module.guide.dal.dataobject.schedule.ScheduleDO;
+import cn.iocoder.yudao.module.guide.service.schedule.ScheduleService;
+
+@Tag(name = "管理后台 - 预约旅程日程管理情报")
+@RestController
+@RequestMapping("/guide/schedule")
+@Validated
+public class ScheduleController {
+
+    @Resource
+    private ScheduleService scheduleService;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建预约旅程日程管理情报")
+    @PreAuthorize("@ss.hasPermission('guide:schedule:create')")
+    public CommonResult<Long> createSchedule(@Valid @RequestBody ScheduleSaveReqVO createReqVO) {
+        return success(scheduleService.createSchedule(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新预约旅程日程管理情报")
+    @PreAuthorize("@ss.hasPermission('guide:schedule:update')")
+    public CommonResult<Boolean> updateSchedule(@Valid @RequestBody ScheduleSaveReqVO updateReqVO) {
+        scheduleService.updateSchedule(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除预约旅程日程管理情报")
+    @Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('guide:schedule:delete')")
+    public CommonResult<Boolean> deleteSchedule(@RequestParam("id") Long id) {
+        scheduleService.deleteSchedule(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得预约旅程日程管理情报")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('guide:schedule:query')")
+    public CommonResult<ScheduleRespVO> getSchedule(@RequestParam("id") Long id) {
+        ScheduleDO schedule = scheduleService.getSchedule(id);
+        return success(BeanUtils.toBean(schedule, ScheduleRespVO.class));
+    }
+
+    @GetMapping("/list")
+    @Operation(summary = "获得预约旅程日程管理情报")
+    @PreAuthorize("@ss.hasPermission('guide:schedule:query')")
+    public CommonResult<List<ScheduleRespVO>> getScheduleList(@RequestParam("guideId") Long guideId) {
+        List<ScheduleDO> listResult = scheduleService.getScheduleList(guideId);
+        return success(BeanUtils.toBean(listResult, ScheduleRespVO.class));
+    }
+
+}

+ 36 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/schedule/vo/SchedulePageReqVO.java

@@ -0,0 +1,36 @@
+package cn.iocoder.yudao.module.guide.controller.admin.schedule.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;
+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 SchedulePageReqVO extends PageParam {
+
+    @Schema(description = "导游编号", example = "23882")
+    private Long guideId;
+
+    @Schema(description = "预约日期")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
+    private LocalDateTime[] bookingDate;
+
+    @Schema(description = "是否可以被预约")
+    private Boolean bookingAvailability;
+
+    @Schema(description = "已经被预约否?")
+    private Boolean booked;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

+ 40 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/schedule/vo/ScheduleRespVO.java

@@ -0,0 +1,40 @@
+package cn.iocoder.yudao.module.guide.controller.admin.schedule.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.*;
+
+@Schema(description = "管理后台 - 预约旅程日程管理情报 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class ScheduleRespVO {
+
+    @Schema(description = "旅程日程编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4853")
+    @ExcelProperty("旅程日程编号")
+    private Long id;
+
+    @Schema(description = "导游编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23882")
+    @ExcelProperty("导游编号")
+    private Long guideId;
+
+    @Schema(description = "预约日期", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("预约日期")
+    private LocalDateTime bookingDate;
+
+    @Schema(description = "是否可以被预约", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("是否可以被预约")
+    private Boolean bookingAvailability;
+
+    @Schema(description = "已经被预约否?", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("已经被预约否?")
+    private Boolean booked;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+}

+ 33 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/schedule/vo/ScheduleSaveReqVO.java

@@ -0,0 +1,33 @@
+package cn.iocoder.yudao.module.guide.controller.admin.schedule.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import jakarta.validation.constraints.*;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 预约旅程日程管理情报新增/修改 Request VO")
+@Data
+public class ScheduleSaveReqVO {
+
+    @Schema(description = "旅程日程编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4853")
+    private Long id;
+
+    @Schema(description = "导游编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23882")
+    @NotNull(message = "导游编号不能为空")
+    private Long guideId;
+
+    @Schema(description = "预约日期", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "预约日期不能为空")
+    private LocalDateTime bookingDate;
+
+    @Schema(description = "是否可以被预约", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "是否可以被预约不能为空")
+    private Boolean bookingAvailability;
+
+    @Schema(description = "已经被预约否?", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "已经被预约否?不能为空")
+    private Boolean booked;
+
+}

+ 77 - 16
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/sights/SightsController.java

@@ -1,5 +1,8 @@
 package cn.iocoder.yudao.module.guide.controller.admin.sights;
 
+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;
@@ -27,10 +30,11 @@ import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
 
 import cn.iocoder.yudao.module.guide.controller.admin.sights.vo.*;
 import cn.iocoder.yudao.module.guide.dal.dataobject.sights.SightsDO;
+import cn.iocoder.yudao.module.guide.dal.dataobject.sights.SightsCommentDO;
 import cn.iocoder.yudao.module.guide.dal.dataobject.sights.SightsI18nExtensionDO;
 import cn.iocoder.yudao.module.guide.service.sights.SightsService;
 
-@Tag(name = "管理后台 - 观光景点基本信息")
+@Tag(name = "管理后台 - 观光景点")
 @RestController
 @RequestMapping("/guide/sights")
 @Validated
@@ -40,14 +44,14 @@ public class SightsController {
     private SightsService sightsService;
 
     @PostMapping("/create")
-    @Operation(summary = "创建观光景点基本信息")
+    @Operation(summary = "创建观光景点")
     @PreAuthorize("@ss.hasPermission('guide:sights:create')")
     public CommonResult<Long> createSights(@Valid @RequestBody SightsSaveReqVO createReqVO) {
         return success(sightsService.createSights(createReqVO));
     }
 
     @PutMapping("/update")
-    @Operation(summary = "更新观光景点基本信息")
+    @Operation(summary = "更新观光景点")
     @PreAuthorize("@ss.hasPermission('guide:sights:update')")
     public CommonResult<Boolean> updateSights(@Valid @RequestBody SightsSaveReqVO updateReqVO) {
         sightsService.updateSights(updateReqVO);
@@ -55,7 +59,7 @@ public class SightsController {
     }
 
     @DeleteMapping("/delete")
-    @Operation(summary = "删除观光景点基本信息")
+    @Operation(summary = "删除观光景点")
     @Parameter(name = "id", description = "编号", required = true)
     @PreAuthorize("@ss.hasPermission('guide:sights:delete')")
     public CommonResult<Boolean> deleteSights(@RequestParam("id") Long id) {
@@ -64,7 +68,7 @@ public class SightsController {
     }
 
     @GetMapping("/get")
-    @Operation(summary = "获得观光景点基本信息")
+    @Operation(summary = "获得观光景点")
     @Parameter(name = "id", description = "编号", required = true, example = "1024")
     @PreAuthorize("@ss.hasPermission('guide:sights:query')")
     public CommonResult<SightsRespVO> getSights(@RequestParam("id") Long id) {
@@ -72,8 +76,15 @@ public class SightsController {
         return success(BeanUtils.toBean(sights, SightsRespVO.class));
     }
 
+    @GetMapping("/list")
+    @Operation(summary = "获得观光景点列表(不包含在trip-sights中的列表)")
+    @PreAuthorize("@ss.hasPermission('guide:sights:query')")
+    public CommonResult<List<SightsRespVO>> getSightsCategoryList(@Valid SightsPageReqVO listReqVO) {
+        List<SightsDO> list = sightsService.getSightsList(listReqVO);
+        return success(BeanUtils.toBean(list, SightsRespVO.class));
+    }
     @GetMapping("/page")
-    @Operation(summary = "获得观光景点基本信息分页")
+    @Operation(summary = "获得观光景点分页")
     @PreAuthorize("@ss.hasPermission('guide:sights:query')")
     public CommonResult<PageResult<SightsRespVO>> getSightsPage(@Valid SightsPageReqVO pageReqVO) {
         PageResult<SightsDO> pageResult = sightsService.getSightsPage(pageReqVO);
@@ -81,7 +92,7 @@ public class SightsController {
     }
 
     @GetMapping("/export-excel")
-    @Operation(summary = "导出观光景点基本信息 Excel")
+    @Operation(summary = "导出观光景点 Excel")
     @PreAuthorize("@ss.hasPermission('guide:sights:export')")
     @ApiAccessLog(operateType = EXPORT)
     public void exportSightsExcel(@Valid SightsPageReqVO pageReqVO,
@@ -89,30 +100,80 @@ public class SightsController {
         pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
         List<SightsDO> list = sightsService.getSightsPage(pageReqVO).getList();
         // 导出 Excel
-        ExcelUtils.write(response, "观光景点基本信息.xls", "数据", SightsRespVO.class,
+        ExcelUtils.write(response, "观光景点.xls", "数据", SightsRespVO.class,
                         BeanUtils.toBean(list, SightsRespVO.class));
     }
+    @GetMapping("/get-count")
+    @Operation(summary = "获得景点 count")
+    @PreAuthorize("@ss.hasPermission('guide:sights:query')")
+    public CommonResult<Long> getSightCount() {
+        return success(sightsService.getCount());
+    }
+    // ==================== 子表(观光景点评论) ====================
+
+    @GetMapping("/sights-comment/page")
+    @Operation(summary = "获得观光景点评论分页")
+    @Parameter(name = "sightsId", description = "观光景点编号,关联 SightDO 的 id")
+    @PreAuthorize("@ss.hasPermission('guide:sights:query')")
+    public CommonResult<PageResult<SightsCommentDO>> getSightsCommentPage(PageParam pageReqVO,
+                                                                                        @RequestParam("sightsId") Long sightsId) {
+        return success(sightsService.getSightsCommentPage(pageReqVO, sightsId));
+    }
+
+    @PostMapping("/sights-comment/create")
+    @Operation(summary = "创建观光景点评论")
+    @PreAuthorize("@ss.hasPermission('guide:sights:create')")
+    public CommonResult<Long> createSightsComment(@Valid @RequestBody SightsCommentDO sightsComment) {
+        return success(sightsService.createSightsComment(sightsComment));
+    }
+
+    @PutMapping("/sights-comment/update")
+    @Operation(summary = "更新观光景点评论")
+    @PreAuthorize("@ss.hasPermission('guide:sights:update')")
+    public CommonResult<Boolean> updateSightsComment(@Valid @RequestBody SightsCommentDO sightsComment) {
+        sightsService.updateSightsComment(sightsComment);
+        return success(true);
+    }
+
+    @DeleteMapping("/sights-comment/delete")
+    @Parameter(name = "id", description = "编号", required = true)
+    @Operation(summary = "删除观光景点评论")
+    @PreAuthorize("@ss.hasPermission('guide:sights:delete')")
+    public CommonResult<Boolean> deleteSightsComment(@RequestParam("id") Long id) {
+        sightsService.deleteSightsComment(id);
+        return success(true);
+    }
+
+	@GetMapping("/sights-comment/get")
+	@Operation(summary = "获得观光景点评论")
+	@Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('guide:sights:query')")
+	public CommonResult<SightsCommentDO> getSightsComment(@RequestParam("id") Long id) {
+	    return success(sightsService.getSightsComment(id));
+	}
 
-    // ==================== 子表(观光景点对语言扩充信息) ====================
+    // ==================== 子表(观光景点语言扩充信息) ====================
 
     @GetMapping("/sights-i18n-extension/page")
-    @Operation(summary = "获得观光景点对语言扩充信息分页")
-    @Parameter(name = "sightsId", description = "景点")
+    @Operation(summary = "获得观光景点语言扩充信息分页")
+    @Parameter(name = "sightsId", description = "景点编号 关联 sightDO 的 id 编号")
     @PreAuthorize("@ss.hasPermission('guide:sights:query')")
     public CommonResult<PageResult<SightsI18nExtensionDO>> getSightsI18nExtensionPage(PageParam pageReqVO,
                                                                                         @RequestParam("sightsId") Long sightsId) {
-        return success(sightsService.getSightsI18nExtensionPage(pageReqVO, sightsId));
+        PageResult<SightsI18nExtensionDO> test= sightsService.getSightsI18nExtensionPage(pageReqVO, sightsId);
+        return success(test);
+//        return success(sightsService.getSightsI18nExtensionPage(pageReqVO, sightsId));
     }
 
     @PostMapping("/sights-i18n-extension/create")
-    @Operation(summary = "创建观光景点对语言扩充信息")
+    @Operation(summary = "创建观光景点语言扩充信息")
     @PreAuthorize("@ss.hasPermission('guide:sights:create')")
     public CommonResult<Long> createSightsI18nExtension(@Valid @RequestBody SightsI18nExtensionDO sightsI18nExtension) {
         return success(sightsService.createSightsI18nExtension(sightsI18nExtension));
     }
 
     @PutMapping("/sights-i18n-extension/update")
-    @Operation(summary = "更新观光景点对语言扩充信息")
+    @Operation(summary = "更新观光景点语言扩充信息")
     @PreAuthorize("@ss.hasPermission('guide:sights:update')")
     public CommonResult<Boolean> updateSightsI18nExtension(@Valid @RequestBody SightsI18nExtensionDO sightsI18nExtension) {
         sightsService.updateSightsI18nExtension(sightsI18nExtension);
@@ -121,7 +182,7 @@ public class SightsController {
 
     @DeleteMapping("/sights-i18n-extension/delete")
     @Parameter(name = "id", description = "编号", required = true)
-    @Operation(summary = "删除观光景点语言扩充信息")
+    @Operation(summary = "删除观光景点语言扩充信息")
     @PreAuthorize("@ss.hasPermission('guide:sights:delete')")
     public CommonResult<Boolean> deleteSightsI18nExtension(@RequestParam("id") Long id) {
         sightsService.deleteSightsI18nExtension(id);
@@ -129,7 +190,7 @@ public class SightsController {
     }
 
 	@GetMapping("/sights-i18n-extension/get")
-	@Operation(summary = "获得观光景点语言扩充信息")
+	@Operation(summary = "获得观光景点语言扩充信息")
 	@Parameter(name = "id", description = "编号", required = true)
     @PreAuthorize("@ss.hasPermission('guide:sights:query')")
 	public CommonResult<SightsI18nExtensionDO> getSightsI18nExtension(@RequestParam("id") Long id) {

+ 7 - 1
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/sights/vo/SightsPageReqVO.java

@@ -9,15 +9,21 @@ 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")
+@Schema(description = "管理后台 - 观光景点分页 Request VO")
 @Data
 @EqualsAndHashCode(callSuper = true)
 @ToString(callSuper = true)
 public class SightsPageReqVO extends PageParam {
 
+    @Schema(description = "旅程ID")
+    private Long tripId;
+
     @Schema(description = "景点分类数组,以逗号分隔")
     private List<Integer> categoryIds;
 
+    @Schema(description = "地域数组,以逗号分隔")
+    private List<Integer> geographicalIds;
+
     @Schema(description = "电话号码")
     private String tel;
 

+ 20 - 1
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/sights/vo/SightsRespVO.java

@@ -1,5 +1,7 @@
 package cn.iocoder.yudao.module.guide.controller.admin.sights.vo;
 
+import cn.iocoder.yudao.module.guide.dal.dataobject.sights.SightsCommentDO;
+import cn.iocoder.yudao.module.guide.dal.dataobject.sights.SightsI18nExtensionDO;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.*;
 import java.util.*;
@@ -10,7 +12,7 @@ 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")
+@Schema(description = "管理后台 - 观光景点 Response VO")
 @Data
 @ExcelIgnoreUnannotated
 public class SightsRespVO {
@@ -27,6 +29,10 @@ public class SightsRespVO {
     @ExcelProperty("景点封面图")
     private String picUrl;
 
+    @Schema(description = "景点轮播图", example = "https://www.iocoder.cn")
+    @ExcelProperty("景点轮播图")
+    private List<String> sliderPicUrls;
+
     @Schema(description = "官网URL", example = "https://www.iocoder.cn")
     @ExcelProperty("官网URL")
     private String url;
@@ -43,13 +49,26 @@ public class SightsRespVO {
     @ExcelProperty("大致游玩所需时间")
     private Integer durationSightseeing;
 
+    @Schema(description = "排序")
+    @ExcelProperty("排序")
+    private Integer sort;
+
     @Schema(description = "状态: 1 上架(开启) 0 下架(禁用) -1 回收", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
     @ExcelProperty(value = "状态: 1 上架(开启) 0 下架(禁用) -1 回收", converter = DictConvert.class)
     @DictFormat("product_spu_status") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
     private Integer status;
 
+    @Schema(description = "地理信息表ID数组,以逗号分隔")
+    @ExcelProperty("地理信息表ID数组,以逗号分隔")
+    private List<Integer> geographicalIds;
+
     @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
     @ExcelProperty("创建时间")
     private LocalDateTime createTime;
 
+    @Schema(description = "多语言信息")
+    private List<SightsI18nExtensionDO>  sightsI18nExtensionDOList;
+
+    @Schema(description = "评价信息")
+    private List<SightsCommentDO>  sightsCommentDOList;
 }

+ 6 - 3
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/admin/sights/vo/SightsSaveReqVO.java

@@ -4,9 +4,12 @@ import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.*;
 import java.util.*;
 import jakarta.validation.constraints.*;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+import cn.iocoder.yudao.module.guide.dal.dataobject.sights.SightsCommentDO;
 import cn.iocoder.yudao.module.guide.dal.dataobject.sights.SightsI18nExtensionDO;
 
-@Schema(description = "管理后台 - 观光景点基本信息新增/修改 Request VO")
+@Schema(description = "管理后台 - 观光景点新增/修改 Request VO")
 @Data
 public class SightsSaveReqVO {
 
@@ -35,8 +38,8 @@ public class SightsSaveReqVO {
     @Schema(description = "大致游玩所需时间")
     private Integer durationSightseeing;
 
-    @Schema(description = "地理信息表ID", example = "5209")
-    private Long geographicalId;
+    @Schema(description = "地理信息表ID数组", example = "5209,12345")
+    private List<Integer> geographicalIds;
 
     @Schema(description = "排序")
     private Integer sort;

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

@@ -79,6 +79,14 @@ public class SightsCategoryController {
         return success(BeanUtils.toBean(list, SightsCategoryRespVO.class));
     }
 
+    @GetMapping("/categorys")
+    @Operation(summary = "获得观光景点分类列表")
+    @PreAuthorize("@ss.hasPermission('guide:sights-category:query')")
+    public CommonResult<List<SightsCategoryRespVO>> getSightsCategorys(@RequestParam List<Integer> ids) {
+        List<SightsCategoryDO> list = sightsCategoryService.getSightsCategoryList(ids);
+        return success(BeanUtils.toBean(list, SightsCategoryRespVO.class));
+    }
+
     @GetMapping("/export-excel")
     @Operation(summary = "导出观光景点分类 Excel")
     @PreAuthorize("@ss.hasPermission('guide:sights-category:export')")

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

@@ -0,0 +1,190 @@
+package cn.iocoder.yudao.module.guide.controller.admin.trip;
+
+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.trip.vo.*;
+import cn.iocoder.yudao.module.guide.dal.dataobject.trip.TripDO;
+import cn.iocoder.yudao.module.guide.dal.dataobject.trip.TripI18nExtensionDO;
+import cn.iocoder.yudao.module.guide.dal.dataobject.trip.TripSightsDO;
+import cn.iocoder.yudao.module.guide.service.trip.TripService;
+
+@Tag(name = "管理后台 - 旅程基本情报")
+@RestController
+@RequestMapping("/guide/trip")
+@Validated
+public class TripController {
+
+    @Resource
+    private TripService tripService;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建旅程基本情报")
+    @PreAuthorize("@ss.hasPermission('guide:trip:create')")
+    public CommonResult<Long> createTrip(@Valid @RequestBody TripSaveReqVO createReqVO) {
+        return success(tripService.createTrip(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新旅程基本情报")
+    @PreAuthorize("@ss.hasPermission('guide:trip:update')")
+    public CommonResult<Boolean> updateTrip(@Valid @RequestBody TripSaveReqVO updateReqVO) {
+        tripService.updateTrip(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除旅程基本情报")
+    @Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('guide:trip:delete')")
+    public CommonResult<Boolean> deleteTrip(@RequestParam("id") Long id) {
+        tripService.deleteTrip(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得旅程基本情报")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('guide:trip:query')")
+    public CommonResult<TripRespVO> getTrip(@RequestParam("id") Long id) {
+        TripDO trip = tripService.getTrip(id);
+        return success(BeanUtils.toBean(trip, TripRespVO.class));
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得旅程基本情报分页")
+    @PreAuthorize("@ss.hasPermission('guide:trip:query')")
+    public CommonResult<PageResult<TripRespVO>> getTripPage(@Valid TripPageReqVO pageReqVO) {
+        PageResult<TripDO> pageResult = tripService.getTripPage(pageReqVO);
+        CommonResult<PageResult<TripRespVO>> returnV = success(BeanUtils.toBean(pageResult, TripRespVO.class));
+        return returnV;
+    }
+    @GetMapping("/get-count")
+    @Operation(summary = "获得旅程 count")
+    @PreAuthorize("@ss.hasPermission('guide:trip:query')")
+    public CommonResult<Long> getTripCount() {
+        return success(tripService.getCount());
+    }
+
+    @GetMapping("/export-excel")
+    @Operation(summary = "导出旅程基本情报 Excel")
+    @PreAuthorize("@ss.hasPermission('guide:trip:export')")
+    @ApiAccessLog(operateType = EXPORT)
+    public void exportTripExcel(@Valid TripPageReqVO pageReqVO,
+              HttpServletResponse response) throws IOException {
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        List<TripDO> list = tripService.getTripPage(pageReqVO).getList();
+        // 导出 Excel
+        ExcelUtils.write(response, "旅程基本情报.xls", "数据", TripRespVO.class,
+                        BeanUtils.toBean(list, TripRespVO.class));
+    }
+
+    // ==================== 子表(旅程多语言扩充信息) ====================
+
+    @GetMapping("/trip-i18n-extension/page")
+    @Operation(summary = "获得旅程多语言扩充信息分页")
+    @Parameter(name = "tripId", description = "旅程编号(关联 tripDO 的 id 编号)")
+    @PreAuthorize("@ss.hasPermission('guide:trip:query')")
+    public CommonResult<PageResult<TripI18nExtensionDO>> getTripI18nExtensionPage(PageParam pageReqVO,
+                                                                                        @RequestParam("tripId") Long tripId) {
+        return success(tripService.getTripI18nExtensionPage(pageReqVO, tripId));
+    }
+
+    @PostMapping("/trip-i18n-extension/create")
+    @Operation(summary = "创建旅程多语言扩充信息")
+    @PreAuthorize("@ss.hasPermission('guide:trip:create')")
+    public CommonResult<Long> createTripI18nExtension(@Valid @RequestBody TripI18nExtensionDO tripI18nExtension) {
+        return success(tripService.createTripI18nExtension(tripI18nExtension));
+    }
+
+    @PutMapping("/trip-i18n-extension/update")
+    @Operation(summary = "更新旅程多语言扩充信息")
+    @PreAuthorize("@ss.hasPermission('guide:trip:update')")
+    public CommonResult<Boolean> updateTripI18nExtension(@Valid @RequestBody TripI18nExtensionDO tripI18nExtension) {
+        tripService.updateTripI18nExtension(tripI18nExtension);
+        return success(true);
+    }
+
+    @DeleteMapping("/trip-i18n-extension/delete")
+    @Parameter(name = "id", description = "编号", required = true)
+    @Operation(summary = "删除旅程多语言扩充信息")
+    @PreAuthorize("@ss.hasPermission('guide:trip:delete')")
+    public CommonResult<Boolean> deleteTripI18nExtension(@RequestParam("id") Long id) {
+        tripService.deleteTripI18nExtension(id);
+        return success(true);
+    }
+
+	@GetMapping("/trip-i18n-extension/get")
+	@Operation(summary = "获得旅程多语言扩充信息")
+	@Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('guide:trip:query')")
+	public CommonResult<TripI18nExtensionDO> getTripI18nExtension(@RequestParam("id") Long id) {
+	    return success(tripService.getTripI18nExtension(id));
+	}
+
+    // ==================== 子表(旅程详细情报) ====================
+
+    @GetMapping("/trip-sights/page")
+    @Operation(summary = "获得旅程详细情报分页")
+    @Parameter(name = "tripId", description = "旅程编号")
+    @PreAuthorize("@ss.hasPermission('guide:trip:query')")
+    public CommonResult<PageResult<TripSightsDO>> getTripSightsPage(PageParam pageReqVO,
+                                                                                        @RequestParam("tripId") Long tripId) {
+        return success(tripService.getTripSightsPage(pageReqVO, tripId));
+    }
+
+    @PostMapping("/trip-sights/create")
+    @Operation(summary = "创建旅程详细情报")
+    @PreAuthorize("@ss.hasPermission('guide:trip:create')")
+    public CommonResult<Long> createTripSights(@Valid @RequestBody TripSightsSaveVO tripSights) {
+        return success(tripService.createTripSights(tripSights));
+    }
+
+    @PutMapping("/trip-sights/update")
+    @Operation(summary = "更新旅程详细情报")
+    @PreAuthorize("@ss.hasPermission('guide:trip:update')")
+    public CommonResult<Boolean> updateTripSights(@Valid @RequestBody TripSightsDO tripSights) {
+        tripService.updateTripSights(tripSights);
+        return success(true);
+    }
+
+    @DeleteMapping("/trip-sights/delete")
+    @Parameter(name = "id", description = "编号", required = true)
+    @Operation(summary = "删除旅程详细情报")
+    @PreAuthorize("@ss.hasPermission('guide:trip:delete')")
+    public CommonResult<Boolean> deleteTripSights(@RequestParam("id") Long id) {
+        tripService.deleteTripSights(id);
+        return success(true);
+    }
+
+	@GetMapping("/trip-sights/get")
+	@Operation(summary = "获得旅程详细情报")
+	@Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('guide:trip:query')")
+	public CommonResult<TripSightsDO> getTripSights(@RequestParam("id") Long id) {
+	    return success(tripService.getTripSights(id));
+	}
+
+}

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

@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.module.guide.controller.admin.trip.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 TripPageReqVO extends PageParam {
+
+    @Schema(description = "导游编号", example = "18507")
+    private Long guideId;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

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

@@ -0,0 +1,54 @@
+package cn.iocoder.yudao.module.guide.controller.admin.trip.vo;
+
+import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
+import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.*;
+import java.util.*;
+import java.util.*;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+import com.alibaba.excel.annotation.*;
+
+@Schema(description = "管理后台 - 旅程基本情报 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class TripRespVO {
+
+    @Schema(description = "旅程编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20578")
+    @ExcelProperty("旅程编号")
+    private Long id;
+
+    @Schema(description = "导游编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18507")
+    @ExcelProperty("导游编号")
+    private Long guideId;
+
+    @Schema(description = "服务对象人数上限", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("服务对象人数上限")
+    private Integer maximumNumber;
+
+    @Schema(description = "导游服务价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "5929")
+    @ExcelProperty("导游服务价格")
+    private Integer price;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+    @Schema(description = "景点封面图", example = "https://www.iocoder.cn")
+    private String picUrl;
+
+    @Schema(description = "旅程开始时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("旅程开始时间")
+    private LocalDateTime startTime;
+
+    @Schema(description = "旅程结束时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("旅程结束时间")
+    private LocalDateTime endTime;
+
+    @Schema(description = "开启状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @ExcelProperty(value = "开启状态", converter = DictConvert.class)
+    @DictFormat("product_spu_status") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
+    private Integer status;
+}

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

@@ -0,0 +1,51 @@
+package cn.iocoder.yudao.module.guide.controller.admin.trip.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import jakarta.validation.constraints.*;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+import cn.iocoder.yudao.module.guide.dal.dataobject.trip.TripI18nExtensionDO;
+import cn.iocoder.yudao.module.guide.dal.dataobject.trip.TripSightsDO;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 旅程基本情报新增/修改 Request VO")
+@Data
+public class TripSaveReqVO {
+
+    @Schema(description = "旅程编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20578")
+    private Long id;
+
+    @Schema(description = "导游编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18507")
+    @NotNull(message = "导游编号不能为空")
+    private Long guideId;
+
+    @Schema(description = "景点封面图", example = "https://www.iocoder.cn")
+    private String picUrl;
+
+    @Schema(description = "旅程开始时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "旅程开始时间不能为空")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime startTime;
+
+    @Schema(description = "旅程结束时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "旅程结束时间不能为空")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime endTime;
+
+    @Schema(description = "服务对象人数上限", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "服务对象人数上限不能为空")
+    private Integer maximumNumber;
+
+    @Schema(description = "导游服务价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "5929")
+    @NotNull(message = "导游服务价格不能为空")
+    private Integer price;
+
+    @Schema(description = "开启状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @NotNull(message = "开启状态不能为空")
+    private Integer status;
+
+}

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

@@ -0,0 +1,24 @@
+package cn.iocoder.yudao.module.guide.controller.admin.trip.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+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 = "管理后台 - 旅程基本情报 Save VO")
+@Data
+@ExcelIgnoreUnannotated
+public class TripSightsSaveVO {
+
+    @Schema(description = "旅程编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20578")
+    @ExcelProperty("旅程编号")
+    private Long tripId;
+
+    @Schema(description = "景点编号s", requiredMode = Schema.RequiredMode.REQUIRED, example = "【18507,123】")
+    @ExcelProperty("景点编号s")
+    private List<Long> sightsIds;
+
+}

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

@@ -0,0 +1,158 @@
+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;
+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 static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
+
+import cn.iocoder.yudao.module.guide.controller.admin.users.vo.*;
+import cn.iocoder.yudao.module.guide.dal.dataobject.users.UsersDO;
+import cn.iocoder.yudao.module.guide.dal.dataobject.users.CommentDO;
+import cn.iocoder.yudao.module.guide.service.users.UsersService;
+
+@Tag(name = "管理后台 - 导游信息")
+@RestController
+@RequestMapping("/guide/users")
+@Validated
+public class UsersController {
+
+    @Resource
+    private UsersService usersService;
+
+    @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);
+    }
+
+    @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);
+    }
+
+    @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));
+    }
+
+    @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));
+    }
+
+    @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 {
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        List<UsersDO> list = usersService.getUsersPage(pageReqVO).getList();
+        // 导出 Excel
+        ExcelUtils.write(response, "导游信息.xls", "数据", UsersRespVO.class,
+                        BeanUtils.toBean(list, UsersRespVO.class));
+    }
+
+    @GetMapping("/get-count")
+    @Operation(summary = "获得导游 count")
+    @PreAuthorize("@ss.hasPermission('guide:users:query')")
+    public CommonResult<Long> getGuideCount() {
+        return success(usersService.getCount());
+    }
+
+    // ==================== 子表(导游评论) ====================
+
+    @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));
+    }
+
+    @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);
+    }
+
+    @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);
+    }
+
+	@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));
+	}
+
+    @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());
+        return success(usersService.getSelfComment(getLoginUserId()));
+    }
+
+}

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

@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.module.guide.controller.admin.users.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 UsersPageReqVO extends PageParam {
+
+    @Schema(description = "用户账号", example = "赵六")
+    private String username;
+
+    @Schema(description = "部门ID", example = "6737")
+    private Long deptId;
+
+    @Schema(description = "手机号码")
+    private String mobile;
+
+    @Schema(description = "导游语言", example = "1")
+    private Integer languageType;
+
+    @Schema(description = "地域")
+    private String geographicalIds;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

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

@@ -0,0 +1,111 @@
+package cn.iocoder.yudao.module.guide.controller.admin.users.vo;
+
+import cn.iocoder.yudao.module.system.enums.DictTypeConstants;
+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 UsersRespVO {
+
+    @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @ExcelProperty("用户编号")
+    private Long id;
+
+    @Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao")
+    @ExcelProperty("用户名称")
+    private String username;
+
+    @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
+    @ExcelProperty("用户昵称")
+    private String nickname;
+
+    @Schema(description = "备注", example = "我是一个用户")
+    private String remark;
+
+    @Schema(description = "部门ID", example = "我是一个用户")
+    private Long deptId;
+    @Schema(description = "部门名称", example = "IT 部")
+    @ExcelProperty("部门名称")
+    private String deptName;
+
+    @Schema(description = "岗位编号数组", example = "1")
+    private Set<Long> postIds;
+
+    @Schema(description = "用户邮箱", example = "yudao@iocoder.cn")
+    @ExcelProperty("用户邮箱")
+    private String email;
+
+    @Schema(description = "手机号码", example = "15601691300")
+    @ExcelProperty("手机号码")
+    private String mobile;
+
+    @Schema(description = "用户性别,参见 SexEnum 枚举类", example = "1")
+    @ExcelProperty(value = "用户性别", converter = DictConvert.class)
+    @DictFormat(DictTypeConstants.USER_SEX)
+    private Integer sex;
+
+    @Schema(description = "用户头像", example = "https://www.iocoder.cn/xxx.png")
+    private String avatar;
+
+    @Schema(description = "状态,参见 CommonStatusEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @ExcelProperty(value = "帐号状态", converter = DictConvert.class)
+    @DictFormat(DictTypeConstants.COMMON_STATUS)
+    private Integer status;
+
+    @Schema(description = "最后登录 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "192.168.1.1")
+    @ExcelProperty("最后登录IP")
+    private String loginIp;
+
+    @Schema(description = "最后登录时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式")
+    @ExcelProperty("最后登录时间")
+    private LocalDateTime loginDate;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式")
+    private LocalDateTime createTime;
+
+    @Schema(description = "导游语言", example = "2")
+    private Integer languageType;
+
+    @Schema(description = "图文自我介绍")
+    private String selfIntroduction;
+
+    @Schema(description = "擅长领域")
+    private List<Long> categoryIds;
+
+    @Schema(description = "服务项目")
+    private String serviceItems;
+
+    @Schema(description = "注意事项", example = "随便")
+    private String memo;
+
+    @Schema(description = "导游服务价格", example = "30627")
+    private Integer price;
+
+    @Schema(description = "服务对象人数上限")
+    private Integer maximumNumber;
+
+    @Schema(description = "地域")
+    private List<Long> geographicalIds;
+
+    @Schema(description = "导游服务开始日")
+    private LocalDateTime startDate;
+
+    @Schema(description = "导游服务终了日")
+    private LocalDateTime endDate;
+
+    @Schema(description = "银行信息(后期需要扩展,平台和导游月底结账用)")
+    private String bankInfo;
+
+    @Schema(description = "导游图", example = "https://www.iocoder.cn")
+    private List<String> picUrls;
+
+}

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

@@ -0,0 +1,98 @@
+package cn.iocoder.yudao.module.guide.controller.admin.users.vo;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.mzt.logapi.starter.annotation.DiffLogField;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import jakarta.validation.constraints.*;
+import org.hibernate.validator.constraints.Length;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+import cn.iocoder.yudao.module.guide.dal.dataobject.users.CommentDO;
+
+@Schema(description = "管理后台 - 导游信息新增/修改 Request VO")
+@Data
+public class UsersSaveReqVO {
+
+    @Schema(description = "用户ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "20260")
+    private Long id;
+
+    @Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao")
+    @NotBlank(message = "用户账号不能为空")
+    @Pattern(regexp = "^[a-zA-Z0-9]{4,30}$", message = "用户账号由 数字、字母 组成")
+    @Size(min = 4, max = 30, message = "用户账号长度为 4-30 个字符")
+    @DiffLogField(name = "用户账号")
+    private String username;
+
+    @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
+    @Size(max = 30, message = "用户昵称长度不能超过30个字符")
+    @DiffLogField(name = "用户昵称")
+    private String nickname;
+
+    @Schema(description = "部门ID", example = "6737")
+    private Long deptId;
+
+    @Schema(description = "用户邮箱")
+    @Email(message = "邮箱格式不正确")
+    @Size(max = 50, message = "邮箱长度不能超过 50 个字符")
+    private String email;
+
+    @Schema(description = "手机号码")
+    private String mobile;
+
+    @Schema(description = "用户性别")
+    private Integer sex;
+
+    @Schema(description = "头像地址")
+    private String avatar;
+
+    @Schema(description = "导游语言", example = "1")
+    private Integer languageType;
+
+    @Schema(description = "图文自我介绍(多语言对应的json格式)")
+    private String selfIntroduction;
+
+    @Schema(description = "擅长领域")
+    private List<Long> categoryIds;
+
+    @Schema(description = "服务项目(多语言json)")
+    private String serviceItems;
+
+    @Schema(description = "提供服务时的注意事项(包含什么,不包含什么多语言json)", example = "随便")
+    private String memo;
+
+    @Schema(description = "导游服务价格", example = "7625")
+    private Integer price;
+
+    @Schema(description = "服务对象人数上限")
+    private Integer maximumNumber;
+
+    @Schema(description = "地域")
+    private List<Long> geographicalIds;
+
+    @Schema(description = "导游服务开始日")
+    private LocalDateTime startDate;
+
+    @Schema(description = "导游服务终了日")
+    private LocalDateTime endDate;
+
+    @Schema(description = "银行信息(后期需要扩展,平台和导游月底结账用)")
+    private String bankInfo;
+
+    @Schema(description = "导游图", example = "https://www.iocoder.cn")
+    private List<String> picUrls;
+
+    @Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456")
+    @Length(min = 4, max = 16, message = "密码长度为 4-16 位")
+    private String password;
+
+    @AssertTrue(message = "密码不能为空")
+    @JsonIgnore
+    public boolean isPasswordValid() {
+        return id != null // 修改时,不需要传递
+                || (ObjectUtil.isAllNotEmpty(password)); // 新增时,必须都传递 password
+    }
+
+}

+ 4 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/base/package-info.java

@@ -0,0 +1,4 @@
+/**
+ * 基础包,放一些通用的 VO 类
+ */
+package cn.iocoder.yudao.module.guide.controller.app.base;

+ 22 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/base/property/AppProductPropertyValueDetailRespVO.java

@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.guide.controller.app.base.property;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "用户 App - 商品属性值的明细 Response VO")
+@Data
+public class AppProductPropertyValueDetailRespVO {
+
+    @Schema(description = "属性的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    private Long propertyId;
+
+    @Schema(description = "属性的名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "颜色")
+    private String propertyName;
+
+    @Schema(description = "属性值的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    private Long valueId;
+
+    @Schema(description = "属性值的名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "红色")
+    private String valueName;
+
+}

+ 42 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/cart/AppCartController.http

@@ -0,0 +1,42 @@
+### 请求 /guide/cart/add 接口 => 成功
+POST {{appApi}}/guide/cart/add
+tenant-id: {{appTenentId}}
+Authorization: Bearer {{appToken}}
+Content-Type: application/json
+
+{
+  "skuId": 1,
+  "count": 10,
+  "addStatus": true
+}
+
+### 请求 /guide/cart/update 接口 => 成功
+PUT {{appApi}}/guide/cart/update
+tenant-id: {{appTenentId}}
+Authorization: Bearer {{appToken}}
+Content-Type: application/json
+
+{
+  "id": 35,
+  "count": 5
+}
+
+### 请求 /guide/cart/delete 接口 => 成功
+DELETE {{appApi}}/guide/cart/delete?ids=1
+tenant-id: {{appTenentId}}
+Authorization: Bearer {{appToken}}
+
+### 请求 /guide/cart/get-count 接口 => 成功
+GET {{appApi}}/guide/cart/get-count
+tenant-id: {{appTenentId}}
+Authorization: Bearer {{appToken}}
+
+### 请求 /guide/cart/get-count-map 接口 => 成功
+GET {{appApi}}/guide/cart/get-count-map
+tenant-id: {{appTenentId}}
+Authorization: Bearer {{appToken}}
+
+### 请求 /guide/cart/list 接口 => 成功
+GET {{appApi}}/guide/cart/list
+tenant-id: {{appTenentId}}
+Authorization: Bearer {{appToken}}

+ 87 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/cart/AppGuideCartController.java

@@ -0,0 +1,87 @@
+package cn.iocoder.yudao.module.guide.controller.app.cart;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
+import cn.iocoder.yudao.module.guide.service.cart.GuideCartService;
+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 lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import cn.iocoder.yudao.module.guide.controller.app.cart.vo.*;
+
+import java.util.List;
+
+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/cart")
+@RequiredArgsConstructor
+@Validated
+@Slf4j
+public class AppGuideCartController {
+
+    @Resource
+    private GuideCartService guideCartService;
+
+    @PostMapping("/add")
+    @Operation(summary = "添加购物车商品")
+    @PreAuthenticated
+    public CommonResult<Long> addCart(@Valid @RequestBody AppGuideCartAddReqVO addCountReqVO) {
+        return success(guideCartService.addCart(getLoginUserId(), addCountReqVO));
+    }
+
+    @PutMapping("/update-bookingdate")
+    @Operation(summary = "更新购物车商品数量")
+    @PreAuthenticated
+    public CommonResult<Boolean> updateCartBookingDate(@Valid @RequestBody AppGuideCartUpdateBookingDateReqVO updateReqVO) {
+        guideCartService.updateCartBookingDate(getLoginUserId(), updateReqVO);
+        return success(true);
+    }
+
+    @PutMapping("/update-selected")
+    @Operation(summary = "更新购物车商品选中")
+    @PreAuthenticated
+    public CommonResult<Boolean> updateCartSelected(@Valid @RequestBody AppGuideCartUpdateSelectedReqVO updateReqVO) {
+        guideCartService.updateCartSelected(getLoginUserId(), updateReqVO);
+        return success(true);
+    }
+
+    @PutMapping("/reset")
+    @Operation(summary = "重置购物车商品")
+    @PreAuthenticated
+    public CommonResult<Boolean> resetCart(@Valid @RequestBody AppGuideCartResetReqVO updateReqVO) {
+        guideCartService.resetCart(getLoginUserId(), updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除购物车商品")
+    @Parameter(name = "ids", description = "购物车商品编号", required = true, example = "1024,2048")
+    @PreAuthenticated
+    public CommonResult<Boolean> deleteCart(@RequestParam("ids") List<Long> ids) {
+        guideCartService.deleteCart(getLoginUserId(), ids);
+        return success(true);
+    }
+
+    @GetMapping("get-count")
+    @Operation(summary = "查询用户在购物车中的商品数量")
+    @PreAuthenticated
+    public CommonResult<Integer> getCartCount() {
+        return success(guideCartService.getCartCount(getLoginUserId()));
+    }
+
+    @GetMapping("/list")
+    @Operation(summary = "查询用户的购物车列表")
+    @PreAuthenticated
+    public CommonResult<AppGuideCartListRespVO> getCartList() {
+        return success(guideCartService.getCartList(getLoginUserId()));
+    }
+
+}

+ 25 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/cart/vo/AppGuideCartAddReqVO.java

@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.module.guide.controller.app.cart.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import net.sf.jsqlparser.expression.DateTimeLiteralExpression;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "用户 App - 购物车添加购物项 Request VO")
+@Data
+public class AppGuideCartAddReqVO {
+
+    @Schema(description = "导游 编号", requiredMode = Schema.RequiredMode.REQUIRED,example = "1024")
+    @NotNull(message = "导游 编号不能为空")
+    private Long guideId;
+
+    @Schema(description = "行程 编号", requiredMode = Schema.RequiredMode.REQUIRED,example = "1024")
+    private Long tripId;
+
+
+    @Schema(description = "预约日期", requiredMode = Schema.RequiredMode.REQUIRED)
+    private LocalDateTime bookingDate;
+
+}

+ 23 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/cart/vo/AppGuideCartListRespVO.java

@@ -0,0 +1,23 @@
+package cn.iocoder.yudao.module.guide.controller.app.cart.vo;
+
+import cn.iocoder.yudao.module.guide.controller.app.trip.vo.AppTripRespVO;
+import cn.iocoder.yudao.module.guide.dal.dataobject.cart.GuideCartDO;
+import cn.iocoder.yudao.module.guide.dal.dataobject.users.UsersDO;
+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 AppGuideCartListRespVO {
+    /**
+     * 有效的购物项数组
+     */
+    private List<GuideCartDO> validList;
+    /**
+     * 无效的购物项数组
+     */
+    private List<GuideCartDO> invalidList;
+}

+ 29 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/cart/vo/AppGuideCartResetReqVO.java

@@ -0,0 +1,29 @@
+package cn.iocoder.yudao.module.guide.controller.app.cart.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "用户 App - 购物车重置 Request VO")
+@Data
+public class AppGuideCartResetReqVO {
+
+    @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    @NotNull(message = "编号不能为空")
+    private Long id;
+
+    @Schema(description = "导游 编号", requiredMode = Schema.RequiredMode.REQUIRED,example = "1024")
+    @NotNull(message = "导游 编号不能为空")
+    private Long guideId;
+
+    @Schema(description = "行程 编号", requiredMode = Schema.RequiredMode.REQUIRED,example = "1024")
+    private Long tripId;
+
+
+    @Schema(description = "预约日期", requiredMode = Schema.RequiredMode.REQUIRED)
+    private LocalDateTime bookingDate;
+
+}

+ 21 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/cart/vo/AppGuideCartUpdateBookingDateReqVO.java

@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.module.guide.controller.app.cart.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "用户 App - 购物车更新预约日期 Request VO")
+@Data
+public class AppGuideCartUpdateBookingDateReqVO {
+
+    @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    @NotNull(message = "编号不能为空")
+    private Long id;
+
+    @Schema(description = "预约日期", requiredMode = Schema.RequiredMode.REQUIRED)
+    private LocalDateTime bookingDate;
+
+}

+ 21 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/cart/vo/AppGuideCartUpdateSelectedReqVO.java

@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.module.guide.controller.app.cart.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.util.Collection;
+
+@Schema(description = "用户 App - 购物车更新是否选中 Request VO")
+@Data
+public class AppGuideCartUpdateSelectedReqVO {
+
+    @Schema(description = "编号列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024,2048")
+    @NotNull(message = "编号列表不能为空")
+    private Collection<Long> ids;
+
+    @Schema(description = "是否选中", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
+    @NotNull(message = "是否选中不能为空")
+    private Boolean selected;
+
+}

+ 105 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/favorite/AppGuideTripFavoriteController.java

@@ -0,0 +1,105 @@
+package cn.iocoder.yudao.module.guide.controller.app.favorite;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
+import cn.iocoder.yudao.module.guide.controller.app.favorite.vo.AppFavoriteReqVO;
+import cn.iocoder.yudao.module.guide.controller.app.favorite.vo.AppFavoriteRespVO;
+import cn.iocoder.yudao.module.guide.controller.app.favorite.vo.AppGuideTripPageReqVO;
+import cn.iocoder.yudao.module.guide.controller.app.schedule.vo.AppScheduleRespVO;
+import cn.iocoder.yudao.module.guide.controller.app.sights.vo.AppSightsRespVO;
+import cn.iocoder.yudao.module.guide.controller.app.trip.vo.AppTripRespVO;
+import cn.iocoder.yudao.module.guide.controller.app.users.vo.AppUsersRespVO;
+import cn.iocoder.yudao.module.guide.dal.dataobject.favorite.GuideTripFavoriteDO;
+import cn.iocoder.yudao.module.guide.service.favorite.GuideTripFavoriteService;
+import cn.iocoder.yudao.module.guide.service.sights.SightsService;
+import cn.iocoder.yudao.module.guide.service.trip.TripService;
+import cn.iocoder.yudao.module.guide.service.users.UsersService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
+
+/**
+ * @author libin
+ */
+@Tag(name = "用户 APP - 收藏")
+@RestController
+@RequestMapping("/guide/trip/favorite")
+public class AppGuideTripFavoriteController {
+
+    @Resource
+    private GuideTripFavoriteService guideTripFavoriteService;
+    @Resource
+    private UsersService usersService; //guide
+
+    @Resource
+    private TripService tripService;
+    @Resource
+    private SightsService sightsService;
+    @PostMapping(value = "/create")
+    @Operation(summary = "添加商品收藏")
+    @PreAuthenticated
+    public CommonResult<Long> createFavorite(@RequestBody @Valid AppFavoriteReqVO reqVO) {
+        return success(guideTripFavoriteService.createFavorite(getLoginUserId(), reqVO));
+    }
+
+    @DeleteMapping(value = "/delete")
+    @Operation(summary = "取消单个商品收藏")
+    @PreAuthenticated
+    public CommonResult<Boolean> deleteFavorite(@RequestBody @Valid AppFavoriteReqVO reqVO) {
+        guideTripFavoriteService.deleteFavorite(getLoginUserId(), reqVO);
+        return success(Boolean.TRUE);
+    }
+
+    @GetMapping(value = "/page")
+    @Operation(summary = "获得商品收藏分页")
+    @PreAuthenticated
+    public CommonResult<PageResult<AppFavoriteRespVO>> getFavoritePage(AppGuideTripPageReqVO reqVO) {
+        PageResult<GuideTripFavoriteDO> favoritePage = guideTripFavoriteService.getFavoritePage(getLoginUserId(), reqVO);
+        if (CollUtil.isEmpty(favoritePage.getList())) {
+            return success(PageResult.empty());
+        }
+        List<AppFavoriteRespVO> appFavoriteRespVOList= BeanUtils.toBean(favoritePage.getList(), AppFavoriteRespVO.class);
+
+        for (AppFavoriteRespVO favorite:appFavoriteRespVOList) {
+            if (favorite.getGuideId()!=null) {
+                favorite.setGuideInfo(BeanUtils.toBean(usersService.getUsers(favorite.getGuideId()), AppUsersRespVO.class));
+            }
+            if (favorite.getTripId()!=null) {
+                favorite.setTripInfo(BeanUtils.toBean(tripService.getAppTrip(favorite.getTripId()), AppTripRespVO.class));
+            }
+            if (favorite.getSightsId()!=null) {
+                favorite.setSightsInfo(BeanUtils.toBean(sightsService.getSights(favorite.getSightsId()), AppSightsRespVO.class));
+            }
+        }
+        // 转换 VO 结果
+        PageResult<AppFavoriteRespVO> pageResult = new PageResult<>(favoritePage.getTotal());
+        pageResult.setList(appFavoriteRespVOList);
+        return success(pageResult);
+    }
+
+    @GetMapping(value = "/exits")
+    @Operation(summary = "检查是否收藏过商品")
+    @PreAuthenticated
+    public CommonResult<Boolean> isFavoriteExists(AppFavoriteReqVO reqVO) {
+        GuideTripFavoriteDO favorite = guideTripFavoriteService.getFavorite(getLoginUserId(), reqVO);
+        return success(favorite != null);
+    }
+
+    @GetMapping(value = "/get-count")
+    @Operation(summary = "获得商品收藏数量")
+    @PreAuthenticated
+    public CommonResult<Long> getFavoriteCount() {
+        return success(guideTripFavoriteService.getFavoriteCount(getLoginUserId()));
+    }
+
+}

+ 19 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/favorite/vo/AppFavoriteBatchReqVO.java

@@ -0,0 +1,19 @@
+package cn.iocoder.yudao.module.guide.controller.app.favorite.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotEmpty;
+import lombok.Data;
+
+import java.util.List;
+
+import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
+
+@Schema(description = "用户 APP - 商品收藏的批量 Request VO") // 用于收藏、取消收藏、获取收藏
+@Data
+public class AppFavoriteBatchReqVO {
+
+    @Schema(description = "商品 SPU 编号数组", requiredMode = REQUIRED, example = "29502")
+    @NotEmpty(message = "商品 SPU 编号数组不能为空")
+    private List<Long> spuIds;
+
+}

+ 22 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/favorite/vo/AppFavoriteReqVO.java

@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.guide.controller.app.favorite.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
+
+@Schema(description = "用户 APP - 商品收藏的单个 Request VO") // 用于收藏、取消收藏、获取收藏
+@Data
+public class AppFavoriteReqVO {
+
+    @Schema(description = "Guide 编号", requiredMode = REQUIRED, example = "29502")
+    private Long guideId;
+
+    @Schema(description = "Trip 编号", requiredMode = REQUIRED, example = "29502")
+    private Long tripId;
+
+    @Schema(description = "Sights 编号", requiredMode = REQUIRED, example = "29502")
+    private Long sightsId;
+
+}

+ 38 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/favorite/vo/AppFavoriteRespVO.java

@@ -0,0 +1,38 @@
+package cn.iocoder.yudao.module.guide.controller.app.favorite.vo;
+
+import cn.iocoder.yudao.module.guide.controller.app.sights.vo.AppSightsRespVO;
+import cn.iocoder.yudao.module.guide.controller.app.trip.vo.AppTripRespVO;
+import cn.iocoder.yudao.module.guide.controller.app.users.vo.AppUsersRespVO;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
+
+@Schema(description = "用户 App - 商品收藏 Response VO")
+@Data
+public class AppFavoriteRespVO {
+
+    @Schema(description = "编号", requiredMode = REQUIRED, example = "1")
+    private Long id;
+
+    @Schema(description = "Guide 编号", requiredMode = REQUIRED, example = "29502")
+    private Long guideId;
+
+    @Schema(description = "Trip 编号", requiredMode = REQUIRED, example = "29502")
+    private Long tripId;
+
+    @Schema(description = "Sights 编号", requiredMode = REQUIRED, example = "29502")
+    private Long sightsId;
+
+    // ========== 商品相关字段 ==========
+
+    @Schema(description = "导游")
+    private AppUsersRespVO guideInfo;
+
+    @Schema(description = "行程")
+    private AppTripRespVO tripInfo;
+
+    @Schema(description = "景点")
+    private AppSightsRespVO sightsInfo;
+
+}

+ 10 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/favorite/vo/AppGuideTripPageReqVO.java

@@ -0,0 +1,10 @@
+package cn.iocoder.yudao.module.guide.controller.app.favorite.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "用户 App - 商品收藏分页查询 Request VO")
+@Data
+public class AppGuideTripPageReqVO extends PageParam {
+}

+ 100 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/history/AppGuideBrowseHistoryController.java

@@ -0,0 +1,100 @@
+package cn.iocoder.yudao.module.guide.controller.app.history;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
+import cn.iocoder.yudao.module.guide.controller.admin.history.vo.GuideBrowseHistoryPageReqVO;
+import cn.iocoder.yudao.module.guide.controller.app.favorite.vo.AppFavoriteRespVO;
+import cn.iocoder.yudao.module.guide.controller.app.history.vo.AppGuideBrowseHistoryDeleteReqVO;
+import cn.iocoder.yudao.module.guide.controller.app.history.vo.AppGuideBrowseHistoryPageReqVO;
+import cn.iocoder.yudao.module.guide.controller.app.history.vo.AppGuideBrowseHistoryRespVO;
+import cn.iocoder.yudao.module.guide.controller.app.sights.vo.AppSightsRespVO;
+import cn.iocoder.yudao.module.guide.controller.app.trip.vo.AppTripRespVO;
+import cn.iocoder.yudao.module.guide.controller.app.users.vo.AppUsersRespVO;
+import cn.iocoder.yudao.module.guide.dal.dataobject.history.GuideBrowseHistoryDO;
+import cn.iocoder.yudao.module.guide.service.history.GuideBrowseHistoryService;
+import cn.iocoder.yudao.module.guide.service.sights.SightsService;
+import cn.iocoder.yudao.module.guide.service.trip.TripService;
+import cn.iocoder.yudao.module.guide.service.users.UsersService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+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 = "用户 APP - 商品浏览记录")
+@RestController
+@RequestMapping("/guide/browse-history")
+public class AppGuideBrowseHistoryController {
+
+    @Resource
+    private GuideBrowseHistoryService guideBrowseHistoryService;
+    @Resource
+    private UsersService usersService; //guide
+
+    @Resource
+    private TripService tripService;
+    @Resource
+    private SightsService sightsService;
+
+    @DeleteMapping(value = "/delete")
+    @Operation(summary = "删除商品浏览记录")
+    @PreAuthenticated
+    public CommonResult<Boolean> deleteBrowseHistory(@RequestBody @Valid AppGuideBrowseHistoryDeleteReqVO reqVO) {
+        guideBrowseHistoryService.hideUserBrowseHistory(getLoginUserId(), reqVO.getIds());
+        return success(Boolean.TRUE);
+    }
+
+    @DeleteMapping(value = "/clean")
+    @Operation(summary = "清空商品浏览记录")
+    @PreAuthenticated
+    public CommonResult<Boolean> deleteBrowseHistory() {
+        guideBrowseHistoryService.hideUserBrowseHistory(getLoginUserId(), null);
+        return success(Boolean.TRUE);
+    }
+
+    @GetMapping(value = "/page")
+    @Operation(summary = "获得商品浏览记录分页")
+    @PreAuthenticated
+    public CommonResult<PageResult<AppGuideBrowseHistoryRespVO>> getBrowseHistoryPage(AppGuideBrowseHistoryPageReqVO reqVO) {
+        GuideBrowseHistoryPageReqVO pageReqVO = BeanUtils.toBean(reqVO, GuideBrowseHistoryPageReqVO.class)
+                .setUserId(getLoginUserId())
+                .setUserDeleted(false); // 排除用户已删除的(隐藏的)
+        PageResult<GuideBrowseHistoryDO> pageResult = guideBrowseHistoryService.getBrowseHistoryPage(pageReqVO);
+        if (CollUtil.isEmpty(pageResult.getList())) {
+            return success(PageResult.empty());
+        }
+        List<AppGuideBrowseHistoryRespVO> appGuideBrowseHistoryRespVOList= BeanUtils.toBean(pageResult.getList(), AppGuideBrowseHistoryRespVO.class);
+        // 得到商品 spu 信息
+
+        for (AppGuideBrowseHistoryRespVO history:appGuideBrowseHistoryRespVOList) {
+            if (history.getGuideId()!=null) {
+                history.setGuideInfo(BeanUtils.toBean(usersService.getUsers(history.getGuideId()), AppUsersRespVO.class));
+            }
+            if (history.getTripId()!=null) {
+                history.setTripInfo(BeanUtils.toBean(tripService.getAppTrip(history.getTripId()), AppTripRespVO.class));
+            }
+            if (history.getSightsId()!=null) {
+                history.setSightsInfo(BeanUtils.toBean(sightsService.getSights(history.getSightsId()), AppSightsRespVO.class));
+            }
+        }
+        // 转换 VO 结果
+        PageResult<AppGuideBrowseHistoryRespVO> returnResult = new PageResult<>(pageResult.getTotal());
+        returnResult.setList(appGuideBrowseHistoryRespVOList);
+        return success(returnResult);
+
+    }
+
+}

+ 18 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/history/vo/AppGuideBrowseHistoryDeleteReqVO.java

@@ -0,0 +1,18 @@
+package cn.iocoder.yudao.module.guide.controller.app.history.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotEmpty;
+import lombok.Data;
+
+import java.util.List;
+
+import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
+
+@Schema(description = "用户 APP - 删除商品浏览记录的 Request VO")
+@Data
+public class AppGuideBrowseHistoryDeleteReqVO {
+
+    @Schema(description = "history 编号数组", requiredMode = REQUIRED, example = "29502")
+    private List<Long> ids;
+
+}

+ 24 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/history/vo/AppGuideBrowseHistoryPageReqVO.java

@@ -0,0 +1,24 @@
+package cn.iocoder.yudao.module.guide.controller.app.history.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+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 = "用户 APP - 商品浏览记录分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class AppGuideBrowseHistoryPageReqVO extends PageParam {
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

+ 37 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/history/vo/AppGuideBrowseHistoryRespVO.java

@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.module.guide.controller.app.history.vo;
+
+import cn.iocoder.yudao.module.guide.controller.app.sights.vo.AppSightsRespVO;
+import cn.iocoder.yudao.module.guide.controller.app.trip.vo.AppTripRespVO;
+import cn.iocoder.yudao.module.guide.controller.app.users.vo.AppUsersRespVO;
+import cn.iocoder.yudao.module.guide.dal.dataobject.trip.TripDO;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
+
+@Schema(description = "用户 App - 商品浏览记录 Response VO")
+@Data
+public class AppGuideBrowseHistoryRespVO {
+
+    @Schema(description = "编号", requiredMode = REQUIRED, example = "1")
+    private Long id;
+
+    @Schema(description = "trip编号", requiredMode = REQUIRED, example = "29502")
+    private Long tripId;
+
+    @Schema(description = "guide编号", requiredMode = REQUIRED, example = "29502")
+    private Long guideId;
+
+    @Schema(description = "sights编号", requiredMode = REQUIRED, example = "29502")
+    private Long sightsId;
+
+    @Schema(description = "导游")
+    private AppUsersRespVO guideInfo;
+
+    @Schema(description = "行程")
+    private AppTripRespVO tripInfo;
+
+    @Schema(description = "景点")
+    private AppSightsRespVO sightsInfo;
+
+}

+ 94 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/must/AppGuideMustController.java

@@ -0,0 +1,94 @@
+package cn.iocoder.yudao.module.guide.controller.app.must;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
+import cn.iocoder.yudao.module.guide.controller.app.must.vo.AppGuideMustPageReqVO;
+import cn.iocoder.yudao.module.guide.controller.app.must.vo.AppGuideMustReqVO;
+import cn.iocoder.yudao.module.guide.controller.app.must.vo.AppGuideMustRespVO;
+import cn.iocoder.yudao.module.guide.controller.app.sights.vo.AppSightsRespVO;
+import cn.iocoder.yudao.module.guide.dal.dataobject.must.GuideMustDO;
+import cn.iocoder.yudao.module.guide.service.must.GuideMustService;
+import cn.iocoder.yudao.module.guide.service.sights.SightsService;
+import cn.iocoder.yudao.module.guide.service.users.UsersService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
+
+/**
+ * @author libin
+ */
+@Tag(name = "用户 APP - 必须去的景点")
+@RestController
+@RequestMapping("/guide/sights/must")
+public class AppGuideMustController {
+
+    @Resource
+    private GuideMustService guideMustService;
+    @Resource
+    private UsersService usersService; //guide
+
+    @Resource
+    private SightsService sightsService;
+    @PostMapping(value = "/create")
+    @Operation(summary = "添加必须去的景点")
+    @PreAuthenticated
+    public CommonResult<Long> createMust(@RequestBody @Valid AppGuideMustReqVO reqVO) {
+        return success(guideMustService.createMust(getLoginUserId(), reqVO));
+    }
+
+    @DeleteMapping(value = "/delete")
+    @Operation(summary = "取消单个商品收藏")
+    @PreAuthenticated
+    public CommonResult<Boolean> deleteMust(@RequestBody @Valid AppGuideMustReqVO reqVO) {
+        guideMustService.deleteMust(getLoginUserId(), reqVO);
+        return success(Boolean.TRUE);
+    }
+
+    @GetMapping(value = "/page")
+    @Operation(summary = "获得商品收藏分页")
+    @PreAuthenticated
+    public CommonResult<PageResult<AppGuideMustRespVO>> getFavoritePage(AppGuideMustPageReqVO reqVO) {
+        PageResult<GuideMustDO> mustPage = guideMustService.getMustPage(getLoginUserId(), reqVO);
+        if (CollUtil.isEmpty(mustPage.getList())) {
+            return success(PageResult.empty());
+        }
+        List<AppGuideMustRespVO> appMustRespVOList= BeanUtils.toBean(mustPage.getList(), AppGuideMustRespVO.class);
+
+        for (AppGuideMustRespVO must:appMustRespVOList) {
+
+            if (must.getSightsId()!=null) {
+                must.setSightsInfo(BeanUtils.toBean(sightsService.getSights(must.getSightsId()), AppSightsRespVO.class));
+            }
+        }
+        // 转换 VO 结果
+        PageResult<AppGuideMustRespVO> pageResult = new PageResult<>(mustPage.getTotal());
+        pageResult.setList(appMustRespVOList);
+        return success(pageResult);
+    }
+
+    @GetMapping(value = "/exits")
+    @Operation(summary = "检查是否收藏过商品")
+    @PreAuthenticated
+    public CommonResult<Boolean> isMustExists(AppGuideMustReqVO reqVO) {
+        GuideMustDO favorite = guideMustService.getMust(getLoginUserId(), reqVO);
+        return success(favorite != null);
+    }
+
+    @GetMapping(value = "/get-count")
+    @Operation(summary = "获得商品收藏数量")
+    @PreAuthenticated
+    public CommonResult<Long> getFavoriteCount() {
+        return success(guideMustService.getMustCount(getLoginUserId()));
+    }
+
+}

+ 10 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/must/vo/AppGuideMustPageReqVO.java

@@ -0,0 +1,10 @@
+package cn.iocoder.yudao.module.guide.controller.app.must.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "用户 App - 商品收藏分页查询 Request VO")
+@Data
+public class AppGuideMustPageReqVO extends PageParam {
+}

+ 15 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/must/vo/AppGuideMustReqVO.java

@@ -0,0 +1,15 @@
+package cn.iocoder.yudao.module.guide.controller.app.must.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
+
+@Schema(description = "用户 APP - 商品收藏的单个 Request VO") // 用于收藏、取消收藏、获取收藏
+@Data
+public class AppGuideMustReqVO {
+
+    @Schema(description = "Sights 编号", requiredMode = REQUIRED, example = "29502")
+    private Long sightsId;
+
+}

+ 25 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/must/vo/AppGuideMustRespVO.java

@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.module.guide.controller.app.must.vo;
+
+import cn.iocoder.yudao.module.guide.controller.app.sights.vo.AppSightsRespVO;
+import cn.iocoder.yudao.module.guide.controller.app.trip.vo.AppTripRespVO;
+import cn.iocoder.yudao.module.guide.controller.app.users.vo.AppUsersRespVO;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
+
+@Schema(description = "用户 App - 商品收藏 Response VO")
+@Data
+public class AppGuideMustRespVO {
+
+    @Schema(description = "编号", requiredMode = REQUIRED, example = "1")
+    private Long id;
+
+    @Schema(description = "Sights 编号", requiredMode = REQUIRED, example = "29502")
+    private Long sightsId;
+
+    // ========== 商品相关字段 ==========
+    @Schema(description = "景点")
+    private AppSightsRespVO sightsInfo;
+
+}

+ 180 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/order/AppGuideTradeOrderController.java

@@ -0,0 +1,180 @@
+package cn.iocoder.yudao.module.guide.controller.app.order;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils;
+import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
+import cn.iocoder.yudao.module.guide.controller.app.order.vo.*;
+
+import cn.iocoder.yudao.module.guide.controller.app.order.vo.item.AppGuideTradeOrderItemCommentCreateReqVO;
+import cn.iocoder.yudao.module.guide.controller.app.order.vo.item.AppGuideTradeOrderItemRespVO;
+import cn.iocoder.yudao.module.guide.controller.app.schedule.vo.AppScheduleRespVO;
+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.service.aftersale.GuideAfterSaleService;
+import cn.iocoder.yudao.module.guide.service.order.GuideTradeOrderQueryService;
+import cn.iocoder.yudao.module.guide.service.order.GuideTradeOrderUpdateService;
+import cn.iocoder.yudao.module.guide.enums.order.TradeOrderStatusEnum;
+import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO;
+import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPageItemRespVO;
+import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
+import com.google.common.collect.Maps;
+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 lombok.extern.slf4j.Slf4j;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
+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.convertMultiMap;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
+
+@Tag(name = "用户 App - 交易订单")
+@RestController
+@RequestMapping("/guide/trade/order")
+@Validated
+@Slf4j
+public class AppGuideTradeOrderController {
+
+    @Resource
+    private GuideTradeOrderUpdateService tradeOrderUpdateService;
+    @Resource
+    private GuideTradeOrderQueryService tradeOrderQueryService;
+
+    @Resource
+    private GuideAfterSaleService afterSaleService;
+    @PostMapping("/settlement")
+    @Operation(summary = "获得订单结算信息")
+    @PreAuthenticated
+    public CommonResult<AppGuideTradeOrderSettlementRespVO> settlementOrder(@Valid @RequestBody List<OrderSettlementReqVO> settlementReqVOs) {
+        return success(tradeOrderUpdateService.settlementOrder(getLoginUserId(), settlementReqVOs));
+    }
+
+    @PostMapping("/create")
+    @Operation(summary = "创建订单")
+    @PreAuthenticated
+    public CommonResult<AppGuideTradeOrderCreateRespVO> createOrder(@Valid @RequestBody AppGuideTradeOrderCreateReqVO createReqVO) {
+        GuideTradeOrderDO order = tradeOrderUpdateService.createOrder(getLoginUserId(), createReqVO);
+        return success(new AppGuideTradeOrderCreateRespVO().setId(order.getId()).setPayOrderId(order.getPayOrderId()));
+    }
+
+
+    @PostMapping("/update-paid")
+    @Operation(summary = "更新订单为已支付") // 由 pay-module 支付服务,进行回调,可见 PayNotifyJob
+    public CommonResult<Boolean> updateOrderPaid(@RequestBody PayOrderNotifyReqDTO notifyReqDTO) {
+        tradeOrderUpdateService.updateOrderPaid(Long.valueOf(notifyReqDTO.getMerchantOrderId()),
+                notifyReqDTO.getPayOrderId());
+        return success(true);
+    }
+
+    @GetMapping("/get-detail")
+    @Operation(summary = "获得交易订单")
+    @Parameter(name = "id", description = "交易订单编号")
+    public CommonResult<AppGuideTradeOrderDetailRespVO> getOrder(@RequestParam("id") Long id) {
+        // 查询订单
+        GuideTradeOrderDO order = tradeOrderQueryService.getOrder(getLoginUserId(), id);
+        if (order == null) {
+            return success(null);
+        }
+        AppGuideTradeOrderDetailRespVO orderDO = BeanUtils.toBean(order, AppGuideTradeOrderDetailRespVO.class);
+        // 查询订单项
+        List<GuideTradeOrderItemDO> orderItems = tradeOrderQueryService.getOrderItemListByOrderId(order.getId());
+
+        orderDO.setItems(BeanUtils.toBean(orderItems, AppGuideTradeOrderItemRespVO.class));
+        // 最终组合
+        return success(orderDO);
+    }
+
+
+    @GetMapping("/page")
+    @Operation(summary = "获得交易订单分页")
+    public CommonResult<PageResult<AppGuideTradeOrderPageItemRespVO>> getOrderPage(AppGuideTradeOrderPageReqVO reqVO) {
+        // 查询订单
+        PageResult<GuideTradeOrderDO> pageResult = tradeOrderQueryService.getOrderPage(getLoginUserId(), reqVO);
+        // 查询订单项
+        List<GuideTradeOrderItemDO> orderItems = tradeOrderQueryService.getOrderItemListByOrderId(
+                convertSet(pageResult.getList(), GuideTradeOrderDO::getId));
+
+        return success(convertPage03( pageResult, orderItems));
+    }
+
+    PageResult<AppGuideTradeOrderPageItemRespVO> convertPage03
+            (PageResult<GuideTradeOrderDO> pageResult,List<GuideTradeOrderItemDO> orderItems){
+        Map<Long, List<GuideTradeOrderItemDO>> orderItemMap = convertMultiMap(orderItems, GuideTradeOrderItemDO::getOrderId);
+        // 转化 List
+        List<AppGuideTradeOrderPageItemRespVO> orderVOs = CollectionUtils.convertList(pageResult.getList(), order -> {
+            List<AppGuideTradeOrderItemRespVO> xOrderItems = BeanUtils.toBean(orderItemMap.get(order.getId()),AppGuideTradeOrderItemRespVO.class);
+            AppGuideTradeOrderPageItemRespVO orderVO = BeanUtils.toBean(order,AppGuideTradeOrderPageItemRespVO.class);
+            orderVO.setItems(xOrderItems);
+            return orderVO;
+        });
+
+        return new PageResult<>(orderVOs, pageResult.getTotal());
+    }
+    @GetMapping("/get-count")
+    @Operation(summary = "获得交易订单数量")
+    public CommonResult<Map<String, Long>> getOrderCount() {
+        Map<String, Long> orderCount = Maps.newLinkedHashMapWithExpectedSize(5);
+        // 全部
+        orderCount.put("allCount", tradeOrderQueryService.getOrderCount(getLoginUserId(), null, null));
+        // 待付款(未支付)
+        orderCount.put("unpaidCount", tradeOrderQueryService.getOrderCount(getLoginUserId(),
+                TradeOrderStatusEnum.UNPAID.getStatus(), null));
+        // 待发货
+        orderCount.put("undeliveredCount", tradeOrderQueryService.getOrderCount(getLoginUserId(),
+                TradeOrderStatusEnum.UNDELIVERED.getStatus(), null));
+        // 待收货
+        orderCount.put("deliveredCount", tradeOrderQueryService.getOrderCount(getLoginUserId(),
+                TradeOrderStatusEnum.DELIVERED.getStatus(), null));
+        // 待评价
+        orderCount.put("uncommentedCount", tradeOrderQueryService.getOrderCount(getLoginUserId(),
+                TradeOrderStatusEnum.COMPLETED.getStatus(), false));
+        // 售后数量
+        orderCount.put("afterSaleCount", afterSaleService.getApplyingAfterSaleCount(getLoginUserId()));
+        return success(orderCount);
+    }
+
+
+    @DeleteMapping("/cancel")
+    @Operation(summary = "取消交易订单")
+    @Parameter(name = "id", description = "交易订单编号")
+    public CommonResult<Boolean> cancelOrder(@RequestParam("id") Long id) {
+        tradeOrderUpdateService.cancelOrderByMember(getLoginUserId(), id);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除交易订单")
+    @Parameter(name = "id", description = "交易订单编号")
+    public CommonResult<Boolean> deleteOrder(@RequestParam("id") Long id) {
+        tradeOrderUpdateService.deleteOrder(getLoginUserId(), id);
+        return success(true);
+    }
+
+    // ========== 订单项 ==========
+
+    @GetMapping("/item/get")
+    @Operation(summary = "获得交易订单项")
+    @Parameter(name = "id", description = "交易订单项编号")
+    public CommonResult<AppGuideTradeOrderItemRespVO> getOrderItem(@RequestParam("id") Long id) {
+        GuideTradeOrderItemDO item = tradeOrderQueryService.getOrderItem(getLoginUserId(), id);
+        return success(BeanUtils.toBean(item,AppGuideTradeOrderItemRespVO.class));
+    }
+
+    @PostMapping("/item/create-comment")
+    @Operation(summary = "创建交易订单项的评价")
+    public CommonResult<Long> createOrderItemComment(@RequestBody AppGuideTradeOrderItemCommentCreateReqVO createReqVO) {
+        return success(tradeOrderUpdateService.createOrderItemCommentByMember(getLoginUserId(), createReqVO));
+    }
+
+}

+ 23 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/order/vo/AppGuideOrderExpressTrackRespDTO.java

@@ -0,0 +1,23 @@
+package cn.iocoder.yudao.module.guide.controller.app.order.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * 快递查询的轨迹 Resp DTO
+ *
+ * @author jason
+ */
+@Schema(description = "用户 App - 快递查询的轨迹 Response VO")
+@Data
+public class AppGuideOrderExpressTrackRespDTO {
+
+    @Schema(description = "发生时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    private LocalDateTime time;
+
+    @Schema(description = "快递状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "已签收")
+    private String content;
+
+}

+ 22 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/order/vo/AppGuideTradeOrderCreateReqVO.java

@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.guide.controller.app.order.vo;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.AssertTrue;
+import lombok.Data;
+
+import java.util.List;
+
+@Schema(description = "用户 App - 交易订单创建 Request VO")
+@Data
+public class AppGuideTradeOrderCreateReqVO  {
+
+    @Schema(description = "备注", example = "这个是我的订单哟")
+    private String remark;
+
+    @Schema(description = "金额", example = "8800")
+    private Integer price;
+
+    @Schema(description = "商品列表", example = "这个是我的订单哟")
+    private List<OrderSettlementReqVO> orderSettlementReqVOs;
+}

+ 16 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/order/vo/AppGuideTradeOrderCreateRespVO.java

@@ -0,0 +1,16 @@
+package cn.iocoder.yudao.module.guide.controller.app.order.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "用户 App - 交易订单创建 Response VO")
+@Data
+public class AppGuideTradeOrderCreateRespVO {
+
+    @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    private Long id;
+
+    @Schema(description = "支付订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    private Long payOrderId;
+
+}

+ 148 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/order/vo/AppGuideTradeOrderDetailRespVO.java

@@ -0,0 +1,148 @@
+package cn.iocoder.yudao.module.guide.controller.app.order.vo;
+
+import cn.iocoder.yudao.module.guide.controller.app.order.vo.item.AppGuideTradeOrderItemRespVO;
+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 AppGuideTradeOrderDetailRespVO {
+
+    // ========== 订单基本信息 ==========
+
+    @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    private Long id;
+
+    @Schema(description = "订单流水号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1146347329394184195")
+    private String no;
+
+    @Schema(description = "订单类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+    private Integer type;
+
+    @Schema(description = "下单时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    private LocalDateTime createTime;
+
+    @Schema(description = "用户备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "你猜")
+    private String userRemark;
+
+    @Schema(description = "订单状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    private Integer status;
+
+    @Schema(description = "购买的商品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
+    private Integer productCount;
+
+    @Schema(description = "订单完成时间")
+    private LocalDateTime finishTime;
+
+    @Schema(description = "订单取消时间")
+    private LocalDateTime cancelTime;
+
+    @Schema(description = "是否评价", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
+    private Boolean commentStatus;
+
+    // ========== 价格 + 支付基本信息 ==========
+
+    @Schema(description = "是否已支付", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
+    private Boolean payStatus;
+
+    @Schema(description = "支付订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    private Long payOrderId;
+
+    @Schema(description = "付款时间")
+    private LocalDateTime payTime;
+
+    @Schema(description = "付款超时时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    private LocalDateTime payExpireTime;
+
+    @Schema(description = "支付渠道", example = "wx_lite_pay")
+    private String payChannelCode;
+    @Schema(description = "支付渠道名", example = "微信小程序支付")
+    private String payChannelName;
+
+    @Schema(description = "商品原价(总)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000")
+    private Integer totalPrice;
+
+    @Schema(description = "订单优惠(总)", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
+    private Integer discountPrice;
+
+    @Schema(description = "运费金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
+    private Integer deliveryPrice;
+
+    @Schema(description = "订单调价(总)", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
+    private Integer adjustPrice;
+
+    @Schema(description = "应付金额(总)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000")
+    private Integer payPrice;
+
+    // ========== 收件 + 物流基本信息 ==========
+
+    @Schema(description = "配送方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    private Integer deliveryType;
+
+    @Schema(description = "发货物流公司编号", example = "10")
+    private Long logisticsId;
+
+    @Schema(description = "发货物流名称", example = "顺丰快递")
+    private String logisticsName;
+
+    @Schema(description = "发货物流单号", example = "1024")
+    private String logisticsNo;
+
+    @Schema(description = "发货时间")
+    private LocalDateTime deliveryTime;
+
+    @Schema(description = "收货时间")
+    private LocalDateTime receiveTime;
+
+    @Schema(description = "收件人名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三")
+    private String receiverName;
+
+    @Schema(description = "收件人手机", requiredMode = Schema.RequiredMode.REQUIRED, example = "13800138000")
+    private String receiverMobile;
+
+    @Schema(description = "收件人地区编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "110000")
+    private Integer receiverAreaId;
+
+    @Schema(description = "收件人地区名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "上海 上海市 普陀区")
+    private String receiverAreaName;
+
+    @Schema(description = "收件人详细地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "中关村大街 1 号")
+    private String receiverDetailAddress;
+
+    @Schema(description = "自提门店编号", example = "1088")
+    private Long pickUpStoreId;
+
+    @Schema(description = "自提核销码", example = "40964096")
+    private String pickUpVerifyCode;
+
+    // ========== 售后基本信息 ==========
+
+    @Schema(description = "售后状态", example = "0")
+    private Integer refundStatus;
+
+    @Schema(description = "退款金额,单位:分", example = "100")
+    private Integer refundPrice;
+
+    // ========== 营销基本信息 ==========
+
+    @Schema(description = "优惠劵编号", example = "1024")
+    private Long couponId;
+
+    @Schema(description = "优惠劵减免金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
+    private Integer couponPrice;
+
+    @Schema(description = "积分抵扣的金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
+    private Integer pointPrice;
+
+    @Schema(description = "VIP 减免金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "888")
+    private Integer vipPrice;
+
+    /**
+     * 订单项数组
+     */
+    private List<AppGuideTradeOrderItemRespVO> items;
+
+}

+ 56 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/order/vo/AppGuideTradeOrderPageItemRespVO.java

@@ -0,0 +1,56 @@
+package cn.iocoder.yudao.module.guide.controller.app.order.vo;
+
+import cn.iocoder.yudao.module.guide.controller.app.order.vo.item.AppGuideTradeOrderItemRespVO;
+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 AppGuideTradeOrderPageItemRespVO {
+
+    @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    private Long id;
+
+    @Schema(description = "订单流水号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1146347329394184195")
+    private String no;
+
+    @Schema(description = "订单类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+    private Integer type;
+
+    @Schema(description = "订单状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    private Integer status;
+
+    @Schema(description = "应付金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000")
+    private Integer totalPrice;
+
+    @Schema(description = "购买的商品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
+    private Integer productCount;
+
+    @Schema(description = "是否评价", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
+    private Boolean commentStatus;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    private LocalDateTime createTime;
+
+    // ========== 价格 + 支付基本信息 ==========
+
+    @Schema(description = "支付订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    private Long payOrderId;
+
+    @Schema(description = "应付金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000")
+    private Integer payPrice;
+
+    // ========== 收件 + 物流基本信息 ==========
+
+    @Schema(description = "配送方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    private Integer deliveryType;
+
+    /**
+     * 订单项数组
+     */
+    private List<AppGuideTradeOrderItemRespVO> items;
+
+}

+ 20 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/order/vo/AppGuideTradeOrderPageReqVO.java

@@ -0,0 +1,20 @@
+package cn.iocoder.yudao.module.guide.controller.app.order.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.guide.enums.order.TradeOrderStatusEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "交易订单分页 Request VO")
+@Data
+public class AppGuideTradeOrderPageReqVO extends PageParam {
+
+    @Schema(description = "订单状态", example = "1")
+    @InEnum(value = TradeOrderStatusEnum.class, message = "订单状态必须是 {value}")
+    private Integer status;
+
+    @Schema(description = "是否评价", example = "true")
+    private Boolean commentStatus;
+
+}

+ 46 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/order/vo/AppGuideTradeOrderSettlementRespVO.java

@@ -0,0 +1,46 @@
+package cn.iocoder.yudao.module.guide.controller.app.order.vo;
+
+import cn.iocoder.yudao.module.guide.controller.app.base.property.AppProductPropertyValueDetailRespVO;
+import cn.iocoder.yudao.module.guide.dal.dataobject.trip.TripDO;
+import cn.iocoder.yudao.module.guide.dal.dataobject.users.UsersDO;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Schema(description = "用户 App - 交易订单结算信息 Response VO")
+@Data
+public class AppGuideTradeOrderSettlementRespVO {
+
+    @Schema(description = "交易类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") // 对应 TradeOrderTypeEnum 枚举
+    private Integer type;
+
+    @Schema(description = "购物项数组", requiredMode = Schema.RequiredMode.REQUIRED)
+    private List<Item> items;
+
+    @Schema(description = "费用", requiredMode = Schema.RequiredMode.REQUIRED)
+    private Integer price;
+
+    @Schema(description = "remark")
+    private String remark;
+    @Schema(description = "购物项")
+    @Data
+    public static class Item {
+
+        @Schema(description = "行程")
+        private TripDO tripInfo;
+        @Schema(description = "导游")
+        private UsersDO guideInfo;
+        @Schema(description = "预约日期")
+        private LocalDateTime bookingDate;
+        @Schema(description = "服务价格")
+        private Integer price;
+        @Schema(description = "购物车编号")
+        private Long cartId;
+
+    }
+}

+ 47 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/order/vo/OrderSettlementReqVO.java

@@ -0,0 +1,47 @@
+package cn.iocoder.yudao.module.guide.controller.app.order.vo;
+
+import cn.hutool.core.util.ObjUtil;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.framework.common.validation.Mobile;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.AssertTrue;
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Schema(description = "用户 App - 交易订单结算 Request VO")
+@Data
+@Valid
+public class OrderSettlementReqVO {
+
+        @Schema(description = " 导游编号", example = "2048")
+        @NotNull(message = "导游编号不能为空")
+        private Long guideId;
+
+        @Schema(description = "行程编号", example = "1024")
+        private Long tripId;
+
+        @Schema(description = "购物车项的编号", example = "1024")
+        private Long cartId;
+
+        @Schema(description = "预约日期", example = "2024-01-01")
+        private LocalDateTime bookingDate;
+
+        @Schema(description = "行程名", example = "美丽东京一日游")
+        private String tripTitle;
+
+        @Schema(description = "导游名", example = "导游AA")
+        private String guideName;
+
+        @Schema(description = "图片", example = "https://pp.jpg")
+        private String picUrl;
+
+        @Schema(description = "金额", example = "8888")
+        private Integer price;
+}

+ 38 - 0
yudao-module-guide/yudao-module-guide-biz/src/main/java/cn/iocoder/yudao/module/guide/controller/app/order/vo/item/AppGuideTradeOrderItemCommentCreateReqVO.java

@@ -0,0 +1,38 @@
+package cn.iocoder.yudao.module.guide.controller.app.order.vo.item;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+
+import java.util.List;
+
+@Schema(description = "用户 App - 商品评价创建 Request VO")
+@Data
+public class AppGuideTradeOrderItemCommentCreateReqVO {
+
+    @Schema(description = "是否匿名", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
+    @NotNull(message = "是否匿名不能为空")
+    private Boolean anonymous;
+
+    @Schema(description = "交易订单项编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2312312")
+    @NotNull(message = "交易订单项编号不能为空")
+    private Long orderItemId;
+
+    @Schema(description = "描述星级 1-5 分", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
+    @NotNull(message = "描述星级 1-5 分不能为空")
+    private Integer descriptionScores;
+
+    @Schema(description = "服务星级 1-5 分", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
+    @NotNull(message = "服务星级 1-5 分不能为空")
+    private Integer benefitScores;
+
+    @Schema(description = "评论内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "穿身上很漂亮诶(*^▽^*)")
+    @NotNull(message = "评论内容不能为空")
+    private String content;
+
+    @Schema(description = "评论图片地址数组,以逗号分隔最多上传 9 张", requiredMode = Schema.RequiredMode.REQUIRED, example = "[https://www.iocoder.cn/xx.png]")
+    @Size(max = 9, message = "评论图片地址数组长度不能超过 9 张")
+    private List<String> picUrls;
+
+}

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio